binder机制之我的理解
第一步
service端,先向系统的ServiceManager 注册自己的服务,拿到唯一的服务号(binder句柄)
后续client通过这个句柄找到服务。
第二步:
client端,想要service提供的服务,就向ServiceManager询问,查到了service的注册的服务,
ServiceManager 给了client端个Service 的**代理对象
(Proxy),这个代理对象运行在Client进程空间,它不执行实际逻辑,
只负责打包请求并发送给内核驱动,并在发送完之后,线阻塞,等待服务端的响应。
第三步:Client调用代理对象的transact方法,打包参数
(Transaction Data),数据被拷贝到Client进程的一块内核缓冲区中。
Binder驱动通过‘mmap机制,将这块内核缓冲区映射**到Service 进程的虚拟地址空间。
数据只需要从User空间拷贝到Kernel 空间一次,然后通过内存映射让 Service 进程直接访问,无需第二次拷贝。(全程只有一次拷贝)
第四步:Binder驱动将事务标记为“等待回复”,并唤醒Service进程中正在等待的Binder线程
Service 的Binder 线程从映射的内存中读取请求数据,并执行真正的业务。
第五步:
Service执行完毕后,将结果写入内核缓冲区(此时数据仍在共享映射区)。
Binder 驱动通知Client进程“数据已就绪”。
Client 进程的Binder 线程从映射内存中读取结果(第二阻塞的线程)
代理对象解包结果,返回给
Client业务代码,事务结束。
Client 端如何通过 Proxy对象发起调用
当 Client 端通过‘bindService或类似方式获取到远程服务的IBinder引用时,它实际上拿到的是一个Stub.Proxy实例Stub.Proxy
内部持有一个mRemote:IBinder对象,这个对象指向远程Service进程中的实际Binder实体。
Proxy方法被调用时,首先创建一个Parcel对象,并将参数写入其中。
mRemote.transact(code, data.reply,flags)。这是触发IPC的关键步骤。
transact()中code,是表示调用哪个方法,data就是请求参数。reply就是等待接受返回值的。
将_data 中的数据拷贝到内核空间。
注意:这里的reply是个空信封,没有写数据,等待服务端写入的。
-唤醒系统中的Binder 驱动线程
-当前线程进入休眠,等待远程处理完成并写入‘_reply。
Binder驱动执行以下操作:驱动分配一个内存空间,将Parcel 中的原始字节数,
拷贝到内核空间。解析引用查找目标进程/线程
唤醒 Server 的Binder线程
Server 线程将返回结果序列化,放入一个reply缓冲区。通知Binder驱动准备发送回复,此时数据仍在Server的用户空间中,尚未进入内核。
Binder驱动不会直接拷贝整个数据块,而是通过‘mmap机制,在Client进程的用户空间和内核空间之间建立映射关系。
Binder 驱动将响应标记为“就绪”,并通过等待队列唤醒之前阻塞的Client线程。Client反序列化数据,就拿到了执行结果。
浙公网安备 33010602011771号