移步系列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

更多相关文章

  1. C语言函数的递归(上)
  2. Android单个进程内存分配
  3. 从Process xxxx (pid xxx) has died分析
  4. Android(安卓)开发中的 Handler ,Thread ,Message ,Runnable 的
  5. Android之Handler详解(四)
  6. android 关于Only the original thread that created a view hie
  7. android中获取到当前线程
  8. android线程相关1
  9. Android(安卓)SurfaceView

随机推荐

  1. webpack 打包多html
  2. 支持API接口的开源CMS,基于Laravel开发
  3. 如何检查有哪些尝试入侵服务器IP?有哪些命
  4. 【阿里云镜像】使用阿里云Docker CE 镜像
  5. Python常见内置高阶函数即高阶函数用法
  6. python3中dict.keys().sort()用不了的解
  7. 场景透视怎么画?绘画透视教学
  8. Kubernetes 使用kubeadm创建集群
  9. Android系统自带样式(android:theme)
  10. Android系统主题样式属性