符合中小企业对网站设计、功能常规化式的企业展示型网站建设
本套餐主要针对企业品牌型网站、中高端设计、前端互动体验...
商城网站建设因基本功能的需求不同费用上面也有很大的差别...
手机微信网站开发、微信官网、微信商城网站...
一. 引言--女娲造人的故事
成都创新互联公司-专业网站定制、快速模板网站建设、高性价比德城网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式德城网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖德城地区。费用合理售后完善,10多年实体公司更值得信赖。
在天地混沌之际,上神女娲因为觉得自己太孤单,没人跟它一起嗨,决定按照自己的模样添加一些生物;于是呢,捏泥为人,并赋予了人生育的能力,所以女娲被称为了人类的母亲;
神话故事很美好,解释了人类的来源,但是这个逻辑中其实有个缺陷,就是女娲从哪里来的?
那有些同学就会问了,这里说Binder设计,为什么要提到女娲造人的故事呢?这是因为二者在源头这个问题的处理上有异曲同工之妙,嗯,后面会再做说明。
二. Android Binder简介
Andoid Binder从Open Binder发展而来,提供了跨进程通信机制;其实linux已经提供很多的跨进程机制,比如管道,共享内存等等,那为什么google要使用binder呢?
其实,大家也可以思考下,针对于移动设备这种低配置的设备(相对于服务器),新的进程间通信机制需要具备什么新的优点呢?
1.内存节省,因为移动设备的低配置,所以需要新的通信机制尽可能的节省资源,binder在跨进程数据拷贝时只进行一次;
2.高效性,比如对于手机这种东西,大家肯定希望它反应迅速,界面流畅;
3. 安全性,手机涉及了大量的用户隐私,比如支付宝账号,电话本联系人号码,短信记录,通话记录等等;
在linux系统中对于权限安全性管理,UID是一个很重要的东西,所以对于安全性,binder就在binder driver里面负责填写调用进程的UID和PID;相比一些在应用程序填写UID和PID的进程间通信机制,安全性得到了极大提高。
总体来说,Binder肯定是一个不错的进程间通信机制,否则android经过这么多年的发展,如果Binder不是足够优秀的话,以google的技术实力,早就被google替换了吧!
三.Binder通信关系总图
Binder作为Android里面进程间通信机制,主要有4个模块参与这个过程,分别是
client
service
ServiceManager
Binder Driver
client和service作为通信的模块很容易理解,因为client需要和service通信,所以它们两个必然会成为通信的一部分。
那service manager和Binder driver起的作用是什么呢?
service manager提供service的注册,查询等服务,那说的再明白一点,就是service Binder本地对象把自己和一个名字添加到service manager注册;
这样,client就可以向service manager通过指定的名字去查询之前注册的service,从而找到对应的Binder实体对象,再继而生成属于自己进程的Binder 引用对象。
最后把这个属于自己进程的Binder引用对象和自己进程内的一个Binder代理对象对应起来;这样client就间接的拥有了service Binder本地对象的引用,进而可以和service通信。
那Binder driver是做什么用的呢?
Binder driver提供的是桥梁的作用,比如从service注册是service manager,抑或从client到service mangager查询service,以及从client到service的通信,都需要通过Binder driver。
所以Binder driver提供了一个桥梁,同时在通信的过程中记录了一些数据。
为了更好的说明,先上一张整体Binder的关系图。
这张图已经基本包括了binder通信过程中的所有对象,我们可以用言语来简略的描述下这个过程和各个对象的含义,至于更详细的我们后面再讲。
过程简短描述:
1.首先这张图有两个空间,用户空间和内核空间;client, service,service manager运行在用户空间;而binder driver运行在内核空间。
2.service manager首先注册为binder driver的服务管理者,注册的过程中,service manager会调用open和mmap方法来通知binder driver为它分配一块最大不超过4MB的内存,当然这个大小可以由service manager来指定,service manager指定的是128KB。这块内存同时被两个虚拟地址应用,一个binder driver的一个是service manager的。
换句话就是说binder driver为service manager分配了一块同时被内核空间和用户空间映射的内存。
这也是binder驱动的精华,通过这种虚拟内存双重映射,减少了binder driver和service manager之间的数据拷贝。
3.这样,binder driver就记录下了与service manager 对应的binder实体对象(也就是图中的sm binder实体)。
并且强制规定sm binder实体对象对应的是句柄值是0。也就是其他进程来访问service,只要它传到binder driver的句柄值是0,那就意味着目标service就是service manager。
然后service manager进程进入等待状态,等待别的进程来唤醒。比如别的进程要注册service或者查询service。
4.service进程启动后,同样会通过open和mmap方法通知binder driver为service进程分配一块不超过4MB的内存,一般应用程序的是1MB左右(1mb - 8kb)。
同第2点一样,这块内存也被binder driver内核空间和service进程用户空间的虚拟地址同时映射。
然后向service manager注册service;正如第2点所言,binder driver强制规定了0号句柄对应的是service manager实体对象,所以service进程只要传入0号句柄,然后把想注册的service一起传入过来就可以了。
5.binder driver接到service的ioctl调用后,找到第2点描述的sm binder实体,然后通过这个sm binder实体找到service manager对应的进程。
此时,service manager的进程正在睡眠等待状态,于是binder driver把要处理的工作封装成一个binder_transaction丢给service manager进程,也就是把数据拷贝到binder driver为service manager分配的那块内存(也就是第2步binder driver为service manager分配的那块内存),这也是binder数据传输的唯一一次数据拷贝,然后唤醒它。
6.此时,service进程会返回service进程用户空间,然后会再次进入binder driver,并且进入等待状态;它需要等待service manager注册service的返回结果。
7.service manager进程被唤醒后,回到service manager用户空间,同时把binder driver拷贝过来的数据读取出来,把名称和从binder driver传入的句柄值保存起来,再次执行结果通过ioctl指令通知binder driver。
8.service manager进程回到binder driver之后,通过之前第5步产生的binder_transaction找到之前调用的binder driver的service进程和线程,把第7点从service manager返回的结果读出来,然后拷贝到binder driver为service分配的内存,再唤醒service线程。
9.service manager在binder driver完成之后,会再次进程等待状态。
10.service进程被service manager进程唤醒之后,会回到service进程的用户空间,然后把第8步binder driver拷贝service进程内存的数据读取出来(这块内存在binder driver中,被service进程和binder driver同时映射),再完成最后的逻辑。
11.client进程启动后,也会像service和service manager一样通过open和mmap方法请求binder driver为client进程分配一块内存用户进程间通信。
12.client进程向service manager发起查询service请求,同时传入要查询service的名称,传入的binder句柄值是0,也就是对应着service manager。
13.binder driver接受到client的查询请求后,根据句柄值0找到service manager的binder实体对象(sm binder实体),然后通过sm binder实体对象找到service manager进程。此时,service manager进程正处于等待状态。
14.binder driver把从client传入的数据拷贝到为service manager分配的那块内存,生成一个binder_transaction,然后唤醒service manager进程。
15.client进程经过一些处理后进入等待状态,等待service manager来唤醒。
16.service manager被唤醒后,把binder driver拷贝给它的数据读取出来,当然最重要的是从client进程传入的service 名称。通过查找,找到名称对应的句柄值。也就是第7点那个名称和句柄值。然后通过ioctl再次回到binder driver。
17.binder driver通过binder_transaction找到第15点的client进程和线程,通过从service manager返回的句柄值找到binder driver里面对应的service 实体对象。然后唤醒client线程。
18.在binder driver里面,client线程根据service 实体对象,生成属于client进程的binder引用对象,也就是一个句柄值,再返回client进程用户空间。
19.在client进程用户空间,把句柄值拷贝出来,封装成一个BpBinder对象,BpBinder对象里面mHandle值就保存了这个句柄值。
20.client和service通信,client使用第19步获取到的mHandle句柄值,发送给binder driver。
21.binder driver根据mHandle句柄值找到client进程内对应的binder引用对象,再根据binder引用对象找到它对应的binder实体对象,再根据binder实体对象找到其所在的binder进程。然后把数据拷贝到binder driver为service进程分配的那块内存,再唤醒service进程。
22.client进程的调用线程进入等待状态。
23.由于binder实体对象有个cookie值指向用户空间service进程的的service地址,所以service在被唤醒后,它可以找到是由哪个service组件来响应此次服务(service进程内可能不止一个service组件)。
24.service完成自己的逻辑后,再次通过binder_ioctl通知binder driver,告诉binder driver处理结果,然后再唤醒client进程。这个过程就和service manager通知service是一样的了。
这样,整个通信过程就基本结束了。
ps:
1. 这里说的service和android应用里面说的4大组件service并不是一个概念,这里的service指的是提供Binder服务的Binder本地对象。
2. 上面说的Binder代理对象,Binder引用对象,Binder实体对象,Binder本地对象是按照从client到service的顺序的,可以按个解释下这几个对象的含义。
a. Binder代理对象,运行在client用户空间,对应的类是BpBinder,实现的关键在于它有个句柄mHandle变量,通过这个变量可以在Binder driver内核空间里面找到对应的Binder引用对象。
b. Binder引用对象,运行在Binder driver内核空间,对应的数据是binder_ref结构体。
c. Binder实体对象,运行在Binder driver内核空间,对应的数据是binder_node结构体。
d.Binder本地对象,运行在service用户空间,对应的数据是BBinder,其实就是一个提供服务的Binder service。
3. 可能大家看到看到对于service manager在binder driver中, client和并没有binder引用对象,而其他service在client进程中却有binder 引用对象,这是为什么呢?
这个问题就回到文章开始的第一点,里面在描述女娲造人关于源头这个问题上的时候,我们说神话故事里面假设女娲是事先存在的,从而弥补了这个故事里面的漏洞。
那在binder机制里面,也有这个问题:就是client通过service manager拿到service的binder句柄值,那么service怎么拿到service manager的句柄值呢?
就好比说人是女娲造的,那女娲又是哪里来的呢?
好吧,跟神话故事一样,我们也是假设service manager是事先存在的,并且规定它的句柄值就是0。
那么client和service只要传入句柄0就可以找到service manager在binder driver中的binder实体对象,自然也不需要binder 引用对象了。
而且service manager进程也不会像其他service进程一样,可能存在多个service服务。
4. service manager请求binder driver为它分配的内存是128kb,一般应用程序(client, service)请求binder driver为它分配的内存是1MB - 8KB。
这是我们要求使用binder时不能传输大于1MB数据的原因,比如通过intent传输图片,很有可能会超过binder传输上限。当然这个我们在后面分析代码的时候会看到。
详见:
android_proj/framework/base/libs/binder/ProcessState.cpp
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
5. 在上图中大家看到有些service进程中可能存在多个service组件,比如service2进程。它们都通过binder driver注册到了service manager,但是它们有不同的名称对应以及不同的service组件地址,这两个区别分别会被service manager和binder driver(通过binder_node结构体的cookie数据)所记住。
所以可以区分。
6. binder线程池,用户空间的程序有个线程池来响应binder driver,但是有个上限,一般是15个线程,详见
android_proj/framework/base/libs/binder/ProcessState.cpp
open_driver(){
...
size_t maxThreads = 15;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
...
}
但是需要说明的是这15个线程指的是binder driver请求用户空间程序创建的最大线程数(当应用程序线程数不足以响应binder请求时,binder driver会请求应用程序分配线程),并不包括用户空间程序主动注册到binder driver的。
四. binder机制中的数据结构
在初步了解binder机制的通信过程后,我们需要更深一步的了解binder通信,所以需要简单讲解下binder通信过程中的数据结构。
用户空间数据 | binder driver内核空间数据 | 描述 |
flat_binder_object | binder_node | binder service对象描述,每个添加到binder driver的service都会对应一个binder_node,包括service manager也是 。 flat_binder_object顾名思义就是压扁了的binder_object,为什么要压扁呢?是为了传输的需求,所以把binder对象从用户空间传输到binder driver内核空间的时候,就需要用到这个数据结构,比如addService的时候。 |
client,service进程 | binder_proc | 对应一个进程,当进程调用open方法打开binder driver的时候,binder driver会保存这个进程的相关信息,就是用binder_proc这个数据结构。 在上面我们说起过,一个进程中可能有多个service组件,比如service2进程,那在binder driver里面也是这种关系。 binder_proc和binder_node是一对多的关系。 binder_proc使用了红黑树的数据结构来描述了它里面binder_node。 红黑树的数据结构大家有不清楚可以百度下。 |
线程 | binder_thread | binder_thread是线程在binder driver中的描述,所以binder_proc和binder_thread的对应关系也是1对多,也是用红黑树来组织的。 |
binder_transaction_data | binder_transaction | binder_transaction用来描述binder driver里面的一个事务。事务在数据库里面用的比较多,binder driver也借用了这个概念。 那binder_transaction_data就刚好是用来描述从用户空间到内核空间传输binder_transaction数据的。 |
- | binder_buffer | 在前面描述过,binder driver会为每个进程分配一个不超过4MB的内存,用来传输数据。 那怎么来管理这块内存呢? binder driver把这块内存划成一页一页来管理,那一个binder_buffer就表示一页。 |
- | binder_ref | binder driver里面的binder引用对象。 binder_ref主要的作用就是拥有一个句柄值,同时指向一个binder_node binder实体对象。 句柄值对应client里面的binder代理对象BpBinder里面的mHandle,所以client可以根据mHandle找到内核对应的binder_ref数据。 binder_ref关联的binder_node对象,这样,找到binder_ref后,就可以进一步找到binder_node。 binder_node上面讲过,关联了binder_proc,以及service进程里面的service组件,也就是binder本地对象。 所以,通过这一层层的关联,都连接起来了。 |
- | binder_ref_death | 跟binder本地对象死亡通知有关。 我们知道binder机制是这样的引用的。 BpBinder(mHandle)->binder_ref->binder_node->BBinder binder本地对象。 那如果binder本地对象意外的挂了呢?比如service所在进程由于程序逻辑错误异常退出了,调用它的client怎么办呢? 所以为了部分解决这个问题,binder因为死亡通知这个功能,当binder本地对象消亡之后,需要通知正在监听它的binder_ref client。 |
- | binder_work | binder driver的工作项描述,后面再具体描述。 |
binder_write_read | binder_write_read | ioctl指令BINDER_WRITE_READ的数据结构。 |
五. 实名binder对象和匿名binder对象
所谓的实名和匿名是针对service manager而言的,就是service manager知不知道这个binder对象的存在,并且给它一个名字相对应。
正如第一步里面所描述的女娲造人的故事,女娲可以造人,但是人也可以造人。如果把女娲比喻成service manager,那么第一代人就是实名binder对象,第一代人以及后面的人造的人就是匿名binder对象;
因为它对于女娲这个service manager而言,女娲并不知道它们的存在和名字。
这个比喻如果难以理解的话,那再举个更加现实的栗子:
如果一个人想进入火车候车室,那么他需要火车票或者站台票,那我们现在来做如下比喻:
例子 | binder | |
进入候车室 | 实现binder通信功能 | |
火车票 | 实名binder对象 | |
站台票 | 匿名binder对象 | |
铁道部 | service manager | |
检票口 | binder driver |
1.假如把进入候车室这个功能比喻成实现binder通信这个功能,那么:
2.火车票和站台票都可以进入候车室,也就是说实名binder和匿名binder都可以完成进程间通信功能,这点并没有什么区别。
3.由于火车票是实名制的,所以铁道部能知道卖出的票和购买人的***一一对应;但是对于站台票,铁道部并不能知道这种对应关系;
那对于service manager和实名binder,匿名binder也是这种关系 -- service mangager清楚的知道所有实名binder的名称,binder服务所在的进程等等信息,但是对于匿名binder却一无所知,它甚至不知道匿名binder的存在。
4.购买站台票不是想买就可以买的,需要持有火车票吃可以购买站台票;
那对于实名binder和匿名binder也是如此,匿名binder不是想创建就能创建的,首先需要得到一个实名binder,通过实名binder得到匿名binder,具体例子可以参考bindService得到一个匿名binder的实现。
5.对于检票口,不管是火车票还是站台票都会从检票口通过,所以检票口可以记录一些信息;同样,对于binder driver,不管是实名binder还是匿名binder都会通过binder driver,binder driver也会记录它们的信息。
六. binder ioctl指令
ioctl指令名称 | 含义 | 注释 |
BINDER_WRITE_READ | 最重要的ioctl指令,后面可以执行很多binder命令操作。 | 独特的先写后读的设计,给予了用户空间程序更多的便利。 |
BINDER_SET_IDLE_TIMEOUT | 暂未使用 | |
BINDER_SET_MAX_THREADS | 设置binder driver可以请求用户空间进程最大线程数。 | 不包括用户空间进程主动注册到binder driver的线程。 |
BINDER_SET_IDLE_PRIORITY | 暂未使用 | |
BINDER_SET_CONTEXT_MGR | 通知binder driver,当前进程成为binder机制上下文,也就是service mangager | binder driver里面只能存在一个service manager,多次调用会出错。 |
BINDER_THREAD_EXIT | 通知binder driver线程退出 | |
BINDER_VERSION | 返回当前binder driver版本号 |
七. binder命令
binder命令按照命令的流向性分为两大类:
1.BC_XXX
2.BR_XXX
从用户空间流向binder driver的命令被称为BC_XXX,也就是binder command的简称;相应的从binder driver流向用户空间进程的称为BR_XXX,也就是binder return的简称。如下图:
对于所有的binder 命令,可以用下面两张表来描述:
具体可以参考./working_directory/kernel/goldfish/driver/staging/android/binder.h
enum BinderDriverCommandProtocol {
...
}
enum BinderDriverReturnProtocol {
...
}
3.BC_XXX
命令名称 | 含义 | 注释 |
BC_TRANSACTION | 意思是进行一次transaction,比如addService,getService,或者client跨进程调用service方法等等。 | 最重要的binder命令之一,一般通过ioctl--BINDER_WRITE_READ来和binder driver交互。 |
BC_REPLY | 回复binder driver | 比如addService的时候,service manager在处理完自己的逻辑后会发送此命令到binder driver,告诉binder driver自己处理结果。 |
BC_ACQUIRE_RESULT | 暂不支持 | |
BC_FREE_BUFFER | 通知binder driver去释放一个binder_buff的内存,参数int表示此binder_buff在用户空间进程的虚拟映射地址。 | 一般是在处理完一个事务之后,通知binder driver释放先关内存。 |
BC_INCREFS | 通知binder driver增加目标service 弱引用, 参数int表示目标service的handle值, | |
BC_ACQUIRE | 通知binder driver增加目标service 强引用,参数int表示目标service的handle值. | |
BC_RELEASE | 通知binder driver减少目标service强引用,参数int表示目标service的handle值. | |
BC_DECREFS | 通知binder driver减少目标service弱引用,参数int表示目标service的handle值. | |
BC_INCREFS_DONE | 通知binder driver BR_INCREFS命令执行完毕,一般由service进程在处理完binder driver的BR_INCREFS命令后向binder driver发出。 | |
BC_ACQUIRE_DONE | 通知binder driver BR_ACQUIRE命令执行完毕,一般由service进程在处理完binder driver的BR_ACQUIRE命令后向binder driver发出。 | 因为binder driver在请求service进程增加一个service组件的强引用之后,它需要等待service组件增加强引用计数的结果,它需要根据这个结果修改自己的一些状态。 |
BC_ATTEMPT_ACQUIRE | 暂不支持 | |
BC_REGISTER_LOOPER | 通知binder driver此进程进入BINDER_LOOPER_STATE_REGISTERED状态,再经过一些处理就会进入就绪状态,可以处理进程的事务。 此命令是binder driver通知用户空间进程创建线程后,用户空间进程创建线程后会调用此命令,通知binder driver此线程已经准备好。 | |
BC_ENTER_LOOPER | 用户空间进程主动请求binder driver通知此线程可以处理进程间binder 通信请求,一般如果没有事情做的话,会进入等待状态。 | 此命令和BC_REGISTER_LOOPER的区别就是 BC_ENTER_LOOPER是用户空间进程主动通知binder driver的, BC_REGISTER_LOOPER是binder driver发现此用户空间进程的线程池无法响应binder通信,需要创建新线程;然后向目标用户空间进程发出请求创建线程命令 用户空间进程创建线程完毕后,会调用BC_REGISTER_LOOPER通知binder driver。 |
BC_EXIT_LOOPER | 通知binder driver此线程退出 | |
BC_REQUEST_DEATH_NOTIFICATION | client请求binder driver注册目标service组件的死亡通知 | 以便在目标serive组件死亡的时候得到通知,然后client可以处理自己的逻辑。 |
BC_CLEAR_DEATH_NOTIFICATION | client通知binder driver取消注册对某个service binder本地对象的死亡通知监听 | |
BC_DEAD_BINDER_DONE | client通知binder driver对某个service进程的binder本地对象死亡通知处理完毕。 |
4.BR_XXX
命令名称 | 含义 | 注释 |
BR_ERROR | 通知用户空间进程,binder driver处理出现异常 | |
BR_OK | 通知用户空间进程,binder driver处理成功 | |
BR_TRANSACTION | binder driver请求用户空间进程处理一个事务,事务的数据方法binder_transaction_data结构体中, | 比如addService的时候,binder driver请求service manager去注册一个service。 |
BR_REPLY | binder driver通知用户空间进程处理完毕 | 比如用户空间进程发起的BC_TRANSACTION 处理完毕后,binder driver就会反馈BR_REPLY |
BR_ACQUIRE_RESULT | 暂不支持 | |
BR_DEAD_REPLY | binder driver反馈目标binder对象已经死亡,返回错误。 | |
BR_TRANSACTION_COMPLETE | binder driver反馈事务处理完成 | |
BR_INCREFS | binder driver请求用户空间进程增加指定binder本地对象的弱引用 | |
BR_ACQUIRE | binder driver请求用户空间进程增加指定binder本地对象的强引用 | |
BR_RELEASE | binder driver请求用户空间进程减少指定binder本地对象的强引用 | |
BR_DECREFS | binder driver请求用户空间进程减少指定binder本地对象的弱引用 | |
BR_ATTEMPT_ACQUIRE | 暂不支持 | |
BR_NOOP | 没有什么操作 | |
BR_SPAWN_LOOPER | binder driver请求用户空间进程分配一个线程;这种情况一般是在用户空间进程线程池无法处理binder driver间通信请求的情况下。 | |
BR_FINISHED | 暂不支持 | |
BR_DEAD_BINDER | 通知用户空间进程所监听的binder本地对象已经销毁 | |
BR_CLEAR_DEATH_NOTIFICATION_DONE | 在用户空间进程请求BC_CLEAR_DEATH_NOTIFICATION命令后,binder driver返回这个命令通知用户空间进程 | |
BR_FAILED_REPLY | binder driver返回失败 | |
八. 引用计数
在第七点的表中,我们提到了所有的Binder协议命令,其中包括类似BC_INCREFS,BC_ACQUIRE,BC_RELEASE,BC_DECREFS之类的命令,表中解释是维护binder对象的引用计数;那为什么要进行这样的设计呢?
那我们可以来做这样一种假设:
client进程引用service进程的一个binder本地对象正在通信,如果这个时候service进程把这个binder本地对象回收了怎么办?
为了解决这个问题,binder机制使用了引用的概念:
在Java里面,我们知道维护一个对象的生命周期可以通过强引用,软引用,弱引用和虚引用来实现(具体的区别大家可以百度,里面一些区别和技巧还是很有用的,特别是软引用用来实现图片的缓存),只要一个对象被从垃圾回收的根节点强引用所关联,那么它是不会被回收的。
所以,类似的,binder机制里面也采用这个概念。
那,binder driver为什么不直接引用binder 本地对象呢?
这是因为binder driver是在内核空间,binder本地对象在service进程的用户空间,不能直接引用。
所以,binder 机制才通过这种通过命令调用的方式,通知service进程为指定的binder本地对象增加/减少引用,从而达到维护用户空间service进程binder本地对象生命周期的目的。
九. 死亡通知机制
通过上面几点介绍,一到七点保证了binder间进程通信,第八点保证了生命周期管理,一切看起来都那么完美。
但是,还是有意外情况发生,那就是:
提供服务的service进程死亡了怎么办?
对应这个问题,client和binder driver都爱莫能助,因为它们也无法控制service进程的生命周期。又回到了第八点阐述的那个问题:
client进程引用service进程的一个binder本地对象正在通信,如果service进程的binder本地对象不存在了怎么办?
对于service进程死亡,一般可以分为两种情况:
1.正常死亡,比如程序自己退出
2.异常退出,比如因为程序里面的一个逻辑错误导致进程退出
如果是第1种情形,程序会自己主动close掉自己进程打开的binder driver;从而调用到binder driver的binder_release函数。
如果是第2种情形,操作系统会帮我们close,从而也可以调用binder driver的binder_release函数。
所以,上面两种可能都可以在binder driver的binder_release函数中去解决。
binder 机制死亡通知的过程是这样的:
a.client进程拿到指向service进程binder本地对象的引用后,它可以向这个service进程binder本地对象请求注册一个死亡通知(其实就是BpBinder,因为它实现了死亡通知的接口)。
b.binder driver记录下了这层对应关系。
c.当binder driver检测到目标service进程已经死亡时,它找到这个进程所有binder本地对象在binder driver里面对应的binder实体对象。
d.然后根据binder实体对象找到所有引用它的binder引用对象,如果发现binder引用对象有注册死亡通知,那么就封装一个binder_work项给binder引用对象所在的进程,然后唤醒它;让那个进程去完成自己的逻辑。
至此,binder设计篇内容全部提供完毕,下面会写一些binder实现篇的东西,也就是从代码的角度来分析这些内容。