Binder 跨进程通信

围巾🧣 2021年03月06日 503次浏览

内存划分

操作系统为了系统和程序的安全,用虚拟内存映射真正的物理内存,把各个程序内存进行隔离。同时把内存分为内核空间和用户空间,程序间通信只能通过内核空间作为中介通信。

内存

传统 IPC 传输数据

可以看到,一个应用的数据传输到一个另一个应用,需要两次复制 copy_from_user(), copy_to_user()

IPC

Binder数据传输

原理

相对传统的IPC,Binder通信只用一次内存复制 copy_from_user(),把数据从发起端复制到内核。 然后接收端部分内存和内核该部分内存使用 memory map(mmap),接收端可以直接读取使用数据,而不用复制。

Binder

内部实现

Binder

调用流程

Binder

对比

对比

AIDL使用

  1. 定义接口

    • 在生成的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,使用

  2. 使用

    客户端

    1. 设置intent,绑定另一个进程service
    2. 绑定成功调用Stub.asInterface()返回对方IBinder(AIDL对象)
    3. 之后就可以调用在Aidl接口定义的方法,跟另一进程通信

    服务端

    1. 实现自己的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
          }
      
      }
      
    2. ,重写onBind方法,把实例化好的 IJinAidl.Stub()(iBinder)返回

  3. 注意事项

    • 项目里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

Android实现的Binder

os-binder