Android 进阶——Framework 核心之Binder 对象及其生命周期小结
Posted CrazyMo_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 进阶——Framework 核心之Binder 对象及其生命周期小结相关的知识,希望对你有一定的参考价值。
文章大纲
引言
前面几篇文章都数次提到了Binder ,那么Binder 到底是什么呢?
一、Binder概述
android 中核心IPC 机制就是通过Binder实现的,Binder 翻译过来是粘合剂的意思,Android 在架构上一直希望模糊进程的概念,而是以组件替代。应用不需要关心组件存放的位置、运行组件的进程和组件的生命周期等细节,却可以在系统中随时随地地进行进程间通信,这就需要通过一种手段把组件“粘合”起来,于是乎Binder应运而生,与传统IPC 相比,融合了远程调用RPC概念,一种面向对象而非面向过程的RPC调用,Binder就像一张网跨越进程和线程将系统组件组织在一起,只要拥有Binder对象就可以使用其组件的功能,即两个进程之间通过Binder对象互相通信,Android Binder IPC架构以面向对象的调用方式使用Binder
,使得在调用远程对象时和调用一个本地对象实例一样。
此组件非Android 四大组件中的组件。
二、Binder 对象
一系列Binder实体对象(binder_node)和Binder引用对象(binder_ref)。在用户空间,运行在Server端的称为Binder本地对象,运行在Client端的称为Binder代理对象;而在内核空间,Binder实体对象用来描述Binder本地对象,Binder引用对象用来描述Binder代理对象。
图摘自https://blog.csdn.net/universus/article/details/6211589?spm=1001.2014.3001.5501
三、Binder 对象生命周期的管理
从上面Binder IPC交互过程可以看到,Binder代理对象与Binder引用对象存在映射关系,Bin der引用对象又与Binder实体对象存在多对一的映射关系,Binder实体对象还依赖于Binder本地对象,为了维护管理这些Binder对象,Binder 采用了引用计数来维护每一个Binder对象的生命周期。
如上图所示,假如Client进程将一个Binder代理对象封装成三个不同的BpInterface对象且三个BpInterface对象都通过强指针引用该Binder代理对象(即该代理对象的强、弱引用计数都等于3)。而一个Binder代理对象只有在创建时才会增加相应的Binder引用对象的弱引用计数,且在第一次被强指针引用时才会增加相应的Binder引用的强引用计数,因此Binder引用对象的强、弱引用计数都为1,小于引用了它的Binder代理对象的强、弱引用计数,即一个Binder代理对象的引用计数与其的引用对象的引用计数是N:1的关系。这样就可以减少Client与Binder驱动的交互,较少BC_ACQUIRE、BC_INCREASE、BC_RELEASE和BC_DECREFS协议交互。
1、Binder本地对象(BBinder)的生命周期管理
Binder本地对象
类型为BBinder
,由用户空间的Server进程创建,一方面会被Server进程的其他对象引用(得益于Android 智能指针技术(RefBase),Server进程其他对象可以通过智能指针来引用这些Binder本地对象。),另一方面被Binder驱动的Binder实体对象间接引用。因为Binder 驱动的Binder实体对象运行于内核空间,不能直接通过智能指针来引用,需要Binder驱动和Server进程约定一套协议来维护它们的引用计数,随即引入了Server Manager
角色参与管理。
Server进程将一个Binder本地对象注册到
Server Manager
时,Binder驱动就会自动为它创建一个Binder实体对象
。当Client进程通过Server Manager
来查询一个Binder本地对象的代理对象
时,Binder驱动就为Binder代理对象所对应的Binder实体对象创建一个Binder引用对象
,然后通过BR_INCREFS和BR_ACQUIRE协议来通知相应的Server进程增加对应的Binder本地对象
的弱引用计数和强引用计数的值。这样就能确保Client进程中的Binder代理对象在引用一个Binder本地对象期间,Binder本地对象不会被销毁;而当没有任何Binder代理对象引用一个Binder本地对象时,Binder驱动就会使用BR_DECREFS和BR_RELEASE协议通知Server 进程减烧对应的本地对象的弱引用和强引用计数的值。
Binder驱动通过BR_INCREFS、BR_ACQUIRE、BR_DECREFS和BR_RELEASE协议来引用运行在Server进程的Binder本地对象并协助管理引用计数的值。
\\kernel\\drivers\\android\\binder.c
static int binder_thread_read(struct binder_proc *proc,struct binder_thread *thread,binder_uintptr_t binder_buffer, size_t size,binder_size_t *consumed, int non_block)
...
while (1)
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w = NULL;
...
if (!binder_worklist_empty_ilocked(&thread->todo))
list = &thread->todo;
else if (!binder_worklist_empty_ilocked(&proc->todo) &&
wait_for_proc_work)
list = &proc->todo;
else
binder_inner_proc_unlock(proc);
/* no data added */
...
switch (w->type)
...
case BINDER_WORK_NODE:
struct binder_node *node = container_of(w, struct binder_node, work);
int strong, weak;
...
//检查改Binder实体对象是否有强引用计数和弱引用计数
strong = node->internal_strong_refs ||
node->local_strong_refs;
weak = !hlist_empty(&node->refs) ||
node->local_weak_refs ||
node->tmp_refs || strong;
if (weak && !has_weak_ref)
node->has_weak_ref = 1;
node->pending_weak_ref = 1;
node->local_weak_refs++;
if (strong && !has_strong_ref)
node->has_strong_ref = 1;
node->pending_strong_ref = 1;
node->local_strong_refs++;
if (!strong && has_strong_ref)
node->has_strong_ref = 0;
if (!weak && has_weak_ref)
node->has_weak_ref = 0;
...
if (weak && !has_weak_ref)
ret = binder_put_node_cmd(
proc, thread, &ptr, node_ptr,
node_cookie, node_debug_id,
BR_INCREFS, "BR_INCREFS");
if (!ret && strong && !has_strong_ref)
ret = binder_put_node_cmd(
proc, thread, &ptr, node_ptr,
node_cookie, node_debug_id,
BR_ACQUIRE, "BR_ACQUIRE");
if (!ret && !strong && has_strong_ref)
ret = binder_put_node_cmd(
proc, thread, &ptr, node_ptr,
node_cookie, node_debug_id,
BR_RELEASE, "BR_RELEASE");
if (!ret && !weak && has_weak_ref)
ret = binder_put_node_cmd(
proc, thread, &ptr, node_ptr,
node_cookie, node_debug_id,
BR_DECREFS, "BR_DECREFS");
if (ret)
return ret;
break;
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION:
struct binder_ref_death *death;
uint32_t cmd;
death = container_of(w, struct binder_ref_death, work);
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
else
cmd = BR_DEAD_BINDER;
binder_stat_br(proc, thread, cmd);
break;
...
return 0;
当Binder驱动和进程或者线程通信时,会把一个task(BINDER_WORK_NODE类型,是一个语Binder实体对象相关的,代表要修改与Binder实体对象所对应的Binder本地对象的引用计数)添加到todo队列中。同时目标进程或者线程就会不断地调用Binder驱动程序的binder_thread_read函数轮询todo队列,有task则去除并返回到用户空间去处理。然后Binder驱动接着就会去根据规则来请求增加或者减少对应Binder本地对象的引用计数值。需要注意的是,对于BR_INCREFS和BR_ACQUIRE协议,Server进程会马上增加Binder本地对象的强引用或弱引用计数,并使用BC_INCREFS_DONE和BC_ACQUIRE_DONE协议通知Binder驱动;而对于BR_RELEASE和BR_DECREFS,Server进程是先将它们缓存在IPCThreadState类的成员变量mPendingStrongDerefs 和mPendingWeakDerefs ,等到Server 进程下次使用IO控制指令BINDER_WRITE_READ进入Binder驱动之前,再来处理,这样处理的原因是想让Server进程优先去处理其他更重要的事。
2、Binder 实体对象(binder_node)生命周期的管理
Binder实体对象
类型为binder_node
,由内核空间的Binder驱动创建,会**被Binder驱动中的Binder引用对象
**所引用。Client进程首次引用一个Binder实体对象时,Binder驱动就会在内部为这个Binder实体对象创建一个对应的Binder引用对象。当Client进程通过Server Manager 来获取一个Server 组件的代理对象时,Binder驱动就会先找到组件对应的Binder实体对象,再创建一个Binder引用对象来引用它,即增加被引用的Binder实体对象的引用计数;而当Client进程不再引用一个Server组件时,就会请求Binder驱动释放之前为所创建的一个Binder引用对象,即减少该Binder引用对象锁引用的Binder实体对象的引用计数。
3、Binder 引用对象(binder_ref)生命周期的管理
Binder引用对象
类型为binder_ref
,由内核空间的Binder驱动创建,会**被B用户空间的中的Binder代理对象
**所引用。Client进程引用了Server进程的一个Binder本地对象
时,Binder驱动就会在内部为这个Binder本地对象创建一个对应的Binder引用对象。Binder引用对象运行于内核空间的Binder驱动程序中,而引用了它的Binder代理对象运行在用户空间的Client进程,不能直接管理,也是通过内部的BC_INCREFS、BC_ACQUIRE、BC_DECREFS和BC_RELEASE协议来增加或者减少强引用计数或弱引用计数。
一个Binder实体对象可以有多个Binder(本地对象的)引用对象。
4、Binder 代理对象(BpBinder)生命周期的管理
Binder代理对象
类型为BpBinder
,由用户空间的Client进程创建,与Binder本地对象类似,一方面会被Client进程的其他对象引用(得益于Android 智能指针技术(RefBase),Server进程其他对象可以通过智能指针来引用这些Binder本地对象。),另一方面它会主动去引用Binder驱动的引用对象。因为Binder 驱动的Binder引用对象运行于内核空间,不能直接通过智能指针来引用,也是通过内部的BC_INCREFS、BC_ACQUIRE、BC_DECREFS和BC_RELEASE协议来增加或者减少强引用计数或弱引用计数。
每一个Binder代理对象都是通过一个句柄值与一个Binder引用对象管理的,Client进程就是通过这个句柄值为维护运行在它里面的Binder代理对象的。
Client进程会在内部建立一个handle_entry类型的Binder代理对象列表,以句柄值为关键字来维护其所有的Binder代理对象。其中handle_entry结构体力有一个指向BpBinder的IBinder指针(即Binder代理对象的地址),当Client进程接到驱动传递过来的句柄值,就以这个句柄值在其内部Binder代理列表去检索是否存在对应的handlle_entry结构体,存在则Client进程继续使用该结构体的BpBinder对象与Server进程通信,反之则会先创建一个BpBinder对象并保存至handle_entry结构体中并将该结构体保存到Binder代理对象列表中(这个Binder代理对象类似缓存池,可以避免重复创建Binder代理对象来引用Binder驱动中同一个Binder引用对象)
简而言之,每一个Binder代理对象都对应一个handle_entry结构体实例,结构体的两个成员变量binder和refs,分别指向Binder代理对象以及其内部的一弱引用计数对象。
struct handle_entry IBinder* binder; RefBase::weakref_type* refs; ;
BpBinder::BpBinder(int32_t handle): mHandle(handle), mAlive(1), mObitsSent(0), mObituaries(NULL)
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle);
当BpBinder 构造函数被调用时,最终还是通过IPCThreadState的incWeakHandle函数增加handle对应的Binder引用对象的弱引用计数,
void IPCThreadState::incWeakHandle(int32_t handle)
mOut.writeInt32(BC_INCREFS);//内部协议通知给Binder驱动去增加弱引用计数,本质上就是把数据写入到Parcel中
mOut.writeInt32(handle);
而当BpBinder 析构函数被调用时,也是通过IPCThreadState的decWeakHandle函数去减少的。总之,有一个Binder代理对象可能被用户空间Client进程的其他对象所引用,当其他对象通过强指针来引用时,Client进程需要请求Binder驱动增加引用计数,但为了减少Client进程与驱动的交互开销,只有当Binder代理对象真正第一次被强指针引用时,Client进程才会请求Binder驱动增加对应Binder引用对象的强引用计数
5、Binder本地对象的异常死亡通知机制
理想情况下,通过智能指针结合那八种内部协议就可以正确的维护和管理Binder 中各个对象的生命周期,但是当Client或者Server进程异常死亡时,其依赖关系就会处处,因此需要一种监控Binder本地对象死亡的机制,当监听到Binder本地对象死亡时间后,通知所有引用了这个Binder本地对象的代理对象(也是需要通过IPCThreadState实现)。
5.1、Binder本地对象死亡监听的注册
Binder代理对象在注册它所引用的Binder本地对象的死亡监听之前,首先要定义好死亡通知的接受者,即必须要继承IBinder的内部类DeathRecipient
,实现很鉴定单只需要重写其函数binderDied即可。在这个Binder代理对象所引用的Binder本地对象死亡时自动触发binderDied函数。其次就是注册死亡通知接收者,调用Binder代理对象中的linkToDeath函数即可完成注册。
5.2、Binder本地对象死亡的判断及通知
当Server进程启动时会主动函数open_binder来打开binder设备文件/dev/binder/,如果是正常退出会自动去调用close函数来关闭设备文件/dev/binder;而异常退出就没有正常关闭binder文件,那么内核就负责去关闭它,随即触发了函数binder_release,于是Binder驱动在通过在binder_release函数中检查进程退出后是否有Binder本地对象在里面运行,有则表示他们已经是死亡的Binder本地对象了,最后再通过内部协议BR_DEAD_BINDER通知Client进程。
5.3、Binder本地对象死亡的反注册
当Client进程不需要监听一个Binder本地对象的死亡事件时,就可以调用Binder代理对象的unLinkToDeath来反注册前面的一个死亡事件监听。
6、引用计数管理小结
当一个Binder实体对象的引用计数由0变成1或者1变成0时,Binder驱动会请求相应的Service组件增加或者减少其引用计数。
- 当一个Bidner实体对象请求一个Service组件来执行某一操作时,会增加该Service组件的强或弱引用计数,Binder实体对象会将has_strong_ref和has_weak_ref置为1
- 当一个Service组件完成一个Binder实体对象所请求的操作后,Binder对象会请求减少该Service组件的强或弱引用计数
- Binder实体对象在请求一个Service组件增加或减少强或弱引用计数的过程中,会将pending_strong_ref或pending_weak_ref置为1,当Service组件完成增加或减少计数时,Binder实体对象会将这两个变量置为0。
以上是关于Android 进阶——Framework 核心之Binder 对象及其生命周期小结的主要内容,如果未能解决你的问题,请参考以下文章
Android 进阶——系统启动之Framework 核心ActivitityManagerService服务启动
Android 进阶——Framework核心 之Binder Java成员类详解
Android 进阶——Framework核心 之Binder Java成员类详解
Android 进阶——Framework 核心之Touch事件分发机制详细攻略