Binder连接池

Posted Young_xiaoT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Binder连接池相关的知识,希望对你有一定的参考价值。

Binder连接池

首先回顾一下 AIDL 的 大致流程:首先创建一个Service和一个AIDL接口,接着创建一个类继承自AIDL接口中的Stub类并实现Stub中的抽象方法,在Service的onBind方法中返回这个类的对象,然后客户端就可以绑定Service,建立连接就可以访问远程服务端的方法了。

如果有100个地方需要用到 AIDL ,需要创建100个 Service 吗?

答案是显而易见的,这时我们需要将AIDL放在同一个Service中去管理。

在这种模式下,整个工作机制是这样的:每个业务模块创建自己的 AIDL 接口并实现此接口,这个时候不同业务模块之间是不能有耦合的,所有的实现细节需要单独开来,然后向服务端提供一个唯一标识和其对应的 Binder 对象; 对于服务端来说,只需要一个 Service 就可以了,服务端提供一个 queryBinder 接口,这个接口会返回相应的 Binder对象。Binder 连接池的主要作用就是将每个业务模块的 Binder 请求统一转发到远程 Service 中去执行,从而避免了重复创建Service工程。

下面看一个简单的例子

1.提供两个 AIDL 接口 :ISecurityCenter 和 ICompute

// ISecurityCenter.aidl

interface ISecurityCenter 
    String encrypt(String content);
    String decrypt(String password);

// ICompute.aidl

interface ICompute 

    int add(int a,int b);

2.实现这两个接口

public class SecurityCenterIml extends ISecurityCenter.Stub 

    private static final char SECRET_CODE = '^';

    @Override
    public String encrypt(String content) throws RemoteException 

        char[] chars = content.toCharArray();
        for (int i = 0; i < chars.length; i++) 
            chars[i] ^= SECRET_CODE;
        
        return new String(chars);
    

    @Override
    public String decrypt(String password) throws RemoteException 
        return encrypt(password);
    

public class ComputeIml extends ICompute.Stub
    @Override
    public int add(int a, int b) throws RemoteException 
        return a + b;
    

3.为 Binder 连接池创建AIDL接口 IBinderPool.aidl

// IBinderPoll.aidl

interface IBinderPool 
   IBinder queryBinder(int binderCode);

4.为Binder连接池创建远程Service并实现IBinderPool

@Override
        public IBinder queryBinder(int binderCode) throws RemoteException 

            IBinder binder = null;
            switch (binderCode) 
                case BINDER_SECURITY_CENTER:
                    binder = new SecurityCenterIml();
                    break;
                case BINDER_COMPUTE:
                    binder = new ComputeIml();
                    break;
                default:
                    break;
            

            return binder;
        
    

当Binder连接池连接上远程服务时,会根据不同模块的标识即binderCode返回不同的Binder对象,通过这个Binder对象所执行的操作全部发生在远程服务端。

5.Service 的实现比较简单

public class BinderPoolService extends Service 

    private static final String TAG = "BinderPoolService";

    private Binder mBinderPool = new BinderPool.BinderPoolImpl();

    @Override
    public void onCreate() 
        super.onCreate();
    

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

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

6.Binder连接池内部需要去绑定远程服务,绑定成功后服务端就可以通过它的queryBinder方法去获取对应的Binder。

public class BinderPool 

    public static final int BINDER_SECURITY_CENTER = 1;
    public static final int BINDER_NONE = -1;
    public static final int BINDER_COMPUTE = 0;

    private Context mContext;


    private IBinderPool mBinderPool;
    private static volatile BinderPool sInstance;
    private CountDownLatch mConnectBinderPoolCountDownLatch;
    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() 
        @Override
        public void binderDied() 
            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
            mBinderPool = null;
            connectBinderPoolService();
        
    ;
    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) 
        
    ;

    private BinderPool(Context context) 
        mContext = context.getApplicationContext();
        connectBinderPoolService();

    

    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 IBinder queryBinder(int bindService)
        IBinder binder = null;

        if (mBinderPool != null)
            try 
                binder = mBinderPool.queryBinder(bindService);
             catch (RemoteException e) 
                e.printStackTrace();
            
        

        return binder;
    

    public static BinderPool getsInstance(Context context) 
        if (sInstance == null) 
            synchronized (BinderPool.class) 
                if (sInstance == null) 
                    sInstance = new BinderPool(context);
                
            
        
        return sInstance;
    



    public static class BinderPoolIml extends IBinderPool.Stub 


        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException 

            IBinder binder = null;
            switch (binderCode) 
                case BINDER_SECURITY_CENTER:
                    binder = new SecurityCenterIml();
                    break;
                case BINDER_COMPUTE:
                    binder = new ComputeIml();
                    break;
                default:
                    break;
            

            return binder;
        
    

7.客户端代码

public class BinderPoolActivity extends AppCompatActivity 

    private ISecurityCenter mSecurityCenter;
    private ICompute mCompute;

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

        new Thread(new Runnable() 
            @Override
            public void run() 
                doWork();
            
        ).start();
    

    private void doWork() 
        BinderPool binderPool = BinderPool.getsInstance(BinderPoolActivity.this);
        IBinder securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);

        mSecurityCenter = SecurityCenterIml.asInterface(securityBinder);

        String msg = "Hello 安卓";

        try 
            String password = mSecurityCenter.encrypt(msg);
            Logger.i("encrypt:" + password);
            Logger.i("decrypt:" + mSecurityCenter.decrypt(password));
         catch (RemoteException e) 
            e.printStackTrace();
        

        IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
        mCompute = ComputeIml.asInterface(computeBinder);

        try 
            Logger.i("add 3 + 5 :" +  mCompute.add(3, 5) + "");
         catch (RemoteException e) 
            e.printStackTrace();
        

    

Log

 ╔════════════════════════════════════════════════════════════════════════════════════════
 ║ Thread: Thread-245
 ╟────────────────────────────────────────────────────────────────────────────────────────
 ║ BinderPoolActivity.access$000  (BinderPoolActivity.java:11)
 ║    BinderPoolActivity.doWork  (BinderPoolActivity.java:39)
 ╟────────────────────────────────────────────────────────────────────────────────────────
 ║ encrypt:;221~寗匍
 ╚════════════════════════════════════════════════════════════════════════════════════════
 ╔════════════════════════════════════════════════════════════════════════════════════════
 ║ Thread: Thread-245
 ╟────────────────────────────────────────────────────────────────────────────────────────
 ║ 
 ║    BinderPoolActivity.doWork  (BinderPoolActivity.java:40)
 ╟────────────────────────────────────────────────────────────────────────────────────────
 ║ decrypt:Hello 安卓
 ╚════════════════════════════════════════════════════════════════════════════════════════ ╔════════════════════════════════════════════════════════════════════════════════════════
║ Thread: Thread-245
╟────────────────────────────────────────────────────────────────────────────────────────
║ BinderPoolActivity.access$000  (BinderPoolActivity.java:11)
║    BinderPoolActivity.doWork  (BinderPoolActivity.java:49)
╟────────────────────────────────────────────────────────────────────────────────────────
║ add 3 + 5 :8
╚════════════════════════════════════════════════════════════════════════════════════════

这样如果有新业务需要加新的 AIDL ,那么实现它自己的 AIDL 接口后,只需要修改 BinderPoolIml 中的 queryBinder 方法,给自己添加一个新的 binderCode 并返回对应的 Binder 对象即可。

另一张表格来说明如何选择合适的 IPC 方式

以上是关于Binder连接池的主要内容,如果未能解决你的问题,请参考以下文章

Binder连接池

Binder连接池

IPC机制之Binder连接池

Android 跨进程通信-Binder机制传输数据限制—罪魁祸首Binder线程池

Binder线程池的启动流程分析

Binder线程池的启动流程分析