Android Binder -- AIDL 原理

Android Binder – AIDL 原理

要理解AIDL的原理,其实很简单,就是不通过AIDL完成一次Binder IPC调用。

一个简单的实例

我们创建一个Binder对象并将其添加到ServiceManager中,并且在另外一个进程中引用。

需要对binder机制有一定了解。
使用ServiceMananger需要相应的jar包,编译framework后生成的classes.jar

定义通用接口

和Native Binder类似,要使用Binder,我们就要定义一个继承了IInterface的接口,并在其中定义codedescriptor以及声明我们的IPC函数。

import android.os.Binder
import android.os.IInterface

interface ICustomService : IInterface {
    companion object {
        const val TRANSACTON_GETPID = Binder.FIRST_CALL_TRANSACTION + 0
        const val descriptor = "com.github.service.ICustomService"
    }
    fun getPid(): Int;
}

接下来,无论是Binder实体类还是Binder代理类,都需要实现该接口。

IPC服务提供者

定义Binder实体类

对于Binder实体类,除了继承之前定义的ICustomService还要继承Binder并且实现它的onTransact:

根据code的不同,执行不同的逻辑。

这里定义为抽象类,所以后续还要继承该类并实现 未实现的方法

也可以直接在这里实现 所有方法。后续直接创建 对象并添加到ServiceManger中

import android.os.Binder
import android.os.IBinder
import android.os.Parcel

abstract class BnCustomService : Binder(), ICustomService {

    override fun asBinder(): IBinder = this

    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
        when (code) {
            ICustomService.TRANSACTON_GETPID -> {
                data.enforceInterface(ICustomService.descriptor)
                reply?.writeInt(getPid())
                return true
            }
            INTERFACE_TRANSACTION -> {
                reply?.writeString(ICustomService.descriptor)
                return true
            }
            else -> {
                return super.onTransact(code, data, reply, flags)
            }
        }
    }
}

将Binder实体对象添加到ServiceManager

首先我们要为BnCustomService实例化一个对象,由于其实抽象类,所以我们定义了一个匿名类并在其中实现了getPid方法。

然后调用ServiceManager.addService将其添加到ServiceManager中。

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Process
import android.os.ServiceManager

class MainActivity : AppCompatActivity() {
    private val mBinder = object: BnCustomService() {
        override fun getPid(): Int {
            return Process.myPid()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onStart() {
        super.onStart()
        ServiceManager.addService("liutimo", mBinder)
    }
}

IPC服务消费者

同样需要继承ICustomService

import android.os.IBinder
import android.os.Parcel

class BpCustomService(val remote: IBinder) : ICustomService {

    override fun getPid(): Int {
        val data = Parcel.obtain()
        val reply = Parcel.obtain()
        data.writeInterfaceToken(ICustomService.descriptor)
        remote.transact(ICustomService.TRANSACTON_GETPID, data, reply, 0)
        val pid = reply.readInt()
        data.recycle()
        reply.recycle()
        return pid
    }

    override fun asBinder(): IBinder {
        return remote
    }
}

和前面不同的是,这里持有了一个IBinder对象。该对象通过ServiceManager.getService获得。和Native Binder中的BpRefBaseBpBinder是一样的。

然后,就可以获取服务并执行IPC函数了。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
    fun onClick(view: View) {
        when (view.id) {
            R.id.button -> {
                val binder = ServiceManager.getService("liutimo")
                val proxy = CustomServiceProxy(binder)
                Toast.makeText(this, "${proxy.getPid()}", Toast.LENGTH_SHORT).show()
            }
            else -> {
            }
        }
    }
}

总结

大家可以看一下aidl文件编译后生成的class文件,基本上就是上面这些流程,不过是将我们的ICustomServiceBnCustomServiceBpCustomService改了名字并且放在一个文件里面。还额外提供了一个asInterface函数来完成我们上面的val proxy = CustomServiceProxy(binder)操作。

使用AIDL的好处就是我们可以省略上述的一些繁琐的通信过程(这些AIDL都自动帮我们完成了),只需要关注接口的实现即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值