美文网首页
IPC之Binder连接池

IPC之Binder连接池

作者: 钦_79f7 | 来源:发表于2019-12-17 12:45 被阅读0次

    参考Android开发艺术探索

    Binder连接池

    什么是Binder连接池?为什么要使用它?

    之前的文章中我们分析了,Binder的使用以及AIDL的使用。大致流程就是:首先创建一个Service 和一个 AIDL 接口,接着创建一个类继承自 AIDL 接口中的Stub 类并实现Stub中的抽象方法,在Service 的onBind 方法中返回这个类的对象,然后客户端就可以绑定服务端Service,建立连接之后,就可以访问远程服务端的方法了。

    上述属于典型的AIDL的使用流程。那么当我们的项目越做越大,假如有10个不同的业务模块都需要使用AIDL进行通信呢?甚至100个呢?我们不可能按照标准流程创建100个Service进行通信吧,真要是这样的话,我们的APP在手机上运行时绝对是重量级的了。所以在这种大型的项目中我们寻找到一种让APP显得很轻量级的解决方案。

    回归初衷,创建Service的目的是作为一个远程服务进程,为我们的业务模块提供数据支持,那么这10个业务模块的运程逻辑我们可以让它们运行在用一个Service的进程中,然后通过Binder连接池来管理各自模块的binder。每个模块根据自身的需要得到对应的binder对象,来调用相应的远程服务。

    代码实现

    aidl

    IBinderPool.aidl

    // IBinderPool.aidl
    package com.stone.templateapp.demo.binderpool;
    
    // Declare any non-default types here with import statements
    
    interface IBinderPool {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        IBinder queryBinder(int binderCode);
    }
    

    ICompute.aidl

    // ICompute.aidl
    package com.stone.templateapp.demo.binderpool;
    
    // Declare any non-default types here with import statements
    
    interface ICompute {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        int add(int a, int b);
    }
    

    ISecurityCenter.aidl

    // ISecurityCenter.aidl
    package com.stone.templateapp.demo.binderpool;
    
    // Declare any non-default types here with import statements
    
    interface ISecurityCenter {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        String encrypt(String content);
        String decrypt(String password);
    }
    

    说明一下:这里我们通过 ICompute 与 ISecurityCenter 来代表多个业务模块的通信需求。两个足够说明逻辑流程了,再多的模块根据自身需求同理增加即可。

    IBinderPool.aidl 是Binder连接池对外提供获取binder对象的接口,然后我们只需要创建一个 IBinderPool对应的Service即可,各个业务模块通过Binder连接池提供的公开接口来获取各自对应的binder对象。

    服务端

    BinderPoolService.kt 连接池的服务

    class BinderPoolService : Service() {
        //Binder连接池 服务,统一向各个模块提供跨进程通信的Binder
        private val mBinderPool = BinderPool.BinderPoolImpl()
    
        override fun onBind(intent: Intent?): IBinder {
            println("on bind")
            return mBinderPool
        }
    }
    

    BinderPool.kt 连接池的具体实现逻辑

    class BinderPool private constructor(context: Context) {
        private val ctx: Context = context.applicationContext
    
        private lateinit var mConnectBinderPoolCountDownLatch: CountDownLatch
        private var mBinderPool: IBinderPool? = null
    
        companion object {
            private const val TAG = "BinderPool"
            const val BINDER_COMPUTE = 0
            const val BINDER_SECURITY_CENTER = 1
    
            @SuppressLint("StaticFieldLeak")
            @Volatile
            private var sInstance: BinderPool? = null
    
            /**
             * 懒汉式单例来处理BinderPool的对象获取
             */
            fun getInstance(context: Context): BinderPool {
                if (sInstance == null) {
                    synchronized(BinderPool::class.java) {
                        if (sInstance == null) {
                            sInstance = BinderPool(context)
                        }
                    }
                }
                return sInstance!!
            }
        }
    
        private val mBinderPoolDeathRecipient = object : IBinder.DeathRecipient {
            override fun binderDied() {
                Logs.w(TAG, "binder died.")
                mBinderPool?.asBinder()?.unlinkToDeath(this, 0)
                mBinderPool = null
                connectBinderPoolService()
            }
        }
    
        private val mBinderPoolConnection = object : ServiceConnection {
            override fun onServiceDisconnected(name: ComponentName?) {
                //do nothing
            }
    
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                mBinderPool = IBinderPool.Stub.asInterface(service)
                try {
                    //设置死亡代理
                    mBinderPool!!.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0)
                } catch (e: RemoteException) {
                    e.printStackTrace()
                }
                //连接上服务之后,调用countDown,使得被阻塞的线程继续执行
                mConnectBinderPoolCountDownLatch.countDown()
            }
        }
    
        init {
            //初始化中 绑定服务
            connectBinderPoolService()
        }
    
    
        @Synchronized
        private fun connectBinderPoolService() {
            //可以阻塞线程,在这里用来将异步操作 转换为同步操作
            mConnectBinderPoolCountDownLatch = CountDownLatch(1)
            //具体执行绑定服务
            ctx.bindService(Intent(ctx, BinderPoolService::class.java), mBinderPoolConnection, Context.BIND_AUTO_CREATE)
            try {
                //阻塞当前线程,等待 CountDown 为0。例如初始化中 count==1,那么只需要有一次的调用 countDown 方法,那么此处被阻塞的线程就会被唤醒 并继续执行
                mConnectBinderPoolCountDownLatch.await()
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
        }
    
        fun queryBinder(binderCode: Int): IBinder? {
            return try {
                //开放给外部,获取各自模块的binder
                mBinderPool?.queryBinder(binderCode)
            } catch (e: Exception) {
                null
            }
        }
    
    
        class BinderPoolImpl : IBinderPool.Stub() {
    
            @Throws(RemoteException::class)
            override fun queryBinder(binderCode: Int): IBinder? {
                //Binder池中具体生成模块各自的Binder
                return when (binderCode) {
                    BINDER_COMPUTE -> ComputeImpl()
                    BINDER_SECURITY_CENTER -> SecurityCenterImpl()
                    else -> null
                }
            }
        }
    }
    

    ComputeImpl 计算模块的Binder类

    class ComputeImpl : ICompute.Stub() {
        //计算模块的Binder类
        override fun add(a: Int, b: Int): Int {
            println("ComputeImpl invoke add")
            return a + b
        }
    }
    

    SecurityCenterImpl 加解密模块的Binder类

    class SecurityCenterImpl : ISecurityCenter.Stub() {
        //加解密模块的Binder类
        companion object {
            const val SECRET_CODE = '^'.toInt()
        }
    
        override fun encrypt(content: String): String {
            println("SecurityCenterImpl invoke encrypt $content")
            val chars = content.toCharArray()
            for ((i, char) in chars.withIndex()) {
                //按位异或
                chars[i] = (char.toInt() xor SECRET_CODE).toChar()
            }
            return String(chars)
        }
    
        override fun decrypt(password: String): String {
            return encrypt(password)
        }
    }
    

    客户端

    class BinderPoolActivity : AppCompatActivity() {
        companion object {
            const val TAG = "BinderPoolActivity"
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_binder_pool)
            setTitle(R.string.title_binder_pool)
            //由于绑定服务时,做了阻塞操作,所以这里需要在线程中执行。
            Thread(Runnable { doWork() }).start()
        }
    
        /**
         * 模拟各模块的调用
         */
        private fun doWork() {
            val binderPool = BinderPool.getInstance(act)
            val securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER)
            val mSecurityCenter = ISecurityCenter.Stub.asInterface(securityBinder)
            Logs.d(TAG, "visit ISecurityCenter")
            val msg = "helloWorld-安卓"
            println("content: $msg")
            try {
                val pwd = mSecurityCenter.encrypt(msg)
                println("encrypt: $pwd")
                println("decrypt: ${mSecurityCenter.decrypt(pwd)}")
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
    
            Logs.d(TAG, "visit ICompute")
            val mComputeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE)
            val mCompute = ICompute.Stub.asInterface(mComputeBinder)
            try {
                println("3 + 5 = ${mCompute.add(3, 5)}")
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
    
            Logs.d(TAG, "the work is finished")
        }
    }
    
    

    AndroidManifest

            <service
                android:name=".demo.binderpool.BinderPoolService"
                android:process=":binder_pool" />
            <activity android:name=".demo.binderpool.BinderPoolActivity" />
    

    运行结果

    com.stone.testdemo:binder_pool I/System.out: on bind
    com.stone.testdemo D/BinderPoolActivity: [ Thread-5577: (BinderPoolActivity.kt:30) doWork ] - visit ISecurityCenter
    com.stone.testdemo I/System.out: content: helloWorld-安卓
    com.stone.testdemo:binder_pool I/System.out: SecurityCenterImpl invoke encrypt helloWorld-安卓
    com.stone.testdemo I/System.out: encrypt: 6;221 1,2:s寗匍
    com.stone.testdemo:binder_pool I/System.out: SecurityCenterImpl invoke encrypt 6;221    1,2:s寗匍
    com.stone.testdemo I/System.out: decrypt: helloWorld-安卓
    com.stone.testdemo D/BinderPoolActivity: [ Thread-5577: (BinderPoolActivity.kt:41) doWork ] - visit ICompute
    com.stone.testdemo:binder_pool I/System.out: ComputeImpl invoke add
    com.stone.testdemo I/System.out: 3 + 5 = 8
    com.stone.testdemo D/BinderPoolActivity: [ Thread-5577: (BinderPoolActivity.kt:50) doWork ] - the work is finished
    

    结尾

    完成上述封装之后,当有新业务需要增加AIDL的时候,我们只需要实现自己的 AIDL 接口之后,修改一下 queryBinder 方法,并增加一个新的 binderCode 即可。并不需要创建新的 Service。

    相关文章

      网友评论

          本文标题:IPC之Binder连接池

          本文链接:https://www.haomeiwen.com/subject/yissnctx.html