八、Android中 IPC 机制(5)之 Binder --- Android 应用层分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz_cfm/article/details/90300279

    什么是 Binder?通过上一篇文章的分析,我们知道了 Binder 就是 Android 系统自己提供的一种跨进程通信的方式,该通信方式在 Linux 中没有。那我们该如何使用它完成跨进程通信呢?这个时候,就从 Android 应用层来出发,Android 系统提供了一个 Binder 类,而这个类对象就是 Server 端和 Client 端进行通信的媒介,当 bindService 的时候,Server 端就会返回一个包含了 Server 端业务调用的 Binder(IBinder 类型) 对象,而客户端就可以通过这个 Binder 对象的引用来获取 Server 端提供的服务或数据,从而完成跨进程通信。

    在 Android 开发中,Binder 主要用在 Service 中,包括 AIDL 和 Messenger,其中普通 Service 中的 Binder 不涉及进程间通信,所以使用起来很简单,由于它无法触及到 Binder 的核心,而 Messenger 的底层其实是 AIDL 来实现的,所以我们这里结合 AIDL(Android Interface Definition Lauguage --- Android 接口定义语言,是 Android 中通过 Binder 机制的 IPC 实现方式之一)以及 Binder 的源码来一起探究 Android 系统是怎么使用 Binder 机制来完成跨进程通信的。

先来简单的看一下 AIDL 的应用:

服务端代码:

1. 创建一个 aidl 文件(里面声明服务端实现的方法,两个方法分别完成两个整型数的加法和减法),创建完成之后,Bulid 工程,打开 build 目录下的 generated 文件夹下面会自动生成一个 ICalculator.java 文件,这个就是通过 Binder 机制完成跨进程通信的关键代码,后面会好好分析。

// ICalculator.aidl
package com.cfm.serverwithaidltest;

interface ICalculator {
    // 两个整型数相加
    int add(int a, int b);
    // 两个整型数相减
    int subtract(int a, int b);
}

2. 创建一个 Service,然后客户端和服务端就可以通过 Service 中的 IBinder 类型的类进行跨进程通信。

package com.cfm.serverwithaidltest;

public class MyService extends Service {

    public IBinder mBinder = new ICalculator.Stub() {
        @Override
        public int add(int a, int b) throws RemoteException {
            return (a + b);
        }

        @Override
        public int subtract(int a, int b) throws RemoteException {
            return (a - b);
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        Log.d("cfmtest", "MyService 服务绑定成功!" + "当前进程名: " + getProcessName(MyService.this));
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("cfmtest", "MyService 服务创建成功!" + "当前进程名: " + getProcessName(MyService.this));
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("cfmtest", "MyService 服务开始!" + "当前进程名: " + getProcessName(MyService.this));
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("cfmtest", "MyService 服务解绑成功!" + "当前进程名: " + getProcessName(MyService.this));
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Log.d("cfmtest", "MyService 服务销毁!" + "当前进程名: " + getProcessName(MyService.this));
        super.onDestroy();
    }

    // 获取进程名方法
    public String getProcessName(Context context) {
        int pid = android.os.Process.myPid();
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();

        if (runningApps == null) {
            return null;
        }

        for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {
            if (procInfo.pid == pid) {
                return procInfo.processName;
            }
        }
        return null;
    }
}

AndroidManifest.xml 中 Service 的定义:

<service android:name=".MyService">
    <intent-filter>
        <action android:name="com.cfm.serverwithaidltest.MYSERVICE"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</service>

3. 创建服务端 Activity。

package com.cfm.serverwithaidltest;

public class ServerActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

下面再看一下客户端实现代码:

1. 首先将服务端下定义的 aidl 类型文件复制到客户端代码中,注意一定要确保文件和包名与服务端保持完全一致,然后再 Build 工程后即可使用 AIDL 完成跨进程通信。

2. 使用 AIDL:

// ClientActivity.java
public class ClientActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ServiceConnection conn = new ServiceConnection() {

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                ICalculator calc = ICalculator.Stub.asInterface(service);

                try {
                    int addResult = calc.add(322, 344);
                    int subtractResult = calc.subtract(1000, 112);
                    Log.d("cfmtest", "计算的加法结果: " + addResult + "当前进程名: " + getProcessName(ClientActivity.this));
                    Log.d("cfmtest", "计算的减法结果: " + subtractResult + "当前进程名: " + getProcessName(ClientActivity.this));

                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };

        Button startServiceBtn = findViewById(R.id.start_btn);
        Button bindServiceBtn = findViewById(R.id.bind_btn);
        Button unBindServiceBtn = findViewById(R.id.unbind_btn);
        Button stopServiceBtn = findViewById(R.id.stop_btn);

        startServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.cfm.serverwithaidltest.MYSERVICE");
                intent.setPackage("com.cfm.serverwithaidltest");
                startService(intent);
            }
        });

        bindServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.cfm.serverwithaidltest.MYSERVICE");
                intent.setPackage("com.cfm.serverwithaidltest");
                bindService(intent, conn, Context.BIND_AUTO_CREATE);
            }
        });

        unBindServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(conn);
            }
        });

        stopServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.cfm.serverwithaidltest.MYSERVICE");
                intent.setPackage("com.cfm.serverwithaidltest");
                stopService(intent);
            }
        });
    }

    // 获取进程名方法
    public static String getProcessName(Context context) {
        int pid = android.os.Process.myPid();
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();

        if (runningApps == null) {
            return null;
        }

        for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {
            if (procInfo.pid == pid) {
                return procInfo.processName;
            }
        }
        return null;
    }
}

    最后  Log 中打印信息:

cfmtest: MyService 服务创建成功!当前进程名: com.cfm.serverwithaidltest
cfmtest: MyService 服务开始!当前进程名: com.cfm.serverwithaidltest
cfmtest: MyService 服务绑定成功!当前进程名: com.cfm.serverwithaidltest
cfmtest: 计算的加法结果: 666当前进程名: com.cfm.clientwithaidltest
cfmtest: 计算的减法结果: 888当前进程名: com.cfm.clientwithaidltest
cfmtest: MyService 服务解绑成功!当前进程名: com.cfm.serverwithaidltest
cfmtest: MyService 服务销毁!当前进程名: com.cfm.serverwithaidltest

    AIDL 其实就是 Android 系统提供的通过 Binder 机制实现跨进程通信的一种封装实现,使得我们使用起来非常简单,从上面结果可以看到,客户端向服务端请求计算两个数的结果,然后服务端接收到请求后在服务端进行计算并最后将结果再返回给客户端,从而实现了 C/S 模型( Client-Server )的跨进程通信。

    而 AIDL 底层的实现关键就是 Binder 类,下面我们先看一下 Binder 类的源码:

public class Binder implements IBinder {
   ...
}

    Binder 实现了 IBinder 接口,下面再看一下 IBinder 源码:

/**
* 远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分,可以被用于远程调用和进程内调用。这个接口描述了一个用于和远程对象交互的抽象协议。不要直接实现这个接口,而是继承Binder对象。
*/
public interface IBinder {
    ...
}

    通过源码我们可以看到它实现了 IBinder 接口。而 IBinder 接口是 Android 系统提供的一种能远程操作的对象的基本接口,也就是继承或者实现了该接口的对象就具备了跨进程传输的能力,所以 Binder 类对象就具备了跨进程传输的能力。

    在 Binder.java 源码中有这两个方法:

// 这个方法的作用就是通过键值对的方式,以字符串 descriptor 为 Key,IInterface 接口为 Value 存到 Binder 对象中的一个 Map<String, IInterface> 对象中
public void attachInterface(IInterface owner, String descriptor) {
        ...
    }

// 这个方法的作用就是通过 String 类型的 descriptor 在 Map<String, IInterface> 对象中查询该 Binder 对象所对应的 IInterface 接口对象。
public IInterface queryLocalInterface(String descriptor) {
        ...
    }

    再看一下 IInterface 接口长什么样子?

package android.os;

/**
* Binder接口的基类。当定义一个新的接口,你必须从IInterface中继承。
*/
public interface IInterface
{
    /**
     * 取得与这个接口有联系的Binder对象。
     * 你必须使用它而不是普通的类型转换,这样代理对象才可以返回正确的结果.
     */
    public IBinder asBinder();
}

    可以看到,它里面就只有一个 asBinder 方法,该方法的作用就是返回当前接口关联的 Binder 对象(因为 Binder 类实现了 IBinder 接口,故返回类型是 IBinder 类型)。这个接口是 Android 系统在进程间通信中定义的通用接口,所有可以在 Binder 中传输的接口都需要继承自该接口。所以当我们使用 Binder 机制自定义一个 Binder 类时,就必须先继承 Android 系统提供的 Binder 类,然后再实现 IInterface 接口类型的接口。下面我们具体分析一下上面使用 AIDL 产生的 java 文件(实际上,就相当于 AIDL 帮助我们自动生成一个可以在进程间通信的 Binder 类):

package com.cfm.serverwithaidltest;

/**
* 这个是 AIDL 自动为我们生成的继承了 IInterface 接口的 ICalculator 接口,这样该接口就可以在 Binder 中传输了。
* 注:所有可以在 Binder 中传输的接口都必须继承 IInterface 接口,所有为了实现跨进程通信而自定义的 Binder 类都必须实现该接口。
*/
public interface ICalculator extends android.os.IInterface
{
    /**
     * 这个 Stub 类就是继承了 Binder 类并实现了 IInterface 接口的抽象 Binder 类,所以该类就是实现 Binder 机制的跨进程通信的关键。
     * 该类的作用就是: 当客户端和服务端都位于同一个进程时,方法调用不会走跨进程的 transact 过程,直接使用 Stub 类中的 onTransact() 完成方法调用;
     * 而当两者位于不同进程时,方法调用需要走 transact 过程,这个逻辑由 Stub 类的内部代理类 Proxy 来完成。
     */
    public static abstract class Stub extends android.os.Binder implements com.cfm.serverwithaidltest.ICalculator
    {
        /**
         * 该 Binder 类的唯一标识,一般用当前 Binder 的类名表示
         */
        private static final java.lang.String DESCRIPTOR = "com.cfm.serverwithaidltest.ICalculator";

        /**
         *  该 Binder 类实现了 IInterface 接口,所以也是 IInterface 类型,通过 attachInterface() 将该 IInterface 类型对象与
         *  DESCRIPTOR 描述符以类似 <key, value> 形式存储,后面就可以通过 queryLocalInterface(DESCRIPTOR) 查找到该 IInterface 类型对象。
         */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * 用于将服务端的 Binder 对象转换成客户端所需的 AIDL 类型的对象。这样客户端就可以调用服务端 Binder 类中实现的方法了。
         * 注:这种转换过程是区分进程的,如果客户端和服务端位于同一进程中,那么此方法返回的就是服务端的 Stub 对象本身;否则返回的是系统封装后的
         * Stub.proxy 对象。
         */
        public static com.cfm.serverwithaidltest.ICalculator asInterface(android.os.IBinder obj)
        {
            // 这个 IBinder 类型的对象 obj,有可能来自服务端进程,也有可能来自客户端进程。如果来自服务端,那就不需要
            // 进行跨进程通信了,只需要返回 Stub 对象,最后调用 Stub 对象本身中的 onTransact 方法即可;否则就需返回 Stub.Proxy 对象,
            // 最后调用 Stub.Proxy 对象中的 transact 方法。
            if ((obj==null)) {
                return null;
            }

            // 判断 obj 对象是否是和服务端的 Binder 对象是同一个,如果是,就是同进程通信;否则就是跨进程通信。
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

            if (((iin!=null)&&(iin instanceof com.cfm.serverwithaidltest.ICalculator))) {
                // 返回当前 Stub 对象本身
                return ((com.cfm.serverwithaidltest.ICalculator)iin);
            }

            // 返回 Stub 对象的内部代理对象 Stub.Proxy
            return new com.cfm.serverwithaidltest.ICalculator.Stub.Proxy(obj);
        }

        /**
         * 实现 IInterface 接口中的方法,返回该接口所关联的 Binder 类,也就是 Stub 类本身
         */
        @Override
        public android.os.IBinder asBinder()
        {
            return this;
        }

        /**
         * 这个方法运行在服务端的 Binder 线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。
         *
         * @param code  服务端通过 code 可以确定客户端所请求目标方法是什么
         * @param data  从该参数可以取出目标方法所需要的参数(如果目标方法有参数的话)
         * @param reply 当目标方法执行完毕后,就向该参数写入返回值(如果目标方法由返回值的话)
         * @param flags 参数flags只有 0 和 FLAG_ONEWAY 两种。默认的跨进程操作是同步的,所以transact()方法的执行会阻塞,调用以同步的形式传递到远程的transact(),
         *              等待远端的transact()返回后继续执行——最好理解的方式就是把两端的transact()看作一个方法,
         *              Binder机制的目标也就是这样。指定FLAG_ONEWAY时,表示Client的transact()是单向调用,
         *              执行后立即返回,无需等待Server端transact()返回。
         * @return 如果此方法返回 false,那么客户端的请求会失败。因此我们可以通过这个特性来做权限验证,准许客户端请求就返回 true,否则就返回 false。
         */
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
        {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code)
            {
                case INTERFACE_TRANSACTION:
                {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_add:
                {
                    data.enforceInterface(descriptor);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = this.add(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                case TRANSACTION_subtract:
                {
                    data.enforceInterface(descriptor);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    int _result = this.subtract(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        /**
         * 当客户端和服务端不位于同一个进程时,客户端就会通过这个 Proxy 代理类,然后通过 transact 方法完成所需方法调用。
         */
        private static class Proxy implements com.cfm.serverwithaidltest.ICalculator
        {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote)
            {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder()
            {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor()
            {
                return DESCRIPTOR;
            }

            /**
             * 该方法运行在客户端
             */
            @Override
            public int add(int a, int b) throws android.os.RemoteException
            {
                // 创建输入型 Parcel 对象 _data
                android.os.Parcel _data = android.os.Parcel.obtain();
                // 创建输出型 Parcel 对象 _reply
                android.os.Parcel _reply = android.os.Parcel.obtain();
                // 创建返回值 _result
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(a);
                    _data.writeInt(b);

                    //调用 transact 方法发起 RPC(远程过程调用)请求,同时当前线程挂起,然后服务端的 onTransact 方法会被调用,
                    // 直到 RPC 过程返回后,当前线程继续执行,并从 _reply 中取出 RPC 过程的返回结果
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                }
                finally {
                    // 释放资源
                    _reply.recycle();
                    _data.recycle();
                }

                // 返回结果
                return _result;
            }

            /**
             * 同上,只是该方法声明中没有返回值,所以最后没有结果返回。
             */
            @Override
            public int subtract(int a, int b) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(a);
                    _data.writeInt(b);
                    mRemote.transact(Stub.TRANSACTION_subtract, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        // 声明两个整型的 id 分别用于标识我们声明的那两个方法。作用是用于标识在 transact 过程中客户端所请求的到底是哪个方法
        static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_subtract = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    // 声明方法。这两个是我们在服务端要实现的方法。
    public int add(int a, int b) throws android.os.RemoteException;
    public int subtract(int a, int b) throws android.os.RemoteException;
}

    上面就是 AIDL 完成进程间通信代码实现以及相应的源码分析,下面我们还需要额外注意两点:

    1. 当客户端发起远程请求时,当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么不能在 UI 线程中发起此远程请求。

    2. 服务端的 Binder 方法运行在 Binder 线程池中,所以 Binder 方法不管是否耗时都应该采用同步的方式去实现,因为它已经运行在一个线程中了。

刚哥提供的 Binder 工作机制图如下:

    综上我们可以看出,AIDL 文件并不是实现 Binder 的必需品,如果你不想使用 AIDL 完成 Binder 机制的跨进程通信,完全可以参考上面 AIDL 自动生成的那个 Binder 类自己自定义一个 Binder 类即可。

    接下来,看一下 Binder 中两个很重要的方法: linkToDeath() 和 unlinkToDeath() 方法。我们知道,Binder 运行在服务端进程,如果服务端进程由于某种原因异常终止,这个时候我们到服务端的 Binder 连接断裂(称之为 Binder 死亡),会导致我们的远程调用失败。更为关键的是,如果客户端不知道 Binder 连接已经断裂,那么它的功能肯定会受到影响,这就是上面这两个方法出现的原因。下面看一下它们的原型:

// 这两个方法都是在 IBinder 接口中声明,然后在 Binder 类中实现的
public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException;

public boolean unlinkToDeath(DeathRecipient recipient, int flags);
public interface DeathRecipient {
    public void binderDied();
}

    在客户端请求服务端服务时,我们可以通过 linkToDeath() 给 Binder 设置一个死亡代理,当 Binder 死亡时,我们就会收到通知,这个时候我们就可以重新发起连接请求从而恢复连接。下面我们看一下怎么使用(还是上面那个 AIDL 的例子,只是把客户端的代码改一下):

// ClientActivity.java
package com.cfm.clientwithaidltest;

public class ClientActivity extends AppCompatActivity {
    private ICalculator calc;

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            calc = ICalculator.Stub.asInterface(service);
            try {
                /* 2. 远程服务绑定成功后,为 Binder 设置死亡代理 */
                service.linkToDeath(mDeathRecipient, 0);

                // 向服务端请求服务
                int addResult = calc.add(322, 344);
                int subtractResult = calc.subtract(1000, 112);

                Log.d("cfmtest", "计算的加法结果: " + addResult + "当前进程名: " + getProcessName(ClientActivity.this));
                Log.d("cfmtest", "计算的减法结果: " + subtractResult + "当前进程名: " + getProcessName(ClientActivity.this));
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    /*
     * 1. 声明一个 DeathRecipient 对象。从上面可以看到 DeathRecipient 是一个接口,
     * 其内部只有一个 binderDied 方法,当服务端 Binder 死亡时,系统会回调 binderDied 方法,
     * 然后我们就可以通过 unlinkToDeath 方法移除之前绑定的 binder 代理并重新绑定远程服务。
     * */
    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if(calc == null) return;
            calc.asBinder().unlinkToDeath(mDeathRecipient, 0);
            calc = null;

            // 重新绑定远程 Service
            Intent intent = new Intent();
            intent.setAction("com.cfm.serverwithaidltest.MYSERVICE");
            intent.setPackage("com.cfm.serverwithaidltest");
            bindService(intent, conn, Context.BIND_AUTO_CREATE);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button startServiceBtn = findViewById(R.id.start_btn);
        Button bindServiceBtn = findViewById(R.id.bind_btn);
        Button unBindServiceBtn = findViewById(R.id.unbind_btn);
        Button stopServiceBtn = findViewById(R.id.stop_btn);

        startServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.cfm.serverwithaidltest.MYSERVICE");
                intent.setPackage("com.cfm.serverwithaidltest");
                startService(intent);
            }
        });

        bindServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.cfm.serverwithaidltest.MYSERVICE");
                intent.setPackage("com.cfm.serverwithaidltest");
                bindService(intent, conn, Context.BIND_AUTO_CREATE);
            }
        });

        unBindServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(conn);
            }
        });

        stopServiceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.cfm.serverwithaidltest.MYSERVICE");
                intent.setPackage("com.cfm.serverwithaidltest");
                stopService(intent);
            }
        });
    }

    // 获取进程名方法
    public static String getProcessName(Context context) {
        int pid = android.os.Process.myPid();
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();

        if (runningApps == null) {
            return null;
        }

        for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {
            if (procInfo.pid == pid) {
                return procInfo.processName;
            }
        }
        return null;
    }
}

    通过上面的代码实现,就能给我们的 Binder 设置死亡代理,当 Binder 死亡的时候我们就可以收到通知了,然后我们重新发起绑定服务请求。另外,通过 Binder 的 isBinderAlive 方法也可以判断 Binder 是否死亡。

猜你喜欢

转载自blog.csdn.net/yz_cfm/article/details/90300279