欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IPC机制系列之四 Android Binder连接池

程序员文章站 2024-03-23 23:33:28
...

  针对客户端多个业务模块要对应自己的AIDL接口,然后通过同一个Service去管理这些AIDL这种模式,设计一个工作机制:每个业务模块创建自己的AIDL接口并实现此接口,这个时候不同的业务模块之间是不能有耦合的,所有实现细节我们要单独开来,然后向服务端提供自己唯一标识和其对应的Binder对象。首先来一张原理图帮助理解一下。

IPC机制系列之四 Android Binder连接池

  服务端的设计

  对于服务端来说,只需要一个Service就行,服务端提供一个queryBinder接口,这个接口能够根据业务模块的特征来返回相应的Binder的对象,不同的业务模块所拿到的他们所需要的Binder对象就可以进行远程方法调用了由此可见,Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免了重复创建Service的过程。

远程Service的实现:

public class BinderPoolService extends Service {
    private static final String TAG="BinderPoolService";
    private Binder mBinderPool=new BinderPool.BinderPoolImpl();
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG,"onBinder()");
        return mBinderPool;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

在清单文件中注册,让其单独运行在另一个进程中:

<service
        android:name=".service.BinderPoolService"
        android:process=":binder_pool"/>
  Binder连接池的具体实现

在它的内部首先要绑定远程服务,绑定成功后,客户端就可以通过他的queryBinder方法去获取相应的Binder的对象,拿到所需要的Binder以后,不同的业务模块就可以工作了。


/**
 * 作者:byd666 on 2017/10/21 10:01
 * 邮箱:aaa@qq.com
 * Binder的连接池
 */

public class BinderPool {
    private static String TAG = "BinderPool";
    public static final int BINDER_SECURITY_CENTER = 1;
    public static final int BINDER_NONE = -1;
    public static final int BINDER_COMPUTE = 0;
    private IBinderPool mBinderPool;
    private CountDownLatch mConnectBinderPoolCountDownLatch;
    private Context mContext;
    private static volatile BinderPool sInstance;

    public BinderPool(Context context) {
        this.mContext = context.getApplicationContext();
        connectBinderPoolService();
    }

    //设计一个懒汉式单例模式,用来返回BinderPool的对象
    public static BinderPool getInstance(Context context) {
        if (sInstance == null) {
            synchronized (BinderPool.class) {
                if (sInstance == null) {
                    sInstance = new BinderPool(context);
                }
            }
        }
        return sInstance;
    }

    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //连接远程服务端
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mConnectBinderPoolCountDownLatch.countDown();
        }

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

    /**
     * 通过binderCode从线程池中查询相应的binder对象
     * @param binderCode binder对象唯一的标识
     * @return binder 根据binderCode找到相应的Binder对象,没有找到返回null
     */
    public IBinder queryBinder(int binderCode) {
        IBinder binder = null;
        try{
            if (mBinderPool != null) {
                binder = mBinderPool.queryBinder(binderCode);
            }
        }catch (RemoteException e) {
            e.printStackTrace();
        }
        return binder;
    }

    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
        //销毁Binder对象
        @Override
        public void binderDied() {
            Log.w(TAG, "binder died");
            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);
            mBinderPool = null;
            connectBinderPoolService();
        }
    };

    //连接远程服务端Service
    private synchronized void connectBinderPoolService() {
        mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
        Intent intent = new Intent(mContext, BinderPoolService.class);
        mContext.bindService(intent, mBinderPoolConnection, Context.BIND_AUTO_CREATE);
        try {
            mConnectBinderPoolCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static class BinderPoolImpl extends IBinderPool.Stub {
        //请求转发的实现方法,当Binder连接池连接上远程服务时,
        //会根据不同的模块的标识即binderCode返回不同的Binder对象
        //通过这个Binder对象所执行的操作全部发生在远程服务端
        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder = null;
            switch (binderCode) {
                case BINDER_SECURITY_CENTER:
                    binder = new SecurityCenterImpl();
                    break;
                case BINDER_COMPUTE:
                    binder = new ComputeImpl();
                    break;
                default:
                    break;
            }
            return binder;
        }
    }

}
  客户端的设计

然后,很简单,我们在重新建一个Activity,开启一个子线程去验证一下:

public class BinderPoolActivity extends AppCompatActivity {
    ISecurityCenter mSecurityCenter;
    ICompute mCompute;
    private static final String TAG="BinderPoolActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //开启一个子线程,去验证binderPool的连接
        new Thread(new Runnable() {
            @Override
            public void run() {
                BinderPool binderPool=BinderPool.getInstance(BinderPoolActivity.this);
                IBinder securityBinder=binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
                mSecurityCenter= SecurityCenterImpl.asInterface(securityBinder);
                Log.d(TAG,"visit ISecurityCenter");
                String msg="hello word,this is android";
                System.out.println("content:"+msg);
                try {
                    String password=mSecurityCenter.encrypt(msg);
                    System.out.println("encrypt:"+password);
                    System.out.println("decrypt:"+mSecurityCenter.decrypt(password));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
             /** ___________________________________无敌分割线___________________________________________*/
                Log.d(TAG,"visit ICompute");
                IBinder computeBinder=binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
                mCompute= ComputeImpl.asInterface(computeBinder);
                try {
                    System.out.println("8+9="+mCompute.add(8,9));
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

Log日志,从日志中我们可以看出,工作一切正常:

10-21 02:16:47.841 2406-2427/byd.com.byd.binderpooldemo D/BinderPoolActivity: visit ISecurityCenter
10-21 02:16:47.841 2406-2427/byd.com.byd.binderpooldemo I/System.out: content:hello word,this is android
10-21 02:16:47.841 2406-2427/byd.com.byd.binderpooldemo I/System.out: encrypt:6;221~)1,:r*67-~7-~?0:,17:
10-21 02:16:47.841 2406-2427/byd.com.byd.binderpooldemo I/System.out: decrypt:hello word,this is android
10-21 02:16:47.842 2406-2427/byd.com.byd.binderpooldemo D/BinderPoolActivity: visit ICompute
10-21 02:16:47.845 2406-2427/byd.com.byd.binderpooldemo I/System.out: 8+9=17
结论分析:

  Binder连接池的好处是显而易见的,有了他之后,开发中比如有一个新的业务模块需要加入新的AIDL,那么在他实现了自己的AIDL接口后,只需要修改BinderPoolImpl中的queryBinder方法,给自己添加一个binderCode并返回相应的Binder对象,不需要再做其他的修改,也不需要创建新的Service,提高了AIDL的开发效率。


附一下项目地址大家可以clone下来,自己深入理解一下

相关标签: android ipc