欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Binder进程间通讯机制笔记

程序员文章站 2024-03-23 23:24:58
...

主要看的两篇文章
https://blog.csdn.net/luoshengyang/article/details/6618363
https://blog.csdn.net/freekiteyu/article/details/70082302
https://blog.csdn.net/china0851/article/details/87770359
1.Servermanager启动
1>servermanager分为framework层和native层,framework层只是对native层进行了封装方便调用
2>Servermanager的启动是在系统开机的时候,init进程解析init.rc文件调用servermanager.c中的main()方法进行启动的,native层还封装了一些与binder驱动交互的方法。

3>ServerManager如何成为binder守护进程
1>打开/dev/binder文件,open(“/dev/binder”, O_RDWR)
2>建立128k内存映射,mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
3>通知Binder驱动程序它是守护进程,binder_become_context_manager(bs);
4>进入循环等待请求的到来:binder_loop(bs, svcmgr_handler);
https://blog.csdn.net/xx326664162/article/details/50519294

内存映射操作mmap:
会使用进程虚拟地址空间和内核虚拟地址空间来映射同一个物理页面
这就是Binder进程间通信机制的精髓所在了,同一个物理页面,一方映射到进程虚拟地址空间,一方面映射到内核虚拟地址空间,这样,进程和内核之间就可以减少一次内存拷贝了,提到了进程间通信效率

那这个进程虚拟地址应该就是在ServerManager(位于用户空间)中,因为client 和server都是靠它来和驱动联系

2.Client和Server获取Servermanager的接口
1>对于Service Manager这个Server来说,Client如果想要获得Service Manager远程接口,却不必通过进程间通信机制来获得,因为Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0
2>获取Service Manager远程接口的函数是defaultServiceManager,这个函数声明在frameworks/base/include/binder/IServiceManager.h文件中;
3>Server和Client拿到这个Service Manager远程接口之后
对Server来说,就是调用IServiceManager::addService这个接口来和Binder驱动程序交互
对Client来说,就是调用IServiceManager::getService这个接口来和Binder驱动程序交互

3.Server:注册服务端
原文:https://blog.csdn.net/china0851/article/details/87770359

JAVA端

   BinderProxy:远程服务在本地的代理;

   Binder:实现IBinder接口,实体Service具体实现一般继承这个类,表示具体业务逻辑实现;

   Parcel:android的数据系列化类,直接在内存中操作,在JAVA端其只是个容器,真正实现在本地端;

   对应本地端

   BpBinder:远程服务代理对象,每个服务都会经过Binder驱动生成对应的handle一一对应;

   BBinder:据图服务的实现,其功能之一返回本地IBinder对象,这个对象相关信息会直接传给Binder驱动;

   Parcel:android数据系列化和反系列化本地管理类;

Binder进程间通讯机制笔记
1、SystemServer调用Servermanager.addService()注册系统服务

2、SystemServer被封装成flat_binder_object结构,此结构的type设置为BINDER_TYPE_BINDER

3、通过BpBinder–》IPCThreadState–》ioctl把请求发送到Binder驱动层,
Binder 驱动收到请求命令向 ServiceManager 的 todo 队列里面添加一条注册服务的事务。事务的任务就是如果没有server的实体就创建服务端进程 binder_node 信息并插入到ServiceManager进程对应的 binder_procs 链表中

4、最后Binder驱动把处理后的数据请求发送到ServiceManager进程进行处理;

5、ServiceManager解析请求后,根据服务名称把SystemService中实体服务对应的handle(这个handle是存储在ServiceManager进程对应的binder_proc里的)保存为一个列表条目 svcinfo

4.Client:通过ServiceManager 获取服务
Binder进程间通讯机制笔记
1、ServiceManager收到getService请求后,会从自己的列表里通过name找到对应的远程系统服务的handle值

2、ServiceManager用这个handle值来填充flat_binder_object结构,然后把请求发送到Binder驱动

3、Binder驱动收到ServiceManager返回的数据后先用这个handle在ServiceManager进程对应的binder_proc里查询到系统服务在ServiceManager的引用(binder_ref),通过binder_ref获取得到真正的远程系统服务实体binder_node;

4、通过真正的远程系统服务实体binder_node在客户端进程里查询是否有这个binder_node的引用,如果没有就会生成binder_ref,同时插入客户端进程对应的binder_proc,到这里远程系统服务在客户端进程里有了一个对应的handle;

5、最后Binder驱动把客户端生成的handle替换flat_binder_object结构里的handle值,然后发送给客户端;
最后客户端进程获取到的远程系统服务对应的代理handle就是客户端进程自己生成的,结合前面章节,我们知道客户端拿到的代理在JAVA层对象是BinderProxy,在native层是BpBinder

首先server和client都调用了ProcessState的构造函数从而都向驱动申请了一块物理内存用于通信数据的存放,然后:
1.server调用SM的addService函数传递一个字符串和实际Binder对象在自己虚拟地址空间的地址到Binder驱动,Binder驱动记录下该地址值,在SM申请的物理内存中分配一个虚拟地址并连同字符串一起传递给SM,而且Binder驱动会记录下两个地址之间的对应关系.
2.client调用SM的getService函数传递一个字符串给SM,SM将相对应的虚拟地址值传递给Binder驱动,Binder驱动查询出实际对象的地址,在client申请的物理内存中分配一个虚拟地址并传递给client,而且Binder驱动会记录下这个地址和实际Binder对象地址之间的对应关系,client这里得到的就是实际Binder的引用了.
到了这一步,真正的Binder对象就拥有两个引用,一个在SM,一个client.
3.client通过得到的Binder引用调用server中的函数,驱动会根据传递过来引用值找到应该处理该请求的进程,并唤醒其中的Binder线程,调用BBinder对象的onTransaction函数,最终调用到实际的函数。

client的缓存:
在Client进程,每一个BpxxxService对象都封装了一个BpBinder对象,因此,确切来说,Client进程缓存的是BpBinder对象,每一个BpBinder对象都与一个Binder句柄值对应。每当Client进程需要创建一个BpxxxService对象时,就会检查本地缓存中是否已经存在对应的BpBinder对象。如果存在的话,就可以直接使用它来创建一个BpxxxService对象,否则的话,就要通过Binder驱动程序来获得一个Binder句柄值,再以这个句柄值来创建一个BpBinder对象,最后再根据这个BpBinder对象来创建一个BpxxxService对象。