Binder 對象引用計數(shù)技術(shù)


它們的交互過程可以分為5個步驟,如下所示:
(1) 運行在 Client 進(jìn)程的 BpBinder 通過 Binder Drvier 向運行在 Server 進(jìn)程的 BBinder 發(fā)送通信請求,Binder Driver 根據(jù) Client 進(jìn)程的 BpBinder 的句柄值找到對應(yīng)的 binder_ref
(2) Binder Dirver 根據(jù)找到的 binder_ref 找到 binder_node, 并創(chuàng)建 binder_transaction(事務(wù)) 來描述此次通信過程.
(3) Binder Driver 根據(jù) binder_node 找到 Server 進(jìn)程的 BBinder, 將 Client 進(jìn)程傳遞的通信數(shù)據(jù)發(fā)送給它.
(4) BBinder 處理完 Client 的請求后,將通信結(jié)果返回給 Binder Driver, Binder Driver 找到之前創(chuàng)建的 binder_transaction.
(5) Binder Driver 根據(jù)前面找到的事務(wù)的相關(guān)屬性來找到發(fā)出進(jìn)程通信請求的 Client 進(jìn)程,并且通知 Client 進(jìn)程將通信結(jié)果返回給對應(yīng)的 BpBinder 來處理.
從上述過程來看, BpBinder 依賴于 binder_ref, 而 BBinder 依賴于 binder_node.所以必須采用一種技術(shù)保證不能銷毀一個還被依賴著的對象.
BBinder 的生命周期
BBinder 可能會被 Server 進(jìn)程的其他對象引用,也可能被 Binder Driver 的 binder_node 引用.
- 被 Server 進(jìn)程的其他對象引用:
RefBase ---- 通過智能指針控制其生命周期. - 被 binder_node 引用
binder_node 處于 Kernel Space,無法使用 智能指針.
需要重新約定一套規(guī)則來維護(hù)它們的引用計數(shù).
- BR_INCREFS
- BR_ACQUIRE
- BR_DECREFS
- BR_RELEASE
維護(hù) Service 組件 即 BBinder 的生命周期.
Binder Driver 要和目標(biāo)進(jìn)程或線程通信時,會把一個工作項加入到它的 todo list 中.目標(biāo)進(jìn)程或線程會不斷的調(diào)用 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 組件內(nèi)部的一個引用計數(shù)對象(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 (默認(rèn)為1):
* 如果 Driver 已經(jīng)請求了 Server 進(jìn)程的 BBinder 為 binder_node 增加了引用計數(shù),
* 那么 Driver 就會將 binder_node 的 has_strong_ref 和 has_weak_ref 設(shè)置為1; 否則為0.
*/
has_strong_ref = node->has_strong_ref;
has_weak_ref = node->has_weak_ref;
/**
* 引用技術(shù)的說明:
* 1. internal_strong_refs, local_strong_refs 描述 binder_node 的強(qiáng)引用計數(shù)。
* 2. local_weak_refs 描述 binder_node 的弱引用計數(shù)。
* 3. 一個 binder_node 請求 Service 執(zhí)行某一操作時,會增加該 Service 的 strong refs 或 weak refs;
* 相應(yīng)的,binder_node 會將成員變量 has_strong_ref 或 has_weak_ref 的值設(shè)置為1.
* 4. 當(dāng)一個 Service 組件完成一個 binder_node 所請求的操作后,
* binder_node 就會請求減少該 Service 的 strong refs 或 weak refs。
* 5. binder_node 在請求一個 Service 增加或減少引用計數(shù)的過程中,
* 會將成員變量 pending_strong_ref 或 pending_weak_ref 的值設(shè)置為1;
* 當(dāng) Service 增加或減少了引用計數(shù)后,binder_node 就會將這兩個成員變量的值設(shè)置為0.
* 6. 當(dāng) binder_node 的引用計數(shù)由0->1, 或由1->0時,Binder Driver 會請求相應(yīng)的 Service 增加或減少其引用計數(shù)。
* 這時候Binder Driver會將修改引用計數(shù)的操作封裝成一個類型為 binder_node 的工作項,
* 即將 binder_node 的 work 的值設(shè)置為 BINDER_WORK_NODE,并將它添加到相應(yīng)的進(jìn)程的 todo list 中,等待處理。
*/
/*
* 這里有一個思想上的轉(zhuǎn)換:
* has_weak_ref, local_weak_refs, has_strong_ref, local_strong_refs
* 描述的是 binder_node 的引用計數(shù).而不是 Service 的引用計數(shù).
* 只是 binder_node 和 Service 相關(guān),當(dāng) binder_node 引用計數(shù)變化時,需要通知 Service 修改引用計數(shù).
*/
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 已經(jīng)引用了一個 BBinder,但是沒有增加它的弱引用計數(shù),通過 BR_INCREFS 增加弱引用計數(shù).
*/
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 已經(jīng)引用了一個 BBinder,但是還沒有增加它的強(qiáng)引用計數(shù),通過 BR_ACQUIRE 增加 強(qiáng)引用計數(shù).
*/
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, 但是還沒有減少強(qiáng)引用計數(shù),通過 BR_RELEASE 減少強(qiáng)引用計數(shù).
*/
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,但是還沒有減少它的弱引用計數(shù),通過 BR_DECREFS 減少弱引用計數(shù).
*/
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()); // 增加 強(qiáng)引用計數(shù).
mOut.writeInt32(BC_ACQUIRE_DONE); // 告訴 Driver , 增加強(qiáng)引用計數(shù) 操作 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()); // 增加 弱引用計數(shù)
mOut.writeInt32(BC_INCREFS_DONE); // 發(fā)送 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;
}
}
/*
* 減少引用計數(shù)無返回,且不著急處理.
* 增加引用計數(shù)有返回,且必須馬上處理,因為如果不處理,很有可能對象被釋放.
*/
binder_node 生命周期
binder_node 由 Driver 創(chuàng)建,并且被 binder_ref 所引用.
當(dāng) Client 進(jìn)程通過 ServiceManager 獲取 Service 組件的代理對象接口時,Drvier就會找到該 Service 組件的 binder_node, 然后再創(chuàng)建一個 binder_ref 來引用它.這是就需要增加 binder_node 的引用計數(shù).相反,當(dāng) Client 不再引用一個 Service 組件時,就會請求 Driver 釋放 binder_ref,這是就需要減少 binder_node 的引用計數(shù).
- 增加引用計數(shù): 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 對應(yīng)于 Server, 那么它的 local 的意思就是 Server 進(jìn)程內(nèi); 那么 internal 就是 描述 binder_ref 對 binder_node 的引用,可以認(rèn)為是 kernel internal.
local_weak_refs, local_strong_refs 描述 binder_node 和 BBinder 之間的引用關(guān)系.如 Drvier 請求 Server 進(jìn)程指向某一操作,就會增加 BBinder 對應(yīng)的 binder_node 的 local 引用計數(shù),避免 binder_node 被過早的銷毀.
Client 進(jìn)程通過 binder_ref 來引用 binder_node 時, Driver 就會增加 binder_node 的 internal 引用計數(shù),防止 binder_node 的過早銷毀.
-
為什么只有 internal_strong_refs ,沒有 internal_weak_refs?
因為 binder_node 的成員變量 refs 隱含了 internal_weak_refs.
/*
* strong : 是否是強(qiáng)引用計數(shù).
* internal: 內(nèi)部引用計數(shù)還是外部引用計數(shù).
* target_list: 指向目標(biāo)進(jìn)程或目標(biāo)線程的 todo list.如果非NULL,就表示增加了 binder_node 引用計數(shù)后,需要增加它所引用的 BBinder 引用計數(shù).
*/
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 執(zhí)行某一操作時,會增加該 Service 的 strong refs 或 weak refs;
* 相應(yīng)的,binder_node 會將成員變量 has_strong_ref 或 has_weak_ref 的值設(shè)置為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;
}
- 減少引用計數(shù): 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 的引用計數(shù).
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; // 是否為 強(qiáng)引用計數(shù)
bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE; // 是否為 增加引用計數(shù)
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 對應(yīng)的 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 的紅黑樹, 關(guān)鍵字是 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;
// 根據(jù)已存在的 desc, 重新設(shè)置 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 根據(jù) 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 的引用計數(shù).
*/
static int binder_inc_ref_olocked(struct binder_ref *ref, int strong,
struct list_head *target_list)
{
int ret;
if (strong) {
/*
* 1. 強(qiáng)引用計數(shù):
* 2. ref->data.strong == 0
* 3. 說明此時 binder_ref 對應(yīng)的 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); // 如果 強(qiáng)引用計數(shù)==0, 那么減少 binder_ref 所引用的 binder_node 的 internal 引用計數(shù).
} 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 引用計數(shù),然后確認(rèn)是否刪除 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 進(jìn)程中的其他對象引用,另一方面也會引用 binder_ref.
- Client 通過 BC_ACQUIRE, BC_INCREFS, BC_RELEASE, BC_DECREFS 來引用 binder_ref
- BpBinder 和 binder_ref 通過 句柄值 desc 進(jìn)行關(guān)聯(lián).Client 通過 desc 來維護(hù)所有的 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);
}
}
-
強(qiáng)引用計數(shù)
為了減少 Client 進(jìn)程 和 Driver 交互開銷,只有第一個被強(qiáng)指針引用時,Client進(jìn)程才會請求Driver增加 binder_ref 的引用計數(shù).反之.
當(dāng)一個對象第一次被強(qiáng)指針引用時,它的成員函數(shù) onFirstRef 會被調(diào)用;當(dāng)一個對象不再被強(qiáng)指針引用時,它的成員函數(shù) onLastStrongRef 就會被調(diào)用.
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);
}