LOADING

加载过慢请开启缓存 浏览器默认开启

Binder 跨进程通信的机制

Binder 是 Android 中实现的进程间通信。在操作系统内核层面,有 Binder 驱动提供支持。

Android 中存在众多系统服务(Service),分别运行在不同的进程中,而应用程序在底层通过 Binder 与这些服务进行交互。

Binder 机制可以通过 共享内存 实现。

每个进程可以像打开文件一样打开 Binder “设备”,而每个进程最多只能打开一个 Binder,其子线程共享该 Binder。

Android 中存在一个 ServiceManager 进程,用于管理其他所有的服务,其自身也是一个服务。

一个进程先获取到 ServiceManager 的 IBinder,再通过 ServiceManager 获得目标服务的 IBinder。

假设一个应用程序 example 想查询当前的 wifi 列表,example 只需要调用 Android Framework 提供的一系列 API 进行操作,拿到 WifiManager 的 IBinder,最终通过 Binder 的 transact 函数执行对应操作。

具体过程如下:

Binder.transact(int code, Parcel data, Parcel reply, 其他参数...)

应用程序将使用一个 code 来告诉服务端执行哪个操作,而 data 则是这个操作的参数,由应用程序写入。Binder.transact 可以理解为一个系统调用,此时陷入操作系统内核,执行 Binder 驱动,将操作请求转发给 Wifi 服务进程,然后挂起当前应用程序的进程,以等待 Wifi 服务进程处理完这个操作请求。当 Wifi 服务进程处理完操作,会将返回数据写入 reply(写入过程可以是共享内存的方式),然后唤醒应用程序的进程,应用程序从 reply 中取出数据。

在这个过程中,需要对 datareply 反复进行装包和解包,过程比较繁琐,因此,通常会使用 AIDL 工具自动生成对应的接口、实现及代理。

共享内存:

假设客户端进程C,想要访问服务进程S的数据。

由于进程隔离机制,客户端C并不能直接访问进程S的数据,可以认为进程拥有自己独立的地址空间。

此时,客户端C通过一个 ServiceManager 间接获取到一个 IBinder 对象的引用,借助 Binder 驱动申请了一段内存,将 C 进程中一部分虚拟地址映射到这段内存,同时也将 S 进程中一部分虚拟地址映射到这部分内存,此时,S 将数据写入这部分新分配的内存后,C 进程也能访问这部分内存,实现了共享内存。

这里的内存映射:

C 进程拥有的对象 IBinder,在 C 进程中的虚拟内存地址假设为 0x7777,而 S 进程拥有的 Binder 对象在 S 进程中的虚拟地址为 0xAAAAA,但实际上两者所指向的是同一块物理内存。虽然二者实际都是访问同一块物理内存,但二者拥有的权限不同。

内存映射的方式减少了内存数据冗余和复制操作的开销。