内存划分
操作系统为了系统和程序的安全,用虚拟内存映射真正的物理内存,把各个程序内存进行隔离。同时把内存分为内核空间和用户空间,程序间通信只能通过内核空间作为中介通信。
传统 IPC 传输数据
可以看到,一个应用的数据传输到一个另一个应用,需要两次复制 copy_from_user(), copy_to_user()
Binder数据传输
原理
相对传统的IPC,Binder通信只用一次内存复制 copy_from_user()
,把数据从发起端复制到内核。 然后接收端部分内存和内核该部分内存使用 memory map(mmap),接收端可以直接读取使用数据,而不用复制。
内部实现
调用流程
对比
AIDL使用
-
定义接口
-
在生成的aidl文件夹创建接口,接口定义要调用的方法。
package top.xlxs.bean; import top.xlxs.bean.Person; interface ILeoAidl { void addPerson(in Person person); List<Person> getPersonList(); }
-
除了支持的几种数据类型,自定义类型要实现
Parcelable
,重写其转变Parcel的方法。package top.xlxs.bean; parcelable Person;
Bean类:Person.kt
package top.xlxs.bean; import android.os.Parcel; import android.os.Parcelable; class Person() : Parcelable { var name: String? = null var grade: Int = 0 constructor(parcel: Parcel) : this() { name = parcel.readString() grade = parcel.readInt() } constructor(name: String?, grade: Int) : this() { this.name = name this.grade = grade } override fun writeToParcel(parcel: Parcel, flags: Int) { parcel.writeString(name) parcel.writeInt(grade) } override fun describeContents(): Int { return 0 } override fun toString(): String { return "Person(name=$name, grade=$grade)" } companion object CREATOR : Parcelable.Creator<Person> { override fun createFromParcel(parcel: Parcel): Person { return Person(parcel) } override fun newArray(size: Int): Array<Person?> { return arrayOfNulls(size) } } }
-
之后新建一个同名的AIDL文件,作为自定义Bean类的映射。对其操作或传输的AIDL接口需导入这个类,不管在不在同一包。
package top.xlxs.bean; import top.xlxs.bean.Person; interface ILeoAidl { void addPerson(in Person person); List<Person> getPersonList(); }
-
make project 生成AIDL文件对应的Java 接口。
-
导入,绑定另一个进程Service,使用
-
-
使用
客户端
- 设置intent,绑定另一个进程service
- 绑定成功调用
Stub.asInterface()
返回对方IBinder(AIDL对象) - 之后就可以调用在Aidl接口定义的方法,跟另一进程通信
服务端:
-
实现自己的Service,内部 新建一个
IJinAidl.Stub()
实例private var iBinder = object : IJinAidl.Stub() { override fun addPerson(person: Person?) { Log.i(TAG, "addPerson: $person") persons.add(person!!) } override fun getPersonList(): MutableList<Person> { Log.i(TAG, "getPersonList: $persons") return persons } override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean { try { super.onTransact(code, data, reply, flags) } catch (e: Exception) { e.printStackTrace() } return true } }
-
,重写onBind方法,把实例化好的
IJinAidl.Stub()(iBinder)
返回
-
注意事项
- 项目里Bean类与其AIDL文件需要有相同包名。另一个进程(service)的AIDL文件也需在相同包名。
源码解析
bindService
分析ContextImpl
ActivityManager.getService().bindIsolatedService()
IActivityManager == IJinAidl aidl接口
ServiceManager.getService(Context.ACTIVITY_SERVICE) ==> IBinder
IActivityManager == Proxy
ActivityManager.getService() ==> Proxy
ActivityManagerNative == Stub
ActivityManagerProxy == Proxy
ActivityManagerService === Service
查看ActivityManagerService
ActivityManagerService#bindServiceLocked()
1.ActiveServices#bringUpServiceLocked()
2.ActiveServices#requestServiceBindingLocked(s, b.intent, callerFg, true);
requestServiceBindingLocked开始真正绑定
// 没有创建app
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
// 创建了App
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.getReportedProcState());
查看 ActivityThread 的 scheduleBindService
sendMessage(H.BIND_SERVICE, s); // handler 消息驱动
// 查看handleMessage 的 BIND_SERVICE情况
handleBindService()
mServices.get(data.token);
IBinder binder = s.onBind(data.intent);
IActivityManager#publishService