Binder 是一个类似于 C/S 架构的通信框架, 有时候客户端可能想知道服务端的状态, 比如服务端如果挂了, 客户端希望能及时的被通知到, 而不是等到再起请求服务端的时候才知道, 这种场景其实在互为 C/S 的时候最常用, 比如 AMS 与 App, 当 App 端进程异常退出的时候, AMS 希望能及时知道, 不仅仅是清理 App 端在 AMS 中的一些信息, 比如 ActivityRecord,ServiceRecord 等, 有时候可能还需要及时恢复一些自启动的 Service.Binder 实现了一套 "死亡讣告" 的功能, 即: 服务端挂了, 或者正常退出, Binder 驱动会向客户端发送一份讣告, 告诉客户端 Binder 服务挂了.
这个 "讣告" 究竟是如何实现的呢? 其作用又是什么呢? 对于 Android 而言, Binder"讣告" 有点采用了类似观察者模式, 因此, 首先需要将 Observer 注册到目标对象中, 其实就是将 Client 注册到 Binder 驱动, 将来 Binder 服务挂掉时候, 就能通过驱动去发送. Binder"讣告" 发送的入口只有一个: 在释放 binder 设备的时候, 在在操作系统中, 无论进程是正常退出还是异常退出, 进程所申请的所有资源都会被回收, 包括打开的一些设备文件, 如 Binder 字符设备等. 在释放的时候, 就会调用相应的 release 函数,"讣告" 也就是在这个时候去发送的. 因此 Binder 讣告其实就仅仅包括两部分: 注册与通知.
Binder"讣告" 的注册入口
这里拿 bindService 为例子进行分析, 其他场景类似, bindService 会首先请求 AMS 去启动 Service,Server 端进程在启动时, 会调用函数 open 来打开设备文件 / dev/binder, 同时将 Binder 服务实体回传给 AMS,AMS 再将 Binder 实体的引用句柄通过 Binder 通信传递给 Client, 也就是在 AMS 回传给 Client 的时候, 会向 Binder 驱动注册. 其实这也比较好理解, 获得了服务端的代理, 就应该关心服务端的死活 . 当 AMS 利用 IServiceConnection 这条 binder 通信线路为 Client 回传 Binder 服务实体的时候, InnerConnection 就会间接的将死亡回调注册到内核:
- private static class InnerConnection extends IServiceConnection.Stub {
- final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
- public void connected(ComponentName name, IBinder service) throws RemoteException {
- LoadedApk.ServiceDispatcher sd = mDispatcher.get();
- if (sd != null) {
- sd.connected(name, service);
- }
- }
- }
ServiceDispatcher 函数进一步调用 doConnected
public void doConnected(ComponentName name, IBinder service) { ServiceDispatcher.ConnectionInfo old; ServiceDispatcher.ConnectionInfo info; synchronized (this) { if (service != null) { mDied = false; info = new ConnectionInfo(); info.binder = service; info.deathMonitor = new DeathMonitor(name, service); try { <!-- 关键点点 1--> service.linkToDeath(info.deathMonitor, 0); } }
看关键点点 1 , 这里的 IBinder service 其实是 AMS 回传的服务代理 BinderProxy,linkToDeath 是一个 Native 函数, 会进一步调用 BpBinde 的 linkToDeath:
status_t BpBinder::linkToDeath( const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags){ <!-- 关键点 1--> IPCThreadState* self = IPCThreadState::self(); self->requestDeathNotification(mHandle, this); self->flushCommands(); }
最终调用 IPCThreadState 的 requestDeathNotification(mHandle, this) 向内核发送 BC_REQUEST_DEATH_NOTIFICATION 请求:
status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy) { mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION); mOut.writeInt32((int32_t)handle); mOut.writeInt32((int32_t)proxy); return NO_ERROR; }
最后来看一下在内核中, 是怎么登记注册的:
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed) { ... case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { ... ref = binder_get_ref(proc, target); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
... 关键点 1
death = kzalloc(sizeof(*death), GFP_KERNEL); binder_stats.obj_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); } } } }
看关键点 1 , 其实就是为 Client 新建 binder_ref_death 对象, 并赋值给 binder_ref. 在 binder 驱动中, binder_node 节点会记录所有 binder_ref, 当 binder_node 所在的进程挂掉后, 驱动就能根据这个全局 binder_ref 列表找到所有 Client 的 binder_ref, 并对于设置了死亡回调的 Client 发送 "讣告", 这是因为在 binder_get_ref_for_node 向 Client 插入 binder_ref 的时候, 也会插入 binder_node 的 binder_ref 列表.
static struct binder_ref * binder_get_ref_for_node(struct binder_proc *proc, struct binder_node *node) { struct rb_node *n; struct rb_node **p = &proc->refs_by_node.rb_node; struct rb_node *parent = NULL; struct binder_ref *ref, *new_ref; if (node) { hlist_add_head(&new_ref->node_entry, &node->refs); } return new_ref; }
如此, 死亡回调入口就被注册到 binder 内核驱动, 之后, 等到进程结束要释放 binder 的时候, 就会触发死亡回调.
死亡通知的发送
在调用 binder_realease 函数来释放相应资源的时候, 最终会调用 binder_deferred_release 函数. 该函数会遍历该 binder_proc 内所有的 binder_node 节点, 并向注册了死亡回调的 Client 发送讣告,
static void binder_deferred_release(struct binder_proc *proc) { .... if (ref->death) { death++; if (list_empty(&ref->death->work.entry)) { ref->death->work.type = BINDER_WORK_DEAD_BINDER; list_add_tail(&ref->death->work.entry, &ref->proc->todo); // 插入到 binder_ref 请求进程的 binder 线程等待队列????? 天然支持 binder 通信吗? // 什么时候, 需要死亡回调, 自己也是 binder 服务? wake_up_interruptible(&ref->proc->wait); } ... }
死亡讣告被直接发送到 Client 端的 binder 进程 todo 队列上, 这里似乎也只对于互为 C/S 通信的场景有用, 当 Client 的 binder 线程被唤醒后, 就会针对 "讣告" 做一些清理及善后工作:
static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed, int non_block) { case BINDER_WORK_DEAD_BINDER: case BINDER_WORK_DEAD_BINDER_AND_CLEAR: case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { struct binder_ref_death *death = container_of(w, struct binder_ref_death, work); uint32_t cmd; if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; else cmd = BR_DEAD_BINDER; ... }
这里会向用户空间写入一个 BR_DEAD_BINDER 命令, 并返回 talkWithDriver 函数, 返回后, IPCThreadState 会继续执行 executeCommand,
status_t IPCThreadState::executeCommand(int32_t cmd) { // 死亡讣告 case BR_DEAD_BINDER: { BpBinder *proxy = (BpBinder*)mIn.readInt32(); <!-- 关键点 1 --> proxy->sendObituary(); mOut.writeInt32(BC_DEAD_BINDER_DONE); mOut.writeInt32((int32_t)proxy); } break; }
看关键点 1,Obituary 直译过来就是讣告, 其实就是利用 BpBinder 发送讣告, 待讣告处理结束后, 再向 Binder 驱动发送确认通知.
void BpBinder::sendObituary() { ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n", this, mHandle, mObitsSent ? "true" : "false"); mAlive = 0; if (mObitsSent) return; mLock.lock(); Vector<Obituary>* obits = mObituaries; if(obits != NULL) { <!-- 关键点 1--> 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, 这里跟注册相对应, 将自己从观察者列表中清除, 之后再上报
void BpBinder::reportOneDeath(const Obituary& obit) { sp<DeathRecipient> recipient = obit.recipient.promote(); ALOGV("Reporting death to recipient: %p\n", recipient.get()); if (recipient == NULL) return; recipient->binderDied(this); }
进而调用上层 DeathRecipient 的回调, 做一些清理之类的逻辑. 以 AMS 为例, 其 binderDied 函数就挺复杂, 包括了一些数据的清理, 甚至还有进程的重建等, 不做讨论.
自己是从事了七年开发的 Android 工程师, 不少人私下问我, 2019 年 Android 进阶该怎么学, 方法有没有?
没错, 年初我花了一个多月的时间整理出来的学习资料, 希望能帮助那些想进阶提升 Android 开发, 却又不知道怎么进阶学习的朋友.[包括高级 UI, 性能优化, 架构师课程, NDK,Kotlin, 混合式开发 (ReactNative+Weex),Flutter 等架构技术资料] , 希望能帮助到您面试前的复习且找到一个好的工作, 也节省大家在网上搜索资料的时间来学习.
来源: http://www.jianshu.com/p/cdcf5cbfc4e0