背景
这是Binder系列的最后一篇了。让我们来聊聊Binder的死亡代理是怎么处理。我们之前只是聊了Binder的启动和传输数据,还差最后一个模块就补上整个缺口了。
如果遇到问题:https://www.jianshu.com/p/e22005e5c411
正文
AMS 为app注册死亡接受通知
还记得在第一篇的调用AppThread在初始化的时候会初始化,调用attachApplicationLocked方法,为AppThread绑定一个ApplicationTread的binder对象。实际上在这个过程是携带ApplicationTread对象,通过Binder通信到了ActivityManagerService(简称AMS),并让AMS远程绑定App的行为。
文件:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
....
final String processName = app.processName;
try {
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
startProcessLocked(app, "link fail", processName);
return false;
}
....
return true;
}
这里有一个新的类AppDeathRecipient,让我们看看究竟
private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp;
final int mPid;
final IApplicationThread mAppThread;
AppDeathRecipient(ProcessRecord app, int pid,
IApplicationThread thread) {
mApp = app;
mPid = pid;
mAppThread = thread;
}
@Override
public void binderDied() {
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true);
}
}
}
文件:/frameworks/base/core/java/android/os/IBinder.java
可以看到这个AppDeathRecipient是继承于IBinder.DeathRecipient。
public interface DeathRecipient {
public void binderDied();
}
这个接口意味着当binder死亡回调之后的行为。
细节补充
文件:/frameworks/native/libs/binder/Parcel.cpp
那么,我们趁热打铁,接着上一章,我们把BBinder本地binder传输到binder中。我们必定会经过binder驱动的binder_transaction这个步骤:
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
....
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc;
...
} break;
可以看到的是,此时我们会把在Parcel中设置好的BINDER_TYPE_BINDER,转化为BINDER_TYPE_HANDLE一个handle的类型。因此,我们可以看到此时当AMS执行attachApplicationLocked方法的时候,必定会从Parcel读取里面的binder对象(readStrongBinder方法)。我们看看Parcel的方法。
文件:
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
return unflatten_binder(ProcessState::self(), *this, val);
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, wp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_WEAK_BINDER:
if (flat->binder != 0) {
out->set_object_and_refs(
reinterpret_cast<IBinder*>(flat->cookie),
reinterpret_cast<RefBase::weakref_type*>(flat->binder));
} else {
*out = NULL;
}
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE:
*out = proc->getWeakProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
}
}
return BAD_TYPE;
}
因此此时我们会根据传下来的type,当时BINDER_TYPE_HANDLE的type时候,就转型为BpBinder,否则代表是本地对象在本地读取直接取出cookie设置进数据中。
因此我们可以推导出,此时IApplicationThread thread是一个BpBinder对象,对应着Java层的BinderProxy对象。
linkToDeath
文件:/frameworks/base/core/java/android/os/Binder.java
public class Binder implements IBinder {
public void linkToDeath(DeathRecipient recipient, int flags) {
}
public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
return true;
}
}
final class BinderProxy implements IBinder {
public native void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException;
public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
}
把整个Binder缩减下来就能知道,实际上Binder本身虽然存在这两个方法,但是由于是本地的类,因此应该由本地处理其死亡,而Proxy身为代理类会通过这种手段告诉binder他要死亡。是否是这样的,我们看看BinderProxy源码就知道了。
native层linkToDeath
文件:/frameworks/base/core/jni/android_util_Binder.cpp
static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,
jobject recipient, jint flags) // throws RemoteException
{
...
BinderProxyNativeData *nd = getBPNativeData(env, obj);
IBinder* target = nd->mObject.get();
if (!target->localBinder()) {
DeathRecipientList* list = nd->mOrgue.get();
sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient, list);
status_t err = target->linkToDeath(jdr, NULL, flags);
if (err != NO_ERROR) {
jdr->clearReference();
signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/);
}
}
}
实际上这里做的事情很简单,就是去除BinderProxy中BinderProxyNativeData 中的JavaDeathRecipient对象,调用BpBinder的linkToDeath方法。
BpBinder的linkToDeath
文件:/frameworks/native/libs/binder/BpBinder.cpp
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
Obituary ob;
ob.recipient = recipient;
ob.cookie = cookie;
ob.flags = flags;
LOG_ALWAYS_FATAL_IF(recipient == NULL,
"linkToDeath(): recipient must be non-NULL");
{
AutoMutex _l(mLock);
if (!mObitsSent) {
if (!mObituaries) {
mObituaries = new Vector<Obituary>;
if (!mObituaries) {
return NO_MEMORY;
}
getWeakRefs()->incWeak(this);
IPCThreadState* self = IPCThreadState::self();
self->requestDeathNotification(mHandle, this);
self->flushCommands();
}
ssize_t res = mObituaries->add(ob);
return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
}
}
return DEAD_OBJECT;
}
- 调用IPCThreadState的requestDeathNotification方法 写入死亡通知方法
- 调用IPCThreadState的flushCommands 发送死亡通知
- 把DeathRecipient,cookie(此时为NULL),flags添加到mObituaries这个Vector向量中。
requestDeathNotification与flushCommands
status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writePointer((uintptr_t)proxy);
return NO_ERROR;
}
void IPCThreadState::flushCommands()
{
if (mProcess->mDriverFD <= 0)
return;
talkWithDriver(false);
// The flush could have caused post-write refcount decrements to have
// been executed, which in turn could result in BC_RELEASE/BC_DECREFS
// being queued in mOut. So flush again, if we need to.
if (mOut.dataSize() > 0) {
talkWithDriver(false);
}
...
}
从上面两个代码段我们可以知道此时IPCThread往binder驱动中写入BC_REQUEST_DEATH_NOTIFICATION命令,并且写入handle(代表BpBinder的句柄),proxy(代表当前BpBinder指针),再通过ioctl传输到Binder驱动
Binder驱动binder_transaction
冗余的东西不在聊,我们直接看看这个方法的分支片段。
//处理死亡通知
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
uint32_t target;
binder_uintptr_t cookie;
struct binder_ref *ref;
struct binder_ref_death *death;
//设置从用户空间下来的数据
if (get_user(target, (uint32_t __user *)ptr))//handle 句柄
return -EFAULT;
ptr += sizeof(uint32_t);
if (get_user(cookie, (binder_uintptr_t __user *)ptr))//BpBinder
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
ref = binder_get_ref(proc, target);
...
//处理死亡通知
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
...
death = kzalloc(sizeof(*death), GFP_KERNEL);
...
binder_stats_created(BINDER_STAT_DEATH);
INIT_LIST_HEAD(&death->work.entry);
death->cookie = cookie;
ref->death = death;
if (ref->node->proc == NULL) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&ref->death->work.entry, &thread->todo);
} else {
list_add_tail(&ref->death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
}
} else {
...
}
} break;
- 1.首先先通过句柄获取远程端对应的binder引用
- 2.创建并且初始化一个binder_death对象(包含死亡链表以及BpBinder),并且把对应的binder引用设置上这个对象。接着初始化好death->work.entry这个散列链表的头。
还有一种特殊情况需要处理,当目标进程已经死亡,设置标记为BINDER_WORK_DEAD_BINDER。换到这个场景就是指还没来及删除binder驱动下方的binder对象,远端进程的App死亡了。
这里分为两种情况讨论:
binder_looper的标志位打开BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED这两个时候,此时会放到当前进程的binder_thread 的todo中。
binder_looper的标志位没打开BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED这两个时候,则直接加到当前进程的进程todo(空闲工作列表中)中,并且立刻唤起当前进程(当前情景是指AMS),详情见:对端(AMS)被唤醒,读取数据 小节。
好像到这里就没有事情要做了。实际上确实如此,这个命令仅仅标记了要死亡的binder引用是哪个。并没有做更多的事情,但是却让java层的回调跟住了binder引用。
当目标死亡时候(App进程死亡)
当App进程死亡的时候,才是真正的开始开始资源回收,因此我们能对应着看看看当App进程死亡,开始回收资源时候,把binder驱动文件close的场景。
这里就不继续跟踪linux内核到binder驱动。
文件:/drivers/staging/android/binder.c
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
我们能看到的时候,当资源关闭就会调用binder_release方法。
static int binder_release(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc = filp->private_data;
debugfs_remove(proc->debugfs_entry);
binder_defer_work(proc, BINDER_DEFERRED_RELEASE);
return 0;
}
static DECLARE_WORK(binder_deferred_work, binder_deferred_func);
static void
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer)
{
mutex_lock(&binder_deferred_lock);
proc->deferred_work |= defer;
if (hlist_unhashed(&proc->deferred_work_node)) {
hlist_add_head(&proc->deferred_work_node,
&binder_deferred_list);
queue_work(binder_deferred_workqueue, &binder_deferred_work);
}
mutex_unlock(&binder_deferred_lock);
}
可以看到的是,这里的处理当执行多个close资源回收的方法,此时会依次进入到binder_deferred_workqueue这个哈希链表(这个数据结构和hashmap很像,之后会在算法部分解析以下)。调用的是binder_deferred_work指向的binder_deferred_func方法。
static void binder_deferred_func(struct work_struct *work)
{
struct binder_proc *proc;
struct files_struct *files;
int defer;
do {
binder_lock(__func__);
mutex_lock(&binder_deferred_lock);
if (!hlist_empty(&binder_deferred_list)) {
proc = hlist_entry(binder_deferred_list.first,
struct binder_proc, deferred_work_node);
hlist_del_init(&proc->deferred_work_node);
defer = proc->deferred_work;
proc->deferred_work = 0;
} else {
proc = NULL;
defer = 0;
}
mutex_unlock(&binder_deferred_lock);
files = NULL;
if (defer & BINDER_DEFERRED_PUT_FILES) {
files = proc->files;
if (files)
proc->files = NULL;
}
if (defer & BINDER_DEFERRED_FLUSH)
binder_deferred_flush(proc);
if (defer & BINDER_DEFERRED_RELEASE)
binder_deferred_release(proc); /* frees proc */
binder_unlock(__func__);
if (files)
put_files_struct(files);
} while (proc);
}
此时我们可以看到,这里进入到了一个循环。不断的取出binder_deferred_list中删除任务,直到这个队列中已经没有任何东西,则把binder_proc指向null,跳出循环。值得注意的是,此时传进来的标志位为BINDER_DEFERRED_RELEASE,因此我们会执行核心方法binder_deferred_release。
App进程清除binder驱动中的数据(binder_deferred_release)
真正开始删除binder驱动中依附于binder_proc的数据将会在binder_deferred_release中清除
static void binder_deferred_release(struct binder_proc *proc)
{
struct binder_transaction *t;
struct rb_node *n;
int threads, nodes, incoming_refs, outgoing_refs, buffers,
active_transactions, page_count;
BUG_ON(proc->vma);
BUG_ON(proc->files);
hlist_del(&proc->proc_node);
// 当前进程为binder_context_mgr_node清除
if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) {
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"%s: %d context_mgr_node gone\n",
__func__, proc->pid);
binder_context_mgr_node = NULL;
}
//释放binder_proc的binder_thread中数据
threads = 0;
active_transactions = 0;
while ((n = rb_first(&proc->threads))) {
struct binder_thread *thread;
thread = rb_entry(n, struct binder_thread, rb_node);
threads++;
active_transactions += binder_free_thread(proc, thread);
}
//释放binder_proc的nodes中数据
nodes = 0;
incoming_refs = 0;
while ((n = rb_first(&proc->nodes))) {
struct binder_node *node;
node = rb_entry(n, struct binder_node, rb_node);
nodes++;
rb_erase(&node->rb_node, &proc->nodes);
incoming_refs = binder_node_release(node, incoming_refs);
}
//释放binder_proc的refs_by_desc中数据
outgoing_refs = 0;
while ((n = rb_first(&proc->refs_by_desc))) {
struct binder_ref *ref;
ref = rb_entry(n, struct binder_ref, rb_node_desc);
outgoing_refs++;
binder_delete_ref(ref);
}
binder_release_work(&proc->todo);
binder_release_work(&proc->delivered_death);
//释放正在使用的allocated_buffers数据
buffers = 0;
while ((n = rb_first(&proc->allocated_buffers))) {
struct binder_buffer *buffer;
buffer = rb_entry(n, struct binder_buffer, rb_node);
t = buffer->transaction;
if (t) {
t->buffer = NULL;
buffer->transaction = NULL;
pr_err("release proc %d, transaction %d, not freed\n",
proc->pid, t->debug_id);
/*BUG();*/
}
binder_free_buf(proc, buffer);
buffers++;
}
binder_stats_deleted(BINDER_STAT_PROC);
//释放映射地址
page_count = 0;
if (proc->pages) {
int i;
for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) {
void *page_addr;
if (!proc->pages[i])
continue;
page_addr = proc->buffer + i * PAGE_SIZE;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%s: %d: page %d at %p not freed\n",
__func__, proc->pid, i, page_addr);
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
__free_page(proc->pages[i]);
page_count++;
}
kfree(proc->pages);
vfree(proc->buffer);
}
put_task_struct(proc->tsk);
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n",
__func__, proc->pid, threads, nodes, incoming_refs,
outgoing_refs, active_transactions, buffers, page_count);
//释放binder_proc
kfree(proc);
}
释放数据分为7个步骤。
1.加入当前是binder_context_mgr_node对应的进程则清除这个全局binder_node (binder实体对象)。这个对象就是指service_manager进程对应的binder_node
2.释放binder_proc的binder_thread链表中数据。这个链表管理所有的binder_thread,这个binder对象会为每一个新的进程想要通过ioctl和新的binder进程通信,都会新建一个。当然使用poll的时候也会新建一个。而这在binder_thread中又有todo 工作链表需要清理,因此会调用binder_free_thread清理里面的工作。这里选择的方案是,把所有的binder工作任务一一都传递给各个需要这个工作的对端,这样就相当于清理了工作链表和依赖栈。
3.释放binder_proc的nodes链表中数据。这个链表管理着所有经过binder_proc当前进程通过传输的binder对象的实体,因此会也需要清理。
4.释放binder_proc的refs_by_desc中数据。这个是代表着binder_proc所有实体的引用,我们会通过引用去找到对应的实体,因此我们需要先清理binder_node实体,再清理引用。
5.释放正在使用的allocated_buffers数据。因为在清理binder_thread中已经处理了对应的工作,但是一般allocated_buffer是等到对端回应之后再清除,此时,不会在等待而是自己主动清除。
- 释放binder_proc的todo列表(里面是binder_work),这个是等待binder_thread处理完才处理的工作列表。还有delivered_death
6.释放映射地址,通过mmap映射的共享地址,此时需要释放回去。
7.释放binder_proc 以上6个步骤读释放完数据,说binder_proc已经没有任何数据了,可以直接释放binder_proc数据。
释放binder_proc的binder_thread链表
作为事务传递为核心的binder驱动,那么binder_free_thread这个方法就显得尤为重要。
static int binder_free_thread(struct binder_proc *proc,
struct binder_thread *thread)
{
struct binder_transaction *t;
struct binder_transaction *send_reply = NULL;
int active_transactions = 0;
//删除节点
rb_erase(&thread->rb_node, &proc->threads);
//获取事务栈,找到目标
t = thread->transaction_stack;
if (t && t->to_thread == thread)
send_reply = t;
while (t) {
active_transactions++;
if (t->to_thread == thread) {
t->to_proc = NULL;
t->to_thread = NULL;
if (t->buffer) {
t->buffer->transaction = NULL;
t->buffer = NULL;
}
t = t->to_parent;
} else if (t->from == thread) {
t->from = NULL;
t = t->from_parent;
} else
BUG();
}
//需要应答的,则发送BR_DEAD_REPLY上当用户空间
if (send_reply)
binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
//清除todo列表
binder_release_work(&thread->todo);
//释放thread
kfree(thread);
binder_stats_deleted(BINDER_STAT_THREAD);
return active_transactions;
}
- 1.先从binder_proc的擦除threads擦除红黑树根部的binder_thread.
- 2.从事务依赖栈寻找哪些事务想要发送当前进程。一旦发现想要发现要发送当前这个即将关闭的进程的任务,就代替这些任务并且直接发送BR_DEAD_REPLY命令。
- 3.处理好这些任务之后,再去使用binder_release_work清空todo列表
- 4.释放binder_thread结构体。
那么值得关注的核心逻辑有两个:
- 1.binder_send_failed_reply 发送死亡命令
- 2.binder_release_work释放todo 链表
binder_send_failed_reply 发送死亡命令
static void binder_send_failed_reply(struct binder_transaction *t,
uint32_t error_code)
{
struct binder_thread *target_thread;
struct binder_transaction *next;
BUG_ON(t->flags & TF_ONE_WAY);
while (1) {
target_thread = t->from;
if (target_thread) {
if (target_thread->return_error != BR_OK &&
target_thread->return_error2 == BR_OK) {
target_thread->return_error2 =
target_thread->return_error;
target_thread->return_error = BR_OK;
}
if (target_thread->return_error == BR_OK) {
....
binder_pop_transaction(target_thread, t);
target_thread->return_error = error_code;
wake_up_interruptible(&target_thread->wait);
} else {
....
}
return;
}
next = t->from_parent;
...
binder_pop_transaction(target_thread, t);
if (next == NULL) {
...
return;
}
t = next;
...
}
}
实际上,这里的逻辑和之前binder_transaction很相似。不同的是,这里会一直寻找事务栈中的binder_transaction所有的事务,换新正在阻塞的对端进程,并且弹出。在这里表现当App进程死亡之后,所有的往其他进程通信的事务,全部弹出,并且唤醒(binder_thread状态正常为BR_OK),把BR_DEAD_REPLY命令发送过去设置当对端对应的binder_thread的返回码,告诉他们此时提供服务的进程已经死亡。
由此可知,实际上能够触发读取对端( AMS) 读取数据的情景有两个,一个是一开始当AMS发送注册死亡通知时候发现此时已经死亡了,则立即唤醒自己端进行读取数据。另一个就是在当前进程(App)死亡时候发送死亡相应BR_DEAD_REPLY。
此时就开始分开两个进程同时进行工作,一个App死亡继续回收资源,一个是AMS被唤醒,读取数据。我们这里继续看看App死亡之后binder_release_work方法。
binder_release_work
实际上我们从上面的binder_free_thread代码段发现,实际上是处理发送给那些需要当前进程(此时的场景是App进程)回应的消息。换句话说,就是在处理发送出去事务。
那么binder_release_work实际上就是在处理读取的命令。
static void binder_release_work(struct list_head *list)
{
struct binder_work *w;
while (!list_empty(list)) {
w = list_first_entry(list, struct binder_work, entry);
list_del_init(&w->entry);
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
struct binder_transaction *t;
t = container_of(w, struct binder_transaction, work);
if (t->buffer->target_node &&
!(t->flags & TF_ONE_WAY)) {
binder_send_failed_reply(t, BR_DEAD_REPLY);
} else {
t->buffer->transaction = NULL;
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
} break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
kfree(w);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break;
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
struct binder_ref_death *death;
death = container_of(w, struct binder_ref_death, work);
kfree(death);
binder_stats_deleted(BINDER_STAT_DEATH);
} break;
default:
break;
}
}
}
这里处理的工作有4种:
BINDER_WORK_TRANSACTION 读取todo链表,释放工作项,需要回复则模拟上面的情况,发送BR_DEAD_REPLY。
BINDER_WORK_TRANSACTION_COMPLETE 遇到这个和之前的处理一样直接释放当前的事务工作
BINDER_WORK_DEAD_BINDER_AND_CLEAR/BINDER_WORK_CLEAR_DEATH_NOTIFICATION:遇到需要清理的死亡恢复则从工作项中找到death对象直接清理。
binder_delete_ref
该方法将会删除binder引用对象
static void binder_delete_ref(struct binder_ref *ref)
{
...
rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc);
rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node);
if (ref->strong)
binder_dec_node(ref->node, 1, 1);
hlist_del(&ref->node_entry);
binder_dec_node(ref->node, 0, 1);
if (ref->death) {
...
list_del(&ref->death->work.entry);
kfree(ref->death);
binder_stats_deleted(BINDER_STAT_DEATH);
}
kfree(ref);
binder_stats_deleted(BINDER_STAT_REF);
}
从上刻面可以得知,此时需要从两个管理binder_ref的共黑树删除当前的引用,以及节点指针。最后,如果发现引用中还有死亡回调,则删除death->work.entry。
对端(AMS)被唤醒,读取数据
此时我们将会从对端AMS开始读取数据看看binder_thread_read是怎么回事
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;
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (put_user(death->cookie,
(binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
binder_stat_br(proc, thread, cmd);
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
list_del(&w->entry);
kfree(death);
binder_stats_deleted(BINDER_STAT_DEATH);
} else
list_move(&w->entry, &proc->delivered_death);
if (cmd == BR_DEAD_BINDER)
goto done; /* DEAD_BINDER notifications can cause transactions */
} break;
此时,对端AMS将会开始读取todo中的命令。这里依据App进程的binder_transaction方法中。如果当目标进程还没有死亡,此时在todo中并不会读取到BINDER_WORK_DEAD_BINDER命令。但是当App死亡之后,就存在了BINDER_WORK_DEAD_BINDER命令。
在这个分支处理了三种命令,一种是注册死亡通知的命令BINDER_WORK_DEAD_BINDER,另外两种是清空死亡通知。我们现在只关心第一种。
我们能看到的是从todo找到死亡引用对象(death_ref)把命令转化为BR_DEAD_BINDER并且把数据拷贝到用户空间。
接下来,看看在IPCThreadState中的looper,怎么获取数据。
IPCThreadState::executeCommand
文件:/frameworks/native/libs/binder/IPCThreadState.cpp
case BR_DEAD_BINDER:
{
BpBinder *proxy = (BpBinder*)mIn.readPointer();
proxy->sendObituary();
mOut.writeInt32(BC_DEAD_BINDER_DONE);
mOut.writePointer((uintptr_t)proxy);
} break;
这里分为两步:
- 1.获取到BpBinder之后调用了sendObituary方法。
- 2.继续往binder驱动写入BC_DEAD_BINDER_DONE。当该方法发送之后回删除之前注册的时候初始化的death->work.entry
BpBinder::sendObituary
void BpBinder::sendObituary()
{
mAlive = 0;
if (mObitsSent) return;
mLock.lock();
Vector<Obituary>* obits = mObituaries;
if(obits != NULL) {
IPCThreadState* self = IPCThreadState::self();
self->clearDeathNotification(mHandle, this);
self->flushCommands();
mObituaries = NULL;
}
mObitsSent = 1;
mLock.unlock();
if (obits != NULL) {
const size_t N = obits->size();
for (size_t i=0; i<N; i++) {
reportOneDeath(obits->itemAt(i));
}
delete obits;
}
}
在这里面还是分为两步:
- 1.调用clearDeathNotification,往BC_CLEAR_DEATH_NOTIFICATION发送命令。
- 2.查看vector向量中绑定了多少的死亡代理,并且逐一调用reportOneDeath方法,报告上层。
BC_CLEAR_DEATH_NOTIFICATION命令
该命令和上面的注册死亡代理相对应
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
uint32_t target;
binder_uintptr_t cookie;
struct binder_ref *ref;
struct binder_ref_death *death;
if (get_user(target, (uint32_t __user *)ptr))//BC_CLEAR_DEATH_NOTIFICATION
return -EFAULT;
ptr += sizeof(uint32_t);
if (get_user(cookie, (binder_uintptr_t __user *)ptr))//BpBinder
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
ref = binder_get_ref(proc, target);
if (ref == NULL) {
break;
}
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
....
} else {
if (ref->death == NULL) {
...
break;
}
death = ref->death;
if (death->cookie != cookie) {
...
break;
}
ref->death = NULL;
if (list_empty(&death->work.entry)) {
death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&death->work.entry, &thread->todo);
} else {
list_add_tail(&death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
} else {
...
death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR;
}
}
} break;
在这里处理和上面处理BC_REQUEST_DEATH_NOTIFICATION几乎一致,不同的是,当判断到todo没有任何工作项,则设置一个新的到队尾,唤醒当前进程继续读取数据。否则什么都不做,只是找到对应的binder引用,转化death的类型为BINDER_WORK_DEAD_BINDER_AND_CLEAR。
当前进程(AMS)继续读取数据
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
list_del(&w->entry);
kfree(death);
binder_stats_deleted(BINDER_STAT_DEATH);
}
此时的工作很简单,就是把当前进程中binder_ref的对应的death对象释放了。
因此BC_CLEAR_DEATH_NOTIFICATION命令到头来只是释放了death的内存,让其不继续回调。
reportOneDeath 反射回java层
void BpBinder::reportOneDeath(const Obituary& obit)
{
sp<DeathRecipient> recipient = obit.recipient.promote();
if (recipient == NULL) return;
recipient->binderDied(this);
}
此时获取了Obituary中之前设置的DeathRecipient结构体,在这里是指JavaDeathRecipient类。我们看看binderDied的方法。
文件:/frameworks/base/core/jni/android_util_Binder.cpp
void binderDied(const wp<IBinder>& who)
{
...
if (mObject != NULL) {
JNIEnv* env = javavm_to_jnienv(mVM);
env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mSendDeathNotice, mObject);
...
}
}
这里就能看到核心调用方法,反射调用java层BinderProxy的sendDeathNotice方法。
private static final void sendDeathNotice(DeathRecipient recipient) {
if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
try {
recipient.binderDied();
}
catch (RuntimeException exc) {
Log.w("BinderNative", "Uncaught exception from death notification",
exc);
}
}
这个recipient不就是我们开头一开始就注册好的AppDeathRecipient的类吗?刚好就回调到binderDied中。
总结
至此,linkToDeath整个流程就完成。实际上这个方法的作用就能下定论,当linkToDeath被注册起来之后,当前的进程的binder对象就会持续对远程端的binder观测其是否存活。
当对端出现了异常导致退出或者进程结束,放到当前的场景就是App进程结束或者闪退,则回通知到对对方观测的binder对象一个死亡回调,AMS就会清除存放在内部相关的Activity的信息,并且销毁回调不再继续监听对方的死亡。
所以,这个设计的核心思想如下:
当远程端没有死亡的时候或者正在死亡,根本不会做任何加入到本身进程的todo链表中,让其读取到命令到回调。一旦远程端死亡了,则会立即把这个对象添加到todo链表中,让对方端唤醒执行回调。
下面是linkToDeath时序图:
下面是当App进程时候的死亡回调时序图
注意:红色线代表了跨进程
结束语
到这里,我就把Binder大致上大大小小的所有的细节大致上都过了一边。整整花了6篇文章,也没办法把Binder的细节处处到位,仅仅只是过了大体的思想以及主要思路。还有binder的poll操作,binder的数据结构rb_tree,hlist等等。
不过在这个过程中,翻阅不少资料,特别是相关于Linux的内核知识以确定当初的学习是否正确。比起两年前当初看Binder就头疼,现在能抓住Binder主要思想来说已经有了不少进步。
Binder只能说是Android的核心之一,但是还有另一个核心当然是四大组件以及底层的绘制原理。里面涉及了opengl,还有linux的gui体系等等。接下来的计划,将会开始写Android 9.0中的Activity的启动流程,写完启动流程之后,因为会涉及到WindowManager,那么必须聊聊opencv,opengl,ffmpeg这几个经典的音视频第三库。
虽然opengl那一块几乎不怎么会,但为了弄明白Android的绘制原理这个坎必须经过。因此之后opengl的文章将会作为学习笔记放出。