美文网首页
Android跨进程通信IPC之16——Binder之nativ

Android跨进程通信IPC之16——Binder之nativ

作者: 凯玲之恋 | 来源:发表于2018-08-19 16:38 被阅读72次

    移步系列Android跨进程通信IPC系列

    1 源码位置

    /frameworks/av/media/libmedia/
      - IMediaDeathNotifier.cpp
    
    framework/native/libs/binder/
      - Binder.cpp
      - BpBinder.cpp
      - IPCThreadState.cpp
      - ProcessState.cpp
      - IServiceManager.cpp
    

    对应的链接为

    在Native层的服务注册,我们依旧选择media为例展开讲解,先来看看media类关系图。

    2类图

    5713484-1048ad1cfa1b87af.png

    图解:

    • 蓝色:代表获取MediaPlayerService服务相关的类
    • 绿色:代表Binder架构中与Binder驱动通信过程中的最为核心的两个类
    • 紫色:代表注册服务获取服务的公共接口/父类

    3 获取服务流程

    3.1 getMediaPlayerService()函数

    //frameworks/av/media/libmedia/IMediaDeathNotifier.cpp   35行
    sp<IMediaPlayerService>&
    IMediaDeathNotifier::getMediaPlayerService()
    {
        Mutex::Autolock _l(sServiceLock);
        if (sMediaPlayerService == 0) {
             // 获取 ServiceManager
            sp<IServiceManager> sm = defaultServiceManager(); 
            sp<IBinder> 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<IMediaPlayerService>(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<IBinder> getService(const String16& name) const
        {
            unsigned n;
            for (n = 0; n < 5; n++){
                sp<IBinder> 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<IBinder> 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<IBinder> Parcel::readStrongBinder() const
    {
        sp<IBinder> val;
        unflatten_binder(ProcessState::self(), *this, &val);
        return val;
    }
    

    里面主要是调用unflatten_binder()函数
    那我们就来详细看下

    3.4.3.1 unflatten_binder()函数

    status_t unflatten_binder(const sp<ProcessState>& proc,
        const Parcel& in, sp<IBinder>* out)
    {
        const flat_binder_object* flat = in.readObject(false);
        if (flat) {
            switch (flat->type) {
                case BINDER_TYPE_BINDER:
                    // 当请求服务的进程与服务属于同一进程
                    *out = reinterpret_cast<IBinder*>(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<BpBinder*>(out->get()), *flat, in);
            }
        }
        return BAD_TYPE;
    }
    

    如果服务的进程与服务属于不同的进程会调用getStrongProxyForHandle()函数,那我们就好好研究下

    3.4.3.2 getStrongProxyForHandle()函数

    sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        sp<IBinder> 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<DeathRecipient>& 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<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;
    }
    

    里面调用了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<IBinder>& who __unused) {
        SortedVector< wp<IMediaDeathNotifier> > 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<IMediaDeathNotifier> 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

    相关文章

      网友评论

          本文标题:Android跨进程通信IPC之16——Binder之nativ

          本文链接:https://www.haomeiwen.com/subject/nkvciftx.html