Android跨进程通信IPC之16——Binder之native层C++篇--获取服务
移步系列Android跨进程通信IPC系列
1 源码位置
/frameworks/av/media/libmedia/ - IMediaDeathNotifier.cppframework/native/libs/binder/ - Binder.cpp - BpBinder.cpp - IPCThreadState.cpp - ProcessState.cpp - IServiceManager.cpp
对应的链接为
- Binder.cpp
- BpBinder.cpp
- IPCThreadState.cpp
- ProcessState.cpp
- IServiceManager.cpp
- IInterface.cpp
- IInterface.cpp
- IInterface.h
- main_mediaserver.cpp
- MediaPlayerService.cpp
- IMediaDeathNotifier.cpp
在Native层的服务注册,我们依旧选择media为例展开讲解,先来看看media类关系图。
2类图
5713484-1048ad1cfa1b87af.png图解:
- 蓝色:代表获取MediaPlayerService服务相关的类
- 绿色:代表Binder架构中与Binder驱动通信过程中的最为核心的两个类
- 紫色:代表注册服务和获取服务的公共接口/父类
3 获取服务流程
3.1 getMediaPlayerService()函数
//frameworks/av/media/libmedia/IMediaDeathNotifier.cpp 35行sp&IMediaDeathNotifier::getMediaPlayerService(){ Mutex::Autolock _l(sServiceLock); if (sMediaPlayerService == 0) { // 获取 ServiceManager sp sm = defaultServiceManager(); sp binder; do { //获取名为"media.player"的服务 binder = sm->getService(String16("media.player")); if (binder != 0) { break; } usleep(500000); // 0.5s } while (true); if (sDeathNotifier == NULL) { // 创建死亡通知对象 sDeathNotifier = new DeathNotifier(); } //将死亡通知连接到binder binder->linkToDeath(sDeathNotifier); sMediaPlayerService = interface_cast(binder); } return sMediaPlayerService;}
其中defaultServiceManager()过程在上面已经说了,返回的是BpServiceManager
在请求获取名为"media.player"的服务过程中,采用不断循环获取的方法。由于MediaPlayerService服务可能还没向ServiceManager注册完成或者尚未启动完成等情况,故则binder返回NULL,休眠0.5s后继续请求,知道获取服务为止。
3.2 BpServiceManager.getService()函数
//frameworks/native/libs/binder/IServiceManager.cpp 134行virtual sp getService(const String16& name) const { unsigned n; for (n = 0; n < 5; n++){ sp svc = checkService(name); if (svc != NULL) return svc; sleep(1); } return NULL; }
- 通过BpServiceManager来获取MediaPlayer服务:检索服务是否存在,当服务存在则返回相应的服务,当服务不存在则休眠1s再继续检索服务。
- 该循环进行5次。为什么循环5次?这估计和Android的ANR的时间为5s相关。如果每次都无法获取服务,循环5次,每次循环休眠1s,忽略checkService()的时间,差不多是5s的时间。
3.3 BpSeriveManager.checkService()函数
//frameworks/native/libs/binder/IServiceManager.cpp 146行virtual sp checkService( const String16& name) const{ Parcel data, reply; //写入RPC头 data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); //写入服务名 data.writeString16(name); remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); return reply.readStrongBinder(); }
检索制定服务是否存在,其中remote()为BpBinder
3.4 BpBinder::transact()函数
// /frameworks/native/libs/binder/BpBinder.cpp 159行status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ if (mAlive) { status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; } return DEAD_OBJECT;}
Binder代理类调用transact()方法,真正工作还是交给IPCThreadState来进行transact工作。
3.4.1 IPCThreadState::self()函数
IPCThreadState* IPCThreadState::self(){ if (gHaveTLS) {restart: const pthread_key_t k = gTLS; IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); if (st) return st; //初始化 IPCThreadState return new IPCThreadState; } if (gShutdown) return NULL; pthread_mutex_lock(&gTLSMutex); //首次进入gHaveTLS为false if (!gHaveTLS) { //创建线程的TLS if (pthread_key_create(&gTLS, threadDestructor) != 0) { pthread_mutex_unlock(&gTLSMutex); return NULL; } gHaveTLS = true; } pthread_mutex_unlock(&gTLSMutex); goto restart;}
- TLS是指Thread local storage(线程本地存储空间),每个线程都拥有自己的TLS,并且是私有空间,线程之间不会共享。
- 通过pthread_getspecific()/pthread_setspecific()函数可以获取/设置这些空间中的内容。从线程本地存储空间获的保存期中的IPCThreadState对象。
以后面的流程和上面的注册流程大致相同,主要流程也是 IPCThreadState:: transact()函数、IPCThreadState::writeTransactionData()函数、IPCThreadState::waitForResponse()函数和IPCThreadState.talkWithDriver()函数,Android跨进程通信IPC之15——Binder之Framework层C++篇--注册服务已经讲解过了,这里就不详细说明了。我们从IPCThreadState.talkWithDriver() 开始继讲解
3.4.2 IPCThreadState:: talkWithDriver()函数
status_t IPCThreadState::talkWithDriver(bool doReceive){ ... binder_write_read bwr; const bool needRead = mIn.dataPosition() >= mIn.dataSize(); const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; bwr.write_size = outAvail; bwr.write_buffer = (uintptr_t)mOut.data(); //接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了。 if (doReceive && needRead) { bwr.read_size = mIn.dataCapacity(); bwr.read_buffer = (uintptr_t)mIn.data(); } else { bwr.read_size = 0; bwr.read_buffer = 0; } //当读缓冲和写缓冲都为空,则直接返回 if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR; bwr.write_consumed = 0; bwr.read_consumed = 0; status_t err; do { //通过ioctl不停的读写操作,跟Binder Driver进行通信 if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) err = NO_ERROR; ... //当被中断,则继续执行 } while (err == -EINTR); ... return err;}
binder_write_read结构体 用来与Binder设备交换数据的结构,通过ioctl与mDriverFD通信,是真正的与Binder驱动进行数据读写交互的过程。先向service manager进程发送查询服务的请求(BR_TRANSACTION)。当service manager 进程收到带命令后,会执行do_find_service()查询服务所对应的handle,然后再binder_send_reply()应发送者,发送BC_REPLY协议,然后再调用binder_transaction(),再向服务请求者的todo队列插入事务。接下来,再看看binder_transaction过程。
3.4.2.1 binder_transaction()函数
//kernel/drivers/android/binder.c 1827行static void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply){ //根据各种判定,获取以下信息: // 目标线程 struct binder_thread *target_thread; // 目标进程 struct binder_proc *target_proc; /// 目标binder节点 struct binder_node *target_node; // 目标 TODO队列 struct list_head *target_list; // 目标等待队列 wait_queue_head_t *target_wait; ... //分配两个结构体内存 struct binder_transaction *t = kzalloc(sizeof(*t), GFP_KERNEL); struct binder_work *tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); //从target_proc分配一块buffer t->buffer = binder_alloc_buf(target_proc, tr->data_size, for (; offp < off_end; offp++) { switch (fp->type) { case BINDER_TYPE_BINDER: ... case BINDER_TYPE_WEAK_BINDER: ... case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { struct binder_ref *ref = binder_get_ref(proc, fp->handle, fp->type == BINDER_TYPE_HANDLE); ... //此时运行在servicemanager进程,故ref->node是指向服务所在进程的binder实体, //而target_proc为请求服务所在的进程,此时并不相等。 if (ref->node->proc == target_proc) { if (fp->type == BINDER_TYPE_HANDLE) fp->type = BINDER_TYPE_BINDER; else fp->type = BINDER_TYPE_WEAK_BINDER; fp->binder = ref->node->ptr; // BBinder服务的地址 fp->cookie = ref->node->cookie; binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); } else { struct binder_ref *new_ref; //请求服务所在进程并非服务所在进程,则为请求服务所在进程创建binder_ref new_ref = binder_get_ref_for_node(target_proc, ref->node); fp->binder = 0; //重新给handle赋值 fp->handle = new_ref->desc; fp->cookie = 0; binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); } } break; case BINDER_TYPE_FD: ... } } //分别target_list和当前线程TODO队列插入事务 t->work.type = BINDER_WORK_TRANSACTION; list_add_tail(&t->work.entry, target_list); tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; list_add_tail(&tcomplete->entry, &thread->todo); if (target_wait) wake_up_interruptible(target_wait); return;}
这个过程非常重要,分两种情况来说:
- 情况1 当请求服务的进程与服务属于不同的进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node
- 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数+1,并且修改type为BINDER_TYPE_BINER或BINDER_TYPE_WEAK_BINDER。
3.4.2.2 binder_thread_read()函数
//kernel/drivers/android/binder.c 2650行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){ ... //当线程todo队列有数据则执行往下执行;当线程todo队列没有数据,则进入休眠等待状态 ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); ... while (1) { uint32_t cmd; struct binder_transaction_data tr; struct binder_work *w; struct binder_transaction *t = NULL; //先从线程todo队列获取事务数据 if (!list_empty(&thread->todo)) { w = list_first_entry(&thread->todo, struct binder_work, entry); // 线程todo队列没有数据, 则从进程todo对获取事务数据 } else if (!list_empty(&proc->todo) && wait_for_proc_work) { ... } switch (w->type) { case BINDER_WORK_TRANSACTION: //获取transaction数据 t = container_of(w, struct binder_transaction, work); break; case : ... } //只有BINDER_WORK_TRANSACTION命令才能继续往下执行 if (!t) continue; if (t->buffer->target_node) { ... } else { tr.target.ptr = NULL; tr.cookie = NULL; //设置命令为BR_REPLY cmd = BR_REPLY; } tr.code = t->code; tr.flags = t->flags; tr.sender_euid = t->sender_euid; if (t->from) { struct task_struct *sender = t->from->proc->tsk; //当非oneway的情况下,将调用者进程的pid保存到sender_pid tr.sender_pid = task_tgid_nr_ns(sender, current->nsproxy->pid_ns); } else { ... } tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; tr.data.ptr.buffer = (void *)t->buffer->data + proc->user_buffer_offset; tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); //将cmd和数据写回用户空间 put_user(cmd, (uint32_t __user *)ptr); ptr += sizeof(uint32_t); copy_to_user(ptr, &tr, sizeof(tr)); ptr += sizeof(tr); list_del(&t->work.entry); t->buffer->allow_user_free = 1; if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { ... } else { t->buffer->transaction = NULL; //通信完成则运行释放 kfree(t); } break; }done: *consumed = ptr - buffer; if (proc->requested_threads + proc->ready_threads == 0 && proc->requested_threads_started < proc->max_threads && (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED))) { proc->requested_threads++; // 生成BR_SPAWN_LOOPER命令,用于创建新的线程 put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer); } return 0;}
3.4.3 readStrongBinder()函数
//frameworks/native/libs/binder/Parcel.cpp 1334行sp Parcel::readStrongBinder() const{ sp val; unflatten_binder(ProcessState::self(), *this, &val); return val;}
里面主要是调用unflatten_binder()函数
那我们就来详细看下
3.4.3.1 unflatten_binder()函数
status_t unflatten_binder(const sp& proc, const Parcel& in, sp* out){ const flat_binder_object* flat = in.readObject(false); if (flat) { switch (flat->type) { case BINDER_TYPE_BINDER: // 当请求服务的进程与服务属于同一进程 *out = reinterpret_cast(flat->cookie); return finish_unflatten_binder(NULL, *flat, in); case BINDER_TYPE_HANDLE: //请求服务的进程与服务属于不同进程 *out = proc->getStrongProxyForHandle(flat->handle); //创建BpBinder对象 return finish_unflatten_binder( static_cast(out->get()), *flat, in); } } return BAD_TYPE;}
如果服务的进程与服务属于不同的进程会调用getStrongProxyForHandle()函数,那我们就好好研究下
3.4.3.2 getStrongProxyForHandle()函数
sp ProcessState::getStrongProxyForHandle(int32_t handle){ sp result; AutoMutex _l(mLock); //查找handle对应的资源项[2.9.3] handle_entry* e = lookupHandleLocked(handle); if (e != NULL) { IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { ... //当handle值所对应的IBinder不存在或弱引用无效时,则创建BpBinder对象 b = new BpBinder(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; } else { result.force_set(b); e->refs->decWeak(this); } } return result;}
readStrong的功能是flat_binder_object解析并创建BpBinder对象
3.4.3.3 lookupHandleLocked函数
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle){ const size_t N=mHandleToObject.size(); //当handle大于mHandleToObject的长度时,进入该分支 if (N <= (size_t)handle) { handle_entry e; e.binder = NULL; e.refs = NULL; //从mHandleToObject的第N个位置开始,插入(handle+1-N)个e到队列中 status_t err = mHandleToObject.insertAt(e, N, handle+1-N); if (err < NO_ERROR) return NULL; } return &mHandleToObject.editItemAt(handle);}
根据handle值来查找对应的handle_entry。
4 死亡通知
死亡通知时为了让Bp端知道Bn端的生死情况
- DeathNotifier是继承IBinder::DeathRecipient类,主要需要实现其binderDied()来进行死亡通告。
- 注册:binder->linkToDeath(sDeathNotifier)是为了将sDeathNotifier死亡通知注册到Binder上。
Bp端只需要覆写binderDied()方法,实现一些后尾清楚类的工作,则在Bn端死掉后,会回调binderDied()进行相应处理
4.1 linkToDeath()函数
// frameworks/native/libs/binder/BpBinder.cpp 173行status_t BpBinder::linkToDeath( const sp& recipient, void* cookie, uint32_t flags){ Obituary ob; ob.recipient = recipient; ob.cookie = cookie; ob.flags = flags; { AutoMutex _l(mLock); if (!mObitsSent) { if (!mObituaries) { mObituaries = new Vector; 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;}
里面调用了requestDeathNotification()函数
4.2 requestDeathNotification()函数
//frameworks/native/libs/binder/IPCThreadState.cpp 670行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;}
向binder driver发送 BC_REQUEST_DEATH_NOTIFICATION命令。后面的流程和 Service Manager 里面的 ** binder_link_to_death() ** 的过程。
4.3 binderDied()函数
//frameworks/av/media/libmedia/IMediaDeathNotifier.cpp 78行void IMediaDeathNotifier::DeathNotifier::binderDied(const wp& who __unused) { SortedVector< wp > list; { Mutex::Autolock _l(sServiceLock); // 把Bp端的MediaPlayerService清除掉 sMediaPlayerService.clear(); list = sObitRecipients; } size_t count = list.size(); for (size_t iter = 0; iter < count; ++iter) { sp notifier = list[iter].promote(); if (notifier != 0) { //当MediaServer挂了则通知应用程序,应用程序回调该方法 notifier->died(); } }}
客户端进程通过Binder驱动获得Binder的代理(BpBinder),死亡通知注册的过程就是客户端进程向Binder驱动注册的一个死亡通知,该死亡通知关联BBinder,即与BpBinder所对应的服务端。
4.4 unlinkToDeath()函数
当Bp在收到服务端的死亡通知之前先挂了,那么需要在对象的销毁方法内,调用unlinkToDeath()来取消死亡通知;
//frameworks/av/media/libmedia/IMediaDeathNotifier.cpp 101行IMediaDeathNotifier::DeathNotifier::~DeathNotifier(){ Mutex::Autolock _l(sServiceLock); sObitRecipients.clear(); if (sMediaPlayerService != 0) { IInterface::asBinder(sMediaPlayerService)->unlinkToDeath(this); }}
4.5 触发时机
- 每当service进程退出时,service manager 会收到来自Binder驱动的死亡通知。
- 这项工作在启动Service Manager时通过 binder_link_to_death(bs, ptr, &si->death)完成。
- 另外,每个Bp端也可以自己注册死亡通知,能获取Binder的死亡消息,比如前面的IMediaDeathNotifier。
那Binder的死亡通知时如何被出发的?对于Binder的IPC进程都会打开/dev/binder文件,当进程异常退出的时候,Binder驱动会保证释放将要退出的进程中没有正常关闭的/dev/binder文件,实现机制是binder驱动通过调用/dev/binder文件所对应的release回调函数,执行清理工作,并且检查BBinder是否有注册死亡通知,当发现存在死亡通知时,那么久向其对应的BpBinder端发送死亡通知消息。
5 总结
在请求服务(getService)的过程,当执行到binder_transaction()时,会区分请求服务所属进程情况。
- 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创binder_ref对象,指向服务进程的binder_noder
- 当请求服务的进程与服务属于同一进程, 则不再创建新对象,只是引用计数+1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
- 最终readStrongBinder(),返回的是BB对象的真实子类
参考
Android跨进程通信IPC之9——Binder之Framework层C++篇2
更多相关文章
- C语言函数的递归(上)
- Android单个进程内存分配
- 从Process xxxx (pid xxx) has died分析
- Android(安卓)开发中的 Handler ,Thread ,Message ,Runnable 的
- Android之Handler详解(四)
- android 关于Only the original thread that created a view hie
- android中获取到当前线程
- android线程相关1
- Android(安卓)SurfaceView