Binder 对象引用计数
Binder 对象引用计数技术
微信截图_20180702183953.png 微信截图_20180702184020.png它们的交互过程可以分为5个步骤,如下所示:
(1) 运行在 Client 进程的 BpBinder 通过 Binder Drvier 向运行在 Server 进程的 BBinder 发送通信请求,Binder Driver 根据 Client 进程的 BpBinder 的句柄值找到对应的 binder_ref
(2) Binder Dirver 根据找到的 binder_ref 找到 binder_node, 并创建 binder_transaction(事务) 来描述此次通信过程.
(3) Binder Driver 根据 binder_node 找到 Server 进程的 BBinder, 将 Client 进程传递的通信数据发送给它.
(4) BBinder 处理完 Client 的请求后,将通信结果返回给 Binder Driver, Binder Driver 找到之前创建的 binder_transaction.
(5) Binder Driver 根据前面找到的事务的相关属性来找到发出进程通信请求的 Client 进程,并且通知 Client 进程将通信结果返回给对应的 BpBinder 来处理.
从上述过程来看, BpBinder 依赖于 binder_ref, 而 BBinder 依赖于 binder_node.所以必须采用一种技术保证不能销毁一个还被依赖着的对象.
BBinder 的生命周期
BBinder 可能会被 Server 进程的其他对象引用,也可能被 Binder Driver 的 binder_node 引用.
- 被 Server 进程的其他对象引用:
RefBase ---- 通过智能指针控制其生命周期. - 被 binder_node 引用
binder_node 处于 Kernel Space,无法使用 智能指针.
需要重新约定一套规则来维护它们的引用计数.
- BR_INCREFS
- BR_ACQUIRE
- BR_DECREFS
- BR_RELEASE
维护 Service 组件 即 BBinder 的生命周期.
Binder Driver 要和目标进程或线程通信时,会把一个工作项加入到它的 todo list 中.目标进程或线程会不断的调用 Driver 的 binder_thread_read 来检查它的 todo list 中是否有新的工作项.如果有,将之读取出来,然后返回到用户空间去处理.
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)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
......
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w = NULL;
struct list_head *list = NULL;
struct binder_transaction *t = NULL;
struct binder_thread *t_from;
binder_inner_proc_lock(proc);
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 */
if (ptr - buffer == 4 && !thread->looper_need_return)
goto retry;
break;
}
if (end - ptr < sizeof(tr) + 4) {
binder_inner_proc_unlock(proc);
break;
}
w = binder_dequeue_work_head_ilocked(list);
switch (w->type) {
....
case BINDER_WORK_NODE: {
// 此时 binder_node 是一个 工作项
struct binder_node *node = container_of(w, struct binder_node, work);
int strong, weak;
// 指向 Userspace 的 Service 组件内部的一个引用计数对象(weakref_impl)的地址(用户空间地址)
// 指向 Userspace 的 Service 组件的地址(用户空间地址)
binder_uintptr_t node_ptr = node->ptr;
binder_uintptr_t node_cookie = node->cookie;
int node_debug_id = node->debug_id;
int has_weak_ref;
int has_strong_ref;
void __user *orig_ptr = ptr;
BUG_ON(proc != node->proc);
// 这是什么意思?
strong = node->internal_strong_refs ||
node->local_strong_refs;
weak = !hlist_empty(&node->refs) ||
node->local_weak_refs ||
node->tmp_refs || strong;
/*
* has_strong_ref 和 has_weak_ref (默认为1):
* 如果 Driver 已经请求了 Server 进程的 BBinder 为 binder_node 增加了引用计数,
* 那么 Driver 就会将 binder_node 的 has_strong_ref 和 has_weak_ref 设置为1; 否则为0.
*/
has_strong_ref = node->has_strong_ref;
has_weak_ref = node->has_weak_ref;
/**
* 引用技术的说明:
* 1. internal_strong_refs, local_strong_refs 描述 binder_node 的强引用计数。
* 2. local_weak_refs 描述 binder_node 的弱引用计数。
* 3. 一个 binder_node 请求 Service 执行某一操作时,会增加该 Service 的 strong refs 或 weak refs;
* 相应的,binder_node 会将成员变量 has_strong_ref 或 has_weak_ref 的值设置为1.
* 4. 当一个 Service 组件完成一个 binder_node 所请求的操作后,
* binder_node 就会请求减少该 Service 的 strong refs 或 weak refs。
* 5. binder_node 在请求一个 Service 增加或减少引用计数的过程中,
* 会将成员变量 pending_strong_ref 或 pending_weak_ref 的值设置为1;
* 当 Service 增加或减少了引用计数后,binder_node 就会将这两个成员变量的值设置为0.
* 6. 当 binder_node 的引用计数由0->1, 或由1->0时,Binder Driver 会请求相应的 Service 增加或减少其引用计数。
* 这时候Binder Driver会将修改引用计数的操作封装成一个类型为 binder_node 的工作项,
* 即将 binder_node 的 work 的值设置为 BINDER_WORK_NODE,并将它添加到相应的进程的 todo list 中,等待处理。
*/
/*
* 这里有一个思想上的转换:
* has_weak_ref, local_weak_refs, has_strong_ref, local_strong_refs
* 描述的是 binder_node 的引用计数.而不是 Service 的引用计数.
* 只是 binder_node 和 Service 相关,当 binder_node 引用计数变化时,需要通知 Service 修改引用计数.
*/
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;
/*
* binder_node 已经引用了一个 BBinder,但是没有增加它的弱引用计数,通过 BR_INCREFS 增加弱引用计数.
*/
if (weak && !has_weak_ref)
ret = binder_put_node_cmd(
proc, thread, &ptr, node_ptr,
node_cookie, node_debug_id,
BR_INCREFS, "BR_INCREFS");
/*
* binder_node 已经引用了一个 BBinder,但是还没有增加它的强引用计数,通过 BR_ACQUIRE 增加 强引用计数.
*/
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");
/*
* binder_node 不再引用 BBinder, 但是还没有减少强引用计数,通过 BR_RELEASE 减少强引用计数.
*/
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");
/*
* binder_node 不再引用 BBinder,但是还没有减少它的弱引用计数,通过 BR_DECREFS 减少弱引用计数.
*/
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;
...
}
}
}
- UserSpace 如何处理?
// IPCThreadState
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_ACQUIRE:
refs = (RefBase::weakref_type*)mIn.readPointer();
obj = (BBinder*)mIn.readPointer();
obj->incStrong(mProcess.get()); // 增加 强引用计数.
mOut.writeInt32(BC_ACQUIRE_DONE); // 告诉 Driver , 增加强引用计数 操作 DONE
mOut.writePointer((uintptr_t)refs);
mOut.writePointer((uintptr_t)obj);
break;
case BR_RELEASE:
refs = (RefBase::weakref_type*)mIn.readPointer();
obj = (BBinder*)mIn.readPointer();
mPendingStrongDerefs.push(obj); // 放到 vector 中,等下次 IO 命令处理
break;
case BR_INCREFS:
refs = (RefBase::weakref_type*)mIn.readPointer();
obj = (BBinder*)mIn.readPointer();
refs->incWeak(mProcess.get()); // 增加 弱引用计数
mOut.writeInt32(BC_INCREFS_DONE); // 发送 BC_INCREFS_DONE 命令.
mOut.writePointer((uintptr_t)refs);
mOut.writePointer((uintptr_t)obj);
break;
case BR_DECREFS:
refs = (RefBase::weakref_type*)mIn.readPointer();
obj = (BBinder*)mIn.readPointer();
mPendingWeakDerefs.push(refs); // 放到 vector 中,等下次 IO 命令处理
break;
}
}
/*
* 减少引用计数无返回,且不着急处理.
* 增加引用计数有返回,且必须马上处理,因为如果不处理,很有可能对象被释放.
*/
binder_node 生命周期
binder_node 由 Driver 创建,并且被 binder_ref 所引用.
当 Client 进程通过 ServiceManager 获取 Service 组件的代理对象接口时,Drvier就会找到该 Service 组件的 binder_node, 然后再创建一个 binder_ref 来引用它.这是就需要增加 binder_node 的引用计数.相反,当 Client 不再引用一个 Service 组件时,就会请求 Driver 释放 binder_ref,这是就需要减少 binder_node 的引用计数.
- 增加引用计数: binder_inc_node
static int binder_inc_node(struct binder_node *node, int strong, int internal,
struct list_head *target_list)
{
int ret;
binder_node_inner_lock(node);
ret = binder_inc_node_nilocked(node, strong, internal, target_list);
binder_node_inner_unlock(node);
return ret;
}
-
BpBinder <---> binder_ref
-
BBinder <---> binder_node
-
binder_ref --引用--> binder_node
-
binder_node 对应于 Server, 那么它的 local 的意思就是 Server 进程内; 那么 internal 就是 描述 binder_ref 对 binder_node 的引用,可以认为是 kernel internal.
-
local_weak_refs, local_strong_refs 描述 binder_node 和 BBinder 之间的引用关系.如 Drvier 请求 Server 进程指向某一操作,就会增加 BBinder 对应的 binder_node 的 local 引用计数,避免 binder_node 被过早的销毁.
-
Client 进程通过 binder_ref 来引用 binder_node 时, Driver 就会增加 binder_node 的 internal 引用计数,防止 binder_node 的过早销毁.
-
为什么只有 internal_strong_refs ,没有 internal_weak_refs?
因为 binder_node 的成员变量 refs 隐含了 internal_weak_refs.
/*
* strong : 是否是强引用计数.
* internal: 内部引用计数还是外部引用计数.
* target_list: 指向目标进程或目标线程的 todo list.如果非NULL,就表示增加了 binder_node 引用计数后,需要增加它所引用的 BBinder 引用计数.
*/
static int binder_inc_node_nilocked(struct binder_node *node, int strong,
int internal,
struct list_head *target_list)
{
struct binder_proc *proc = node->proc;
assert_spin_locked(&node->lock);
if (proc)
assert_spin_locked(&proc->inner_lock);
if (strong) {
if (internal) {
if (target_list == NULL &&
node->internal_strong_refs == 0 &&
!(node->proc &&
node == node->proc->context->
binder_context_mgr_node &&
node->has_strong_ref)) {
pr_err("invalid inc strong node for %d\n",
node->debug_id);
return -EINVAL;
}
node->internal_strong_refs++;
} else
node->local_strong_refs++;
/*
* 一个 binder_node 请求 Service 执行某一操作时,会增加该 Service 的 strong refs 或 weak refs;
* 相应的,binder_node 会将成员变量 has_strong_ref 或 has_weak_ref 的值设置为1.
*/
if (!node->has_strong_ref && target_list) {
binder_dequeue_work_ilocked(&node->work);
binder_enqueue_work_ilocked(&node->work, target_list);
}
} else {
if (!internal)
node->local_weak_refs++;
if (!node->has_weak_ref && list_empty(&node->work.entry)) {
if (target_list == NULL) {
pr_err("invalid inc weak node for %d\n",
node->debug_id);
return -EINVAL;
}
binder_enqueue_work_ilocked(&node->work, target_list);
}
}
return 0;
}
- 减少引用计数: binder_dec_node
static void binder_dec_node(struct binder_node *node, int strong, int internal)
{
bool free_node;
binder_node_inner_lock(node);
free_node = binder_dec_node_nilocked(node, strong, internal);
binder_node_inner_unlock(node);
if (free_node)
binder_free_node(node);
}
static bool binder_dec_node_nilocked(struct binder_node *node,
int strong, int internal)
{
struct binder_proc *proc = node->proc;
assert_spin_locked(&node->lock);
if (proc)
assert_spin_locked(&proc->inner_lock);
if (strong) {
if (internal)
node->internal_strong_refs--;
else
node->local_strong_refs--;
if (node->local_strong_refs || node->internal_strong_refs)
return false;
} else {
if (!internal)
node->local_weak_refs--;
if (node->local_weak_refs || node->tmp_refs ||
!hlist_empty(&node->refs))
return false;
}
if (proc && (node->has_strong_ref || node->has_weak_ref)) {
if (list_empty(&node->work.entry)) {
binder_enqueue_work_ilocked(&node->work, &proc->todo);
binder_wakeup_proc_ilocked(proc);
}
} else {
if (hlist_empty(&node->refs) && !node->local_strong_refs &&
!node->local_weak_refs && !node->tmp_refs) {
if (proc) {
binder_dequeue_work_ilocked(&node->work);
rb_erase(&node->rb_node, &proc->nodes);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"refless node %d deleted\n",
node->debug_id);
} else {
BUG_ON(!list_empty(&node->work.entry));
spin_lock(&binder_dead_nodes_lock);
/*
* tmp_refs could have changed so
* check it again
*/
if (node->tmp_refs) {
spin_unlock(&binder_dead_nodes_lock);
return false;
}
hlist_del(&node->dead_node);
spin_unlock(&binder_dead_nodes_lock);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"dead node %d deleted\n",
node->debug_id);
}
return true;
}
}
return false;
}
binder_ref 生命周期
- BC_ACQUIRE
- BC_INCREFS
- BC_RELEASE
- BC_DECREFS
增加或减少 binder_ref 的引用计数.
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
struct binder_context *context = proc->context;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error.cmd == BR_OK) {
int ret;
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]);
atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]);
atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]);
}
switch (cmd) {
case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS: {
uint32_t target;
const char *debug_string;
bool strong = cmd == BC_ACQUIRE || cmd == BC_RELEASE; // 是否为 强引用计数
bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE; // 是否为 增加引用计数
struct binder_ref_data rdata;
if (get_user(target, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
ret = -1;
if (increment && !target) {
struct binder_node *ctx_mgr_node;
mutex_lock(&context->context_mgr_node_lock);
ctx_mgr_node = context->binder_context_mgr_node; // 是否为 ServiceManager 的 引用对象
if (ctx_mgr_node)
ret = binder_inc_ref_for_node(
proc, ctx_mgr_node,
strong, NULL, &rdata);
mutex_unlock(&context->context_mgr_node_lock);
}
if (ret)
ret = binder_update_ref_for_handle(
proc, target, increment, strong,
&rdata);
break;
}
}
}
}
- binder_inc_ref_for_node
/**
* binder_inc_ref_for_node() - increment the ref for given proc/node
* @proc: proc containing the ref
* @node: target node
* @strong: true=strong reference, false=weak reference
* @target_list: worklist to use if node is incremented
* @rdata: the id/refcount data for the ref
*
* Given a proc and node, increment the ref. Create the ref if it
* doesn't already exist
*
* Return: 0 if successful, else errno
*/
static int binder_inc_ref_for_node(struct binder_proc *proc,
struct binder_node *node,
bool strong,
struct list_head *target_list,
struct binder_ref_data *rdata)
{
struct binder_ref *ref;
struct binder_ref *new_ref = NULL;
int ret = 0;
binder_proc_lock(proc);
ref = binder_get_ref_for_node_olocked(proc, node, NULL);
if (!ref) {
binder_proc_unlock(proc);
new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
if (!new_ref)
return -ENOMEM;
binder_proc_lock(proc);
ref = binder_get_ref_for_node_olocked(proc, node, new_ref);
}
ret = binder_inc_ref_olocked(ref, strong, target_list);
*rdata = ref->data;
binder_proc_unlock(proc);
if (new_ref && ref != new_ref)
/*
* Another thread created the ref first so
* free the one we allocated
*/
kfree(new_ref);
return ret;
}
- binder_get_ref_for_node_olocked: 获取 binder_node 对应的 binder_ref
/**
* binder_get_ref_for_node_olocked() - get the ref associated with given node
* @proc: binder_proc that owns the ref
* @node: binder_node of target
* @new_ref: newly allocated binder_ref to be initialized or %NULL
*
* Look up the ref for the given node and return it if it exists
*
* If it doesn't exist and the caller provides a newly allocated
* ref, initialize the fields of the newly allocated ref and insert
* into the given proc rb_trees and node refs list.
*
* Return: the ref for node. It is possible that another thread
* allocated/initialized the ref first in which case the
* returned ref would be different than the passed-in
* new_ref. new_ref must be kfree'd by the caller in
* this case.
*/
static struct binder_ref *binder_get_ref_for_node_olocked(
struct binder_proc *proc,
struct binder_node *node,
struct binder_ref *new_ref)
{
struct binder_context *context = proc->context;
struct rb_node **p = &proc->refs_by_node.rb_node;
struct rb_node *parent = NULL;
struct binder_ref *ref;
struct rb_node *n;
// 遍历 binder_proc->refs_by_node 的红黑树, 关键字是 binder_node 的地址.查找引用该 binder_node 的 binder_ref
while (*p) {
parent = *p;
ref = rb_entry(parent, struct binder_ref, rb_node_node);
if (node < ref->node)
p = &(*p)->rb_left;
else if (node > ref->node)
p = &(*p)->rb_right;
else
return ref;
}
if (!new_ref)
return NULL;
binder_stats_created(BINDER_STAT_REF);
/*
* new_ref 的初始化
*/
new_ref->data.debug_id = atomic_inc_return(&binder_last_id);
new_ref->proc = proc;
new_ref->node = node;
rb_link_node(&new_ref->rb_node_node, parent, p);
rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
// 如果是 ServiceManager 的 binder_ref, desc = 0, 否则 desc = 1
new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1;
// 根据已存在的 desc, 重新设置 new_ref 的 desc
for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
ref = rb_entry(n, struct binder_ref, rb_node_desc);
if (ref->data.desc > new_ref->data.desc)
break;
new_ref->data.desc = ref->data.desc + 1; // rfs_by_desc 根据 desc 的大小排序的红黑树.
}
// 插入 binder_ref 的 rfs_by_desc 的 红黑树中.
p = &proc->refs_by_desc.rb_node;
while (*p) {
parent = *p;
ref = rb_entry(parent, struct binder_ref, rb_node_desc);
if (new_ref->data.desc < ref->data.desc)
p = &(*p)->rb_left;
else if (new_ref->data.desc > ref->data.desc)
p = &(*p)->rb_right;
else
BUG();
}
rb_link_node(&new_ref->rb_node_desc, parent, p);
rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc);
binder_node_lock(node);
// 将 new_ref 插入到 它所引用的 binder_node 的 hlist 中.
hlist_add_head(&new_ref->node_entry, &node->refs);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d new ref %d desc %d for node %d\n",
proc->pid, new_ref->data.debug_id, new_ref->data.desc,
node->debug_id);
binder_node_unlock(node);
return new_ref;
}
/**
* binder_inc_ref_olocked() - increment the ref for given handle
* @ref: ref to be incremented
* @strong: if true, strong increment, else weak
* @target_list: list to queue node work on
*
* Increment the ref. @ref->proc->outer_lock must be held on entry
*
* Return: 0, if successful, else errno
*/
/*
* target_list: 表示 增加了 binder_ref 后,需要增加 它所引用的 binder_node 或 BBinder 的引用计数.
*/
static int binder_inc_ref_olocked(struct binder_ref *ref, int strong,
struct list_head *target_list)
{
int ret;
if (strong) {
/*
* 1. 强引用计数:
* 2. ref->data.strong == 0
* 3. 说明此时 binder_ref 对应的 binder_node 的 internal_strong_refs 需要 +1
*/
if (ref->data.strong == 0) {
ret = binder_inc_node(ref->node, 1, 1, target_list);
if (ret)
return ret;
}
ref->data.strong++;
} else {
if (ref->data.weak == 0) {
ret = binder_inc_node(ref->node, 0, 1, target_list);
if (ret)
return ret;
}
ref->data.weak++;
}
return 0;
}
- binder_update_ref_for_handle
/**
* binder_update_ref_for_handle() - inc/dec the ref for given handle
* @proc: proc containing the ref
* @desc: the handle associated with the ref
* @increment: true=inc reference, false=dec reference
* @strong: true=strong reference, false=weak reference
* @rdata: the id/refcount data for the ref
*
* Given a proc and ref handle, increment or decrement the ref
* according to "increment" arg.
*
* Return: 0 if successful, else errno
*/
static int binder_update_ref_for_handle(struct binder_proc *proc,
uint32_t desc, bool increment, bool strong,
struct binder_ref_data *rdata)
{
int ret = 0;
struct binder_ref *ref;
bool delete_ref = false;
binder_proc_lock(proc);
ref = binder_get_ref_olocked(proc, desc, strong);
if (increment)
ret = binder_inc_ref_olocked(ref, strong, NULL);
else
delete_ref = binder_dec_ref_olocked(ref, strong);
if (rdata)
*rdata = ref->data;
binder_proc_unlock(proc);
if (delete_ref)
binder_free_ref(ref); // 释放 binder_ref,如果 binder_ref->node 不为 NULL,释放 binder_ref->node
return ret;
err_no_ref:
binder_proc_unlock(proc);
return ret;
}
/**
* binder_dec_ref() - dec the ref for given handle
* @ref: ref to be decremented
* @strong: if true, strong decrement, else weak
*
* Decrement the ref.
*
* Return: true if ref is cleaned up and ready to be freed
*/
static bool binder_dec_ref_olocked(struct binder_ref *ref, int strong)
{
if (strong) {
ref->data.strong--;
if (ref->data.strong == 0)
binder_dec_node(ref->node, strong, 1); // 如果 强引用计数==0, 那么减少 binder_ref 所引用的 binder_node 的 internal 引用计数.
} else {
ref->data.weak--;
}
if (ref->data.strong == 0 && ref->data.weak == 0) {
binder_cleanup_ref_olocked(ref);
return true;
}
return false;
}
static void binder_cleanup_ref_olocked(struct binder_ref *ref)
{
bool delete_node = false;
rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc);
rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node);
binder_node_inner_lock(ref->node);
if (ref->data.strong)
binder_dec_node_nilocked(ref->node, 1, 1);
hlist_del(&ref->node_entry);
// 减少 binder_ref 所引用的 binder_node 的 strong | internal 引用计数,然后确认是否删除 binder_node
delete_node = binder_dec_node_nilocked(ref->node, 0, 1);
binder_node_inner_unlock(ref->node);
/*
* Clear ref->node unless we want the caller to free the node
*/
if (!delete_node) {
/*
* The caller uses ref->node to determine
* whether the node needs to be freed. Clear
* it since the node is still alive.
*/
ref->node = NULL;
}
// 删除 binder_ref 的死亡通知
if (ref->death) {
binder_dequeue_work(ref->proc, &ref->death->work);
binder_stats_deleted(BINDER_STAT_DEATH);
}
binder_stats_deleted(BINDER_STAT_REF);
}
BpBinder 生命周期
- BpBinder 一方面会被 Client 进程中的其他对象引用,另一方面也会引用 binder_ref.
- Client 通过 BC_ACQUIRE, BC_INCREFS, BC_RELEASE, BC_DECREFS 来引用 binder_ref
- BpBinder 和 binder_ref 通过 句柄值 desc 进行关联.Client 通过 desc 来维护所有的 BpBinder.
class ProcessState {
struct handle_entry {
IBinder* binder;
RefBase::weakref_type* refs;
};
handle_entry* lookupHandleLocked(int32_t handle);
Vector<handle_entry>mHandleToObject;
};
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = NULL;
e.refs = NULL;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return NULL;
}
return &mHandleToObject.editItemAt(handle);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) { // ServiceManager
// Special case for context manager...
// The context manager is the only object for which we create
// a BpBinder proxy without already holding a reference.
// Perform a dummy transaction to ensure the context manager
// is registered before we create the first local reference
// to it (which will occur when creating the BpBinder).
// If a local reference is created for the BpBinder when the
// context manager is not present, the driver will fail to
// provide a reference to the context manager, but the
// driver API does not return status.
//
// Note that this is not race-free if the context manager
// dies while this code runs.
//
// TODO: add a driver API to wait for context manager, or
// stop special casing handle 0 for context manager and add
// a driver API to get a handle to the context manager with
// proper reference counting.
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
void IPCThreadState::incStrongHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_ACQUIRE);
mOut.writeInt32(handle);
}
void IPCThreadState::decStrongHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
mOut.writeInt32(BC_RELEASE);
mOut.writeInt32(handle);
}
void IPCThreadState::incWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_INCREFS);
mOut.writeInt32(handle);
}
void IPCThreadState::decWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_DECREFS);
mOut.writeInt32(handle);
}
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle);
}
BpBinder::~BpBinder()
{
ALOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
IPCThreadState* ipc = IPCThreadState::self();
mLock.lock();
Vector<Obituary>* obits = mObituaries;
if(obits != NULL) {
if (ipc) ipc->clearDeathNotification(mHandle, this);
mObituaries = NULL;
}
mLock.unlock();
if (obits != NULL) {
// XXX Should we tell any remaining DeathRecipient
// objects that the last strong ref has gone away, so they
// are no longer linked?
delete obits;
}
if (ipc) {
ipc->expungeHandle(mHandle, this);
ipc->decWeakHandle(mHandle);
}
}
-
强引用计数
为了减少 Client 进程 和 Driver 交互开销,只有第一个被强指针引用时,Client进程才会请求Driver增加 binder_ref 的引用计数.反之.
当一个对象第一次被强指针引用时,它的成员函数 onFirstRef 会被调用;当一个对象不再被强指针引用时,它的成员函数 onLastStrongRef 就会被调用.
void BpBinder::onFirstRef()
{
ALOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
IPCThreadState* ipc = IPCThreadState::self();
if (ipc) ipc->incStrongHandle(mHandle);
}
void BpBinder::onLastStrongRef(const void* /*id*/)
{
ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
IF_ALOGV() {
printRefs();
}
IPCThreadState* ipc = IPCThreadState::self();
if (ipc) ipc->decStrongHandle(mHandle);
}