android Binder详解(4)

来源:互联网 发布:淘宝火锅底料 编辑:程序博客网 时间:2024/06/05 12:40

3.4 getService()分析

clinet中获取service接口的调用如下:

    sp<ISampleService> sampleSrv;    if(getService(String16("SampleService"), &sampleSrv) != NO_ERROR){        ALOGE("get SampleService fail");        return 0;    }
getService()实现如下:

template<typename INTERFACE>status_t getService(const String16& name, sp<INTERFACE>* outService){    const sp<IServiceManager> sm = defaultServiceManager();    if (sm != NULL) {        *outService = interface_cast<INTERFACE>(sm->getService(name));        if ((*outService) != NULL) return NO_ERROR;    }    return NAME_NOT_FOUND;}
这其中获取ServiceManager接口的动作,前面已经分析过了。之后有两个动作:
1,sm->getService(name)获取到一个sp<IBinder>对象。
2,从获取的BpBinder指针中构造出BpSampleService对象。

第二步是很清楚的,就是调用了BpSampleService::interface_cast<ISampleService>(sp<IBinder>)。我们主要需要研究一下第一步的细节。


3.4.1 BpServiceManager::getService()

BpServiceManager::getService()是调用了checkService()函数

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;            ALOGI("Waiting for service %s...\n", String8(name).string());            sleep(1);        }        return NULL;    }
virtual sp<IBinder> checkService( const String16& name) const    {        Parcel data, reply;        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());        data.writeString16(name);        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);        return reply.readStrongBinder();    }
checkService()中之写入了InterfaceToken和servicename,然后就开始了transact()了。
这边的transact因为没有写入object,流程和PING_TRANSACTION的基本一样了。我们直接到ServiceManager端看看具体的处理。

3.4.2 ServiceManager处理CHECK_SERVICE_TRANSACTION

command和ADD_SERVICE一样在svcmgr_handler()中处理

    case SVC_MGR_GET_SERVICE:    case SVC_MGR_CHECK_SERVICE:       //获取service name。        s = bio_get_string16(msg, &len);       //查找对应的service。        ptr = do_find_service(bs, s, len, txn->sender_euid);        if (!ptr)            break;        bio_put_ref(reply, ptr);        return 0;
主要看下do_find_service()

void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid){    //根据service name找到对应的svcinfo结点。    struct svcinfo *si;    si = find_svc(s, len);    //    ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);    if (si && si->ptr) {        if (!si->allow_isolated) {            // If this service doesn't allow access from isolated processes,            // then check the uid to see if it is isolated.            unsigned appid = uid % AID_USER;            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {                return 0;            }        }    //返回结点中的ptr,这个ptr是binder中对应的binder_ref.desc。        return si->ptr;    } else {        return 0;    }}
我们看到了最终返回的是SampleService在ServiceManager这边对应的binder_ref的desc信息,之后这个信息被写入到write buffer中:
void bio_put_ref(struct binder_io *bio, void *ptr){     //构造了一个binder_object,也就是一个flat_binder_object。    struct binder_object *obj;    if (ptr)        obj = bio_alloc_obj(bio);    else        obj = bio_alloc(bio, sizeof(*obj));    if (!obj)        return;    obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;    obj->type = BINDER_TYPE_HANDLE;    obj->pointer = ptr;    obj->cookie = 0;}
之后进入binder_send_reply(),在这里,我们write了BC_FREE_BUFFER,还有一组BC_REPLY信息,BC_REPLY信息中,是在bio_put_ref()中构造的binder_object。
带着这些信息,我们进入到binder中,首先在binder_thread_write()中处理BC_FREE_BUFFER,这边的处理和之前的PING_TRANSACTION基本一致,没有object,释放掉binder_buffer就可以了。
然后处理BC_REPLY,主要在binder_transaction()函数中,这里和addService处理差异在于reply信息是一个object,而不是一个数据,我们看下组织binder_transaction的部分:

        //remote binder object, means BpBinder。        case BINDER_TYPE_HANDLE:        case BINDER_TYPE_WEAK_HANDLE: {            struct binder_ref *ref = binder_get_ref(proc, fp->handle);            if (ref == NULL) {                binder_user_error("%d:%d got transaction with invalid handle, %ld\n",                        proc->pid,                        thread->pid, fp->handle);                return_error = BR_FAILED_REPLY;                goto err_binder_get_ref_failed;            }            if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {                return_error = BR_FAILED_REPLY;                goto err_binder_get_ref_failed;            }            //如果传给service所在的进程,转换为BINDER_TYPE_BINDER类型的object。            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;                fp->cookie = ref->node->cookie;                binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);                trace_binder_transaction_ref_to_node(t, ref);                binder_debug(BINDER_DEBUG_TRANSACTION,                         "        ref %d desc %d -> node %d u%p\n",                         ref->debug_id, ref->desc, ref->node->debug_id,                         ref->node->ptr);            } else {//传入到其他client进程,为目标进程建立新的binder_ref,并传回这个新的binder_ref的信息。                struct binder_ref *new_ref;                new_ref = binder_get_ref_for_node(target_proc, ref->node);//第一次会建立一个新的binder_ref。                if (new_ref == NULL) {                    return_error = BR_FAILED_REPLY;                    goto err_binder_get_ref_for_node_failed;                }                fp->handle = new_ref->desc;//用目标进程desc替换。                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);                trace_binder_transaction_ref_to_ref(t, ref,                                    new_ref);                binder_debug(BINDER_DEBUG_TRANSACTION,                         "        ref %d desc %d -> ref %d desc %d (node %d)\n",                         ref->debug_id, ref->desc, new_ref->debug_id,                         new_ref->desc, ref->node->debug_id);            }        } break;
在这里,binder会为client进程建立一个新的binder_ref出来,他会在当前进程中得到一个唯一的desc也就是handle值,注意desc值0是保留给了ServiceManager,最终我们把这个handle回填到data中。

3.4.3 client端处理返回信息
client在IPCThreadState::waitForResponse()处理BR_REPLY,数据传递给Parcel reply中,最终调用得到了sp<IBinder>对象。

reply.readStrongBinder();
我们看看readStrongBinder()里面做了什么:
sp<IBinder> Parcel::readStrongBinder() const{    sp<IBinder> val;    unflatten_binder(ProcessState::self(), *this, &val);    return val;}
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 = static_cast<IBinder*>(flat->cookie);                return finish_unflatten_binder(NULL, *flat, in);            case BINDER_TYPE_HANDLE:                //查找对应的BpBinder对象。                *out = proc->getStrongProxyForHandle(flat->handle);                return finish_unflatten_binder(                    static_cast<BpBinder*>(out->get()), *flat, in);        }            }    return BAD_TYPE;}
最终还是调用了getStrongproxyForHandle()来获取了sp<IBinder>,参数的handle就是在binder中的binder_ref.desc。
getStrongproxyForHandle()中创建BpBinder的动作,我们就不在看了,我们看一下如果不是首次调用的情况下的处理:
} else {            // This little bit of nastyness is to allow us to add a primary            // reference to the remote proxy when this team doesn't have one            // but another team is sending the handle to us.           //force_set()函数和直接赋值的差异在于它会强制调用RefBase.onFirstRef(),对这里来说           //也就是会出发BpBinder.onFirstRef()。            result.force_set(b);            e->refs->decWeak(this);        }
这段代码中主要注意一下result.fore_set(b)这行代码,这里又强制触发了一次RefBase.onFirstRef(),调用的目的是对binder中的binder_ref增加了一次引用。
但是这里有个问题:
force_set对于binder_ref又增加了一次reference,但是因为他们用的都是同意BpBinder,最终只会调用一次onLastStrongRef()去decrease strong reference,这样会导致ref的增减不同步,可能是会有问题的。(加了debug信息确认,的确是会出现这样的问题的。)


至此,getService()部分分析完毕,我们看到了service的传递主要是依赖binder对于binder_ref的管理,binder_ref.desc决定了在user层的handle,user层又使用handle去建立了一个BpBinder,所有的service访问结构都是使用这个BpBinder构造出BpXXX对象来操作service接口。


3.5 sayHello()调用分析
这部分我们分析下client端调用SampleService的sayHello()接口的流程,看看client端是如何把信息投递到service进程中去的。

3.5.1 sayHello() client调用

virtual int sayHello(const String8& clientName){        Parcel data,reply;        data.writeInterfaceToken(ISampleService::getInterfaceDescriptor());        data.writeString8(clientName);        remote()->transact(BnSampleService::SAY_HELLO, data, &reply);        int ret = reply.readInt32();        ALOGD("sayHello return %d",ret);        return ret;    }
这边直接进入到binder中的binder_transaction()函数中去看处理,首先是查找target node的动作:
     if (tr->target.handle) {//handle不为0的情况,这个是一般service的处理。            struct binder_ref *ref;            ref = binder_get_ref(proc, tr->target.handle);            if (ref == NULL) {                binder_user_error("%d:%d got transaction to invalid handle\n",                    proc->pid, thread->pid);                return_error = BR_FAILED_REPLY;                goto err_invalid_target_handle;            }            target_node = ref->node;        } else {//handle为0,即ServiceManager的case,直接获取binder_context_mgr_node。            target_node = binder_context_mgr_node;            if (target_node == NULL) {                return_error = BR_DEAD_REPLY;                goto err_no_context_mgr_node;            }        }
这部分和ServiceManager不一样,ServieManager的handle always为0,判断handle值为0就可以使用binder_context_mgr_node了。
对于一般service,handle是当前进程中的binder_ref的desc,根据handle我们可以找到对应的binder_ref,而binder_ref.node保存了它所对应的binder_node。
得到了target node之后,可以找到对应的target proc,这样我们就可以把work加入到到对应的进程的todo list中去了。

3.5.2 sayHello() Service端调用

Service端是在IPCThreadState::joinThreadPool()中响应处理的,通过talkWithDriver()和binder打交道,在binder_thread_read()中获取到client传来的信息,流程没有什么特别的,我们注意一下传回来的数据的组织:

        if (t->buffer->target_node) {//transaction cmd时候。            //对于binder_context_mgr_node,ptr和cookie都为0。            //对于一般service来说,binder_node中的ptr是service的weakrefs指针,cookie是service的对象指针。(见Parcel中的flatten_binder())            struct binder_node *target_node = t->buffer->target_node;            tr.target.ptr = target_node->ptr;            tr.cookie =  target_node->cookie;            t->saved_priority = task_nice(current);            if (t->priority < target_node->min_priority &&                !(t->flags & TF_ONE_WAY))                binder_set_nice(t->priority);            else if (!(t->flags & TF_ONE_WAY) ||                 t->saved_priority > target_node->min_priority)                binder_set_nice(target_node->min_priority);            cmd = BR_TRANSACTION;        } else {//reply cmd时候,reply时候target_node为null。            tr.target.ptr = NULL;            tr.cookie = NULL;            cmd = BR_REPLY;        }
注意这边tr.target.ptr和tr.cookie这两个指针,cookie这个就是SampleService的对象。
回到在executeCommand()中处理command:

      case BR_TRANSACTION:        {            binder_transaction_data tr;            result = mIn.read(&tr, sizeof(tr));            ALOG_ASSERT(result == NO_ERROR,                "Not enough command data for brTRANSACTION");            if (result != NO_ERROR) break;                        Parcel buffer;           //将data保存到Parcel中。            buffer.ipcSetDataReference(                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),                tr.data_size,                reinterpret_cast<const size_t*>(tr.data.ptr.offsets),                tr.offsets_size/sizeof(size_t), freeBuffer, this);                        const pid_t origPid = mCallingPid;            const uid_t origUid = mCallingUid;                        mCallingPid = tr.sender_pid;            mCallingUid = tr.sender_euid;                       //调整Priority。            int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);            if (gDisableBackgroundScheduling) {                if (curPrio > ANDROID_PRIORITY_NORMAL) {                    // We have inherited a reduced priority from the caller, but do not                    // want to run in that state in this process.  The driver set our                    // priority already (though not our scheduling class), so bounce                    // it back to the default before invoking the transaction.                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);                }            } else {                if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {                    // We want to use the inherited priority from the caller.                    // Ensure this thread is in the background scheduling class,                    // since the driver won't modify scheduling classes for us.                    // The scheduling group is reset to default by the caller                    // once this method returns after the transaction is complete.                    set_sched_policy(mMyThreadId, SP_BACKGROUND);                }            }            //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);                        Parcel reply;            IF_LOG_TRANSACTIONS() {                TextOutput::Bundle _b(alog);                alog << "BR_TRANSACTION thr " << (void*)pthread_self()                    << " / obj " << tr.target.ptr << " / code "                    << TypeCode(tr.code) << ": " << indent << buffer                    << dedent << endl                    << "Data addr = "                    << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)                    << ", offsets addr="                    << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;            }            if (tr.target.ptr) {//ptr存在的情况下,                sp<BBinder> b((BBinder*)tr.cookie);//cookie是指向service对象指针,是继承BBinder的,转换为BBinder调用。                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);                if (error < NO_ERROR) reply.setError(error);            } else {//thre_context_object没有看到被set的地方,目前没有使用到。                const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);                if (error < NO_ERROR) reply.setError(error);            }                        //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",            //     mCallingPid, origPid, origUid);                        if ((tr.flags & TF_ONE_WAY) == 0) {                LOG_ONEWAY("Sending reply to %d!", mCallingPid);                sendReply(reply, 0);//发送返回信息。            } else {                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);//不需要返回值的情况。            }                        mCallingPid = origPid;            mCallingUid = origUid;            IF_LOG_TRANSACTIONS() {                TextOutput::Bundle _b(alog);                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "                    << tr.target.ptr << ": " << indent << reply << dedent << endl;            }                    }        break;
调用还是很简单的,从data中读取cookie,就是Service对象的指针,转换为BBinder对象,调用BBinder的transact函数:
status_t BBinder::transact(    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){    data.setDataPosition(0);    status_t err = NO_ERROR;    switch (code) {        case PING_TRANSACTION:            reply->writeInt32(pingBinder());            break;        default:            err = onTransact(code, data, reply, flags);            break;    }    if (reply != NULL) {        reply->setDataPosition(0);    }    return err;}
在BBinder::transact()函数中,回去调用我们在BnSampleService中重写的onTransact()函数,最终调用到SampleService::sayHello()了。

调用后,回到executeCommand()中看看sendReply()里面怎么返回的:
status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags){    status_t err;    status_t statusBuffer;    err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);    if (err < NO_ERROR) return err;        return waitForResponse(NULL, NULL);}
这里和IPCTransaction::transact()一样,调用了writeTransactionData()来组织要写给binder的binder_transaction_data数据,之后调用waitForResponse()来将数据写给binder。
注意binder返回的数据,在executeComand()中被付给了Parcel buffer这个局部对象,在buffer析构的时候,回去free掉内存,不需要我们再去释放了。

3.5.3 sayHello() client端处理reply

reply的处理这里就不说了,和前面所讲到的处理是i一样的,没有任何差别。



3.6 TF_ONE_WAY调用的差别

在前面的分析中,我们已经碰到了很多次TF_ONE_WAY这个flag,在binder中也看不到有些和正常调用不一样的处理,这边我们来写一个TF_ONE_WAY调用的接口来分下TF_ONE_WAY调用的流程上的差异。
首先在SampleService里面加了一个新的接口:

int SampleService::sayHelloAsync(const String8& clientName){    ALOGD("Async Hello to %s",clientName.string());    return 0;}
BpSampleService的实现是:

virtual int sayHelloAsync(const String8& clientName){        Parcel data,reply;        data.writeInterfaceToken(ISampleService::getInterfaceDescriptor());        data.writeString8(clientName);        remote()->transact(BnSampleService::SAY_HELLO, data, &reply,TF_ONE_WAY);        int ret = reply.readInt32();        if(NOT_ENOUGH_DATA == ret)            ALOGD("for async mode ,there is no reply ~~");        else            ALOGD("sayHelloAsync return %d",ret);        return 0;    }

3.6.1 client调用过程
在IPCThreadState::transact()中的流程有差异,调用waitForResponse()的reply为NULL:
err = waitForResponse(NULL, NULL);
之后还是调用talkWithDriver()去和binder交互,看看binder部分的差别,我们看有判断TF_ONE_WAY部分的代码就可以了。
binder_transaction()中差异:
if (!reply && !(tr->flags & TF_ONE_WAY))        t->from = thread;//同步transaction的时候,记录from。    else        t->from = NULL;//异步transaction或者reply时候,不需要记录from了。
异步模式的时候,不会在binder_transaction中记录from的thread。



t->buffer = binder_alloc_buf(target_proc, tr->data_size,        tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
申请binder_buffer的时候,异步模式申请的时候,最后一个参数is_async是为true的,看下binder_alloc_buffer中对于is_async的处理的差异:
if (is_async &&        proc->free_async_space < size + sizeof(struct binder_buffer)) {        binder_debug(BINDER_DEBUG_BUFFER_ALLOC,                 "%d: binder_alloc_buf size %zd failed, no async space left\n",                  proc->pid, size);        return NULL;    }
    buffer->async_transaction = is_async;    if (is_async) {        //update free_async_space        proc->free_async_space -= size + sizeof(struct binder_buffer);        binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,                 "%d: binder_alloc_buf size %zd async free %zd\n",                  proc->pid, size, proc->free_async_space);    }
异步模式下,要检测和更新free_async_space空间,另外就是影响了binder_buffer中的async_transaction的flag。
从这里我们可以看出来free_async_space是对于async调用的一个限制,使用的空间不能超过mmap size的一半。


if (reply) {        BUG_ON(t->buffer->async_transaction != 0);        //清除掉binder_tranasaction发起thread的transaction_stack。        binder_pop_transaction(target_thread, in_reply_to);    } else if (!(t->flags & TF_ONE_WAY)) {//同步transaction        BUG_ON(t->buffer->async_transaction != 0);        t->need_reply = 1;        //transaction_stack指向当前thread的最后一个binder_transaction,通过from_parent进行链接。        t->from_parent = thread->transaction_stack;        thread->transaction_stack = t;    } else {//异步transaction        BUG_ON(target_node == NULL);        BUG_ON(t->buffer->async_transaction != 1);        if (target_node->has_async_transaction) {            target_list = &target_node->async_todo;            target_wait = NULL;        } else            target_node->has_async_transaction = 1;    }
这边TF_ONE_WAY,在这里有比较重大的影响,如果当前没有异步调用的时候,只是设置target_node的has_async_transaction为1,否则的话,为更改target_list为target_node的async_todo,而不是原来的thread/proc的todo list。


之后进入binder_thread_read(),client端在这里是read了BR_TRANSACTION_COMPLETE command后,返回user层,在IPCThreadState::waitForResponse()中进行BR_TRANSACTION_COMPLETE的处理:

case BR_TRANSACTION_COMPLETE:            if (!reply && !acquireResult) goto finish;            break;
这里我们看到了差异,在异步模式下,reply和acquireResult都是NULL,这里会直接进入finish的代码段,这样waitForResponse()函数就返回了到了我们BpSampleService::sayHelloAsync()中了,这里的reply中没有写入任何的数据。

到这里,client调用已经完全结束了,我们可以清楚看到了异步调用下,我们只是发出command后就退出了,并不会等待service返回BR_REPLY的信息。

3.6.2 service的响应
SampleService还是从binder_thread_read()中读取command:

       if (t->buffer->target_node) {//transaction cmd时候。            //对于binder_context_mgr_node,ptr和cookie都为0。            //对于一般service来说,binder_node中的ptr是service的weakrefs指针,cookie是service的对象指针。(见Parcel中的flatten_binder())            struct binder_node *target_node = t->buffer->target_node;            tr.target.ptr = target_node->ptr;            tr.cookie =  target_node->cookie;            t->saved_priority = task_nice(current);            //同步模式下设置priority            if (t->priority < target_node->min_priority &&                !(t->flags & TF_ONE_WAY))                binder_set_nice(t->priority);            else if (!(t->flags & TF_ONE_WAY) ||                 t->saved_priority > target_node->min_priority)                binder_set_nice(target_node->min_priority);            cmd = BR_TRANSACTION;        } else {//reply cmd时候,reply时候target_node为null。            tr.target.ptr = NULL;            tr.cookie = NULL;            cmd = BR_REPLY;        }
同步模式下,将client的priority传递给service端。异步模式下,不需要传递,因为client不会等待service的reply。


        //记录sender_pid。        //异步模式,或者reply情况下,t->from == 0.        if (t->from) {            struct task_struct *sender = t->from->proc->tsk;            tr.sender_pid = task_tgid_nr_ns(sender,                            task_active_pid_ns(current));        } else {            tr.sender_pid = 0;        }
t->from是client在binder_transaction()中设置的,对于异步模式下,from为NULL。from在这里影响了binder_thread_read()中记录sender_pid,我们后面在user层处理中看到sender_pid。


       if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {            //同步模式下更新stack信息,binder_transaction t会在reply时候在binder_transaction()中pop掉。            t->to_parent = thread->transaction_stack;            t->to_thread = thread;            thread->transaction_stack = t;//把最近读到的binder_transaction设置为transaction_stack        } else {//异步模式,或者reply时,binder_transaction已经不需要了            //(reply时候才需要通过binder_transaction找到reply的target thread),在这里直接释放掉。            t->buffer->transaction = NULL;            kfree(t);            binder_stats_deleted(BINDER_STAT_TRANSACTION);        }
异步模式时候,binder_transaction没有记录到thread->transaction_stack中去,而是直接释放了。因为service不会发送reply信息,也不需要binder_transaction了。

从binder_thread_read()中返回后,回到user层处理读取到的BR_TRANSACTION:

            //client的pid和uid。在异步模式下的时候为0。            mCallingPid = tr.sender_pid;            mCallingUid = tr.sender_euid;
异步模式的时候,这里的sender_pid为0,而不是client的真实pid。

另外差异就在于reply的发送,同步模式会发送BC_REPLY给binder,但是对于异步模式来说我们什么都不需要做了。

除去reply之外,我们还要看下freebuffer的处理,Parcel data析构会去调用IPCThreadState::freeBuffer()去发送BC_FREE_BUFFER给binder,我们到binder_thread_write()中看看:

          //异步操作的时候,work会被加入到async_todo的list中,在free时候,把下一个work挪到thread的todo中去。           if (buffer->async_transaction && buffer->target_node) {                BUG_ON(!buffer->target_node->has_async_transaction);                if (list_empty(&buffer->target_node->async_todo))                    buffer->target_node->has_async_transaction = 0;                else                    list_move_tail(buffer->target_node->async_todo.next, &thread->todo);            }
这部分代码和之前binder_transaction()中的代码是呼应的,

        if (target_node->has_async_transaction) {            target_list = &target_node->async_todo;            target_wait = NULL;        } else            target_node->has_async_transaction = 1;
当前的target_node中有异步操作在执行的时候,work加入到了binder_node.async_todo的list中去,当一个async操作完成的时候,再从async_todo中拿出一个新的work加入到thread的todo list中去。
这样的操作逻辑,让异步操作是在一个thread中去完成,因为异步操作的client不会等待,不需要尽快的返回,可以空出更多的thread给同步操作使用。

接着我们看看释放binder_buffer的函数binder_free_buf():

    if (buffer->async_transaction) {        proc->free_async_space += size + sizeof(struct binder_buffer);        binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,                 "%d: binder_free_buf size %zd async free %zd\n",                  proc->pid, size, proc->free_async_space);    }
和申请的时候一样,需要更新一下free_async_space的值。这里我们已经看出来free_async_space是异步操作所能申请的buffer的最大size,每次异步操作申请的时候,会在free_async_space中减掉,而在释放的时候,会增加free_async_space。
free_async_space的最大值是mmap size的一半,也就是说binder要求至少保留一半的内存给同步操作去使用。


3.6.3 小结
异步操作的流程我们已经看完了,差异主要是:
1,client发出异步操作后,直接返回,不等待service reply。
2,client发给service的work,在service在处理其他异步操作时候,会被加入到binder_node.async_todo中去,而不是thread/proc的todo中。
4,client发给service的binder_transaction结构,在service read的时候,会直接释放。
5,client传给service的sender_pid为0。
6,service不会发送BC_REPLY给binder。
7,处理BC_FREE_BUFFER时会检测async_todo是否还有work,如果有,会挪到thread.todo中去执行。



3.7 DeathRecipient调用的分析
在第二章编写SampleService的时候,我们在client调用中调用了linkToDeath()去注册service的died的notification,但是实际跑起来之后,这个callback没有被调用到。
我们这里分析下代码,这个回调是怎么工作的,为什么我们的注册没有工作起来。

client中注册的动作如下:

    DeathCallBack* deathCb = new DeathCallBack();    sampleSrv->asBinder()->linkToDeath(deathCb);
调用了BpBinder::linkToDeath()

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) {//判断BpBinder是否已经die。            if (!mObituaries) {//构造一个vector来保存注册的DeathRecipient,并发送BC_REQUEST_DEATH_NOTIFICATION给binder。                mObituaries = new Vector<Obituary>;                if (!mObituaries) {                    return NO_MEMORY;                }                ALOGV("Requesting death notification: %p handle %d\n", this, mHandle);                getWeakRefs()->incWeak(this);                IPCThreadState* self = IPCThreadState::self();                self->requestDeathNotification(mHandle, this);                self->flushCommands();            }            ssize_t res = mObituaries->add(ob);//把注册的DeathRecipient加入到mObituaries。            return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;        }    }    return DEAD_OBJECT;}
在这里,注册的DeathRecipient是被加入到了mObituaries这个vector里面去了,没有直接传递给binder。
mObituaries创建时候,通过函数requestDeathNotificaiton(),写了一个command 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;}
这个command在flushCommands()中被写入到binder :

void IPCThreadState::flushCommands(){    if (mProcess->mDriverFD <= 0)        return;    talkWithDriver(false);//false表明不会读取command,只是去写command。}

之后在binder中处理BC_REQUEST_DEATH_NOTIFICATION,之前我们在分析addService()的时候,已经看到了这个command的处理,主要行为就是为当前的binder_ref创建了了一个binder_ref_death对象。


但是我们的问题还没有解决,当service挂掉的时候,是如何被通知到的呢?考service异常退出的时候是不会来得及去和binder做交互的,那么一定是系统帮忙做了什么。
再想到当进程异常退出的时候,系统会帮助我们做file的flush,release的动作来回收资源,binder对于系统来说一样也是个file,所以也会做一样的处理,所以我们关注一下binder_flush()和binder_release():

static int binder_flush(struct file *filp, fl_owner_t id){    struct binder_proc *proc = filp->private_data;    if(proc->bLogDbg)        printk("Process %d called flush \n",proc->pid);    binder_defer_work(proc, BINDER_DEFERRED_FLUSH);    return 0;}
这里调用了binder_defer_work():

static voidbinder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer){    mutex_lock(&binder_deferred_lock);    proc->deferred_work |= defer;//记录defer work的flag。    if (hlist_unhashed(&proc->deferred_work_node)) {        hlist_add_head(&proc->deferred_work_node,                &binder_deferred_list);        //将binder_deferred_work放到binder_deferred_workqueue中去。        queue_work(binder_deferred_workqueue, &binder_deferred_work);    }    mutex_unlock(&binder_deferred_lock);}
所以flush()中,在proc的deferred_work中设上了BINDER_DEFERRED_FLUSH,并在binder_deferred_workqueue中加入了一个新的work。
binder_deferred_workqueue是binder在binder_init()中建立的一个workqueue,任务放到bufferqueue中会被逐个执行。

binder_deferred_work是下面的代码声明

static DECLARE_WORK(binder_deferred_work, binder_deferred_func);
也就是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;//获取defer的值        } 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;        }        //处理binder_flush()传来的state BINDER_DEFERRED_FLUSH        if (defer & BINDER_DEFERRED_FLUSH)            binder_deferred_flush(proc);        //处理binder_release()传来的state BINDER_DEFERRED_RELEASE        if (defer & BINDER_DEFERRED_RELEASE)            binder_deferred_release(proc); /* frees proc */        binder_unlock(__func__);        if (files)            put_files_struct(files);    } while (proc);}
最终我们调用了binder_deferred_flush(),

static void binder_deferred_flush(struct binder_proc *proc){    struct rb_node *n;    int wake_count = 0;    //让进程所有等待的thread都立刻返回出去。    for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) {        struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node);        thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;        if (thread->looper & BINDER_LOOPER_STATE_WAITING) {            wake_up_interruptible(&thread->wait);            wake_count++;        }    }    wake_up_interruptible_all(&proc->wait);    binder_debug(BINDER_DEBUG_OPEN_CLOSE,             "binder_flush: %d woke %d threads\n", proc->pid,             wake_count);}
这个函数中让所有等待的thread,都从等待中退出出去(BINDER_LOOPER_STATE_NEED_RETURN会让thread从binder_thread_read中直接返回出去,即使没有读到任何东西)。


继续看下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;}
和binder_flush()基本一样,只是push的work的state是BINDER_DEFERRED_RELEASE,看看这个类型在binder_deferred_func()中的处理,

        //处理binder_release()传来的state BINDER_DEFERRED_RELEASE        if (defer & BINDER_DEFERRED_RELEASE)            binder_deferred_release(proc); /* frees 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);    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;    }    threads = 0;    active_transactions = 0;    //清除所有的binder_thread对象。    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);    }    nodes = 0;    incoming_refs = 0;    //release所有的binder_node对象的资源,当进程中有多个serivce的时候,会有多个binder_node。    //注意这里只是对binder_node做release动作,并不是delete掉binder_node的对象,这个对象因为client还在引用,所以暂时不会被删除。    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);    }    outgoing_refs = 0;    //清除当前进程的reference。    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);    }    //清除两个list。    binder_release_work(&proc->todo);    binder_release_work(&proc->delivered_death);    buffers = 0;    //释放掉已经申请的binder_buffer。    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);    //释放mmap的物理page。    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);    kfree(proc);}
这里我们重点关注一下binder_node的release,这个会设计到client端的binder_ref的处理,

static int binder_node_release(struct binder_node *node, int refs){    struct binder_ref *ref;    int death = 0;    list_del_init(&node->work.entry);    binder_release_work(&node->async_todo);    if (hlist_empty(&node->refs)) {        kfree(node);        binder_stats_deleted(BINDER_STAT_NODE);        return refs;    }    node->proc = NULL;//将proc置空,binder_proc在release之后不会存在了,但是binder_node不会被delete。    node->local_strong_refs = 0;    node->local_weak_refs = 0;    hlist_add_head(&node->dead_node, &binder_dead_nodes);//加入到binder_dead_nodes中去。    //遍历node对应的所有的binder_ref对象。    hlist_for_each_entry(ref, &node->refs, node_entry) {        refs++;        if (!ref->death)            continue;        death++;        if (list_empty(&ref->death->work.entry)) {//在client的proc.todo中加入BINDER_WORK_DEAD_BINDER work.            ref->death->work.type = BINDER_WORK_DEAD_BINDER;            list_add_tail(&ref->death->work.entry,                      &ref->proc->todo);            wake_up_interruptible(&ref->proc->wait);        } else            BUG();    }    binder_debug(BINDER_DEBUG_DEAD_BINDER,             "node %d now dead, refs %d, death %d\n",             node->debug_id, refs, death);    return refs;}
在这里,binder_node.proc被reset为NULL,遍历了所有的binder_ref,如果binder_ref.death非空,会在binder_ref所在的proc中加入BINDER_WORK_DEAD_BINDER的work。
binder_ref.death正是我们在BC_REQUEST_DEATH_NOTIFICATION中为binder_ref创建的。

这里我们已经看出问题了,client在没有和binder交互的情况下,是不可能处理到BINDER_WORK_DEAD_BINDER这个work的。所以我们在client这段也需要调用一下IPCThreadState::joinThreadPool()。


我们假设已经建立了一个thread的情况继续往下分析。
回到SampleService的client端来,当SampleService挂掉之后,client的todo中有了一个BINDER_WORK_DEAD_BINDER的work。

        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;            //获取binder_ref_death对象。            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;            //写回cmd。            if (put_user(cmd, (uint32_t __user *)ptr))                return -EFAULT;            ptr += sizeof(uint32_t);            if (put_user(death->cookie, (void * __user *)ptr))                return -EFAULT;            ptr += sizeof(void *);            binder_stat_br(proc, thread, cmd);            binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,                     "%d:%d %s %p\n",                      proc->pid, thread->pid,                      cmd == BR_DEAD_BINDER ?                      "BR_DEAD_BINDER" :                      "BR_CLEAR_DEATH_NOTIFICATION_DONE",                      death->cookie);            if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {                list_del(&w->entry);                kfree(death);                binder_stats_deleted(BINDER_STAT_DEATH);            } else//加入到delivered_death list                list_move(&w->entry, &proc->delivered_death);            if (cmd == BR_DEAD_BINDER)                goto done; /* DEAD_BINDER notifications can cause transactions */        } break;
这里向user层写回了command BR_DEAD_BINDER,并把当前的work加入到delivered_death list中去。

回到user层后,处理BR_DEAD_BINDER,

         case BR_DEAD_BINDER:        {            BpBinder *proxy = (BpBinder*)mIn.readInt32();            proxy->sendObituary();//调用注册的death callback.            mOut.writeInt32(BC_DEAD_BINDER_DONE);//写回BC_DEAD_BINDER_DONE,告诉binder已经处理完毕。            mOut.writeInt32((int32_t)proxy);        } break;
这里调用了BpBinder::sendObituary(),

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) {        ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);        IPCThreadState* self = IPCThreadState::self();        self->clearDeathNotification(mHandle, this);//写BC_CLEAR_DEATH_NOTIFICATION command给binder。        self->flushCommands();        mObituaries = NULL;    }    mObitsSent = 1;    mLock.unlock();    ALOGV("Reporting death of proxy %p for %d recipients\n",        this, obits ? obits->size() : 0);    if (obits != NULL) {        const size_t N = obits->size();        for (size_t i=0; i<N; i++) {//调用注册在vector中的DeathRecipient。            reportOneDeath(obits->itemAt(i));        }        delete obits;    }}
我们注册的DeathRecipient就是保存在了mObituaries这个vecotor,在函数最后的for 循环中,每个注册的DeathRecipient最终被执行。

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);}

处理完BR_DEAD_BINDER之后,client又向binder中写了两个command,BC_CLEAR_DEATH_NOTIFICATION 和 BC_DEAD_BINDER_DONE,再进入binder中看这两个command的处理。
BC_CLEAR_DEATH_NOTIFICATION在binder_thread_write()中是和BC_REQUEST_DEATH_NOTIFICATION在一个case中处理的,他们的处理是相反的, BC_REQUEST_DEATH_NOTIFICATION为当前的binder_ref建立了一个新的binder_ref_death对象,而BC_CLEAR_DEATH_NOTIFICATION是清除了当前的binder_ref.death指针:

} else {                if (ref->death == NULL) {                    binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n",                        proc->pid, thread->pid);                    break;                }                death = ref->death;                if (death->cookie != cookie) {                    binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %p != %p\n",                        proc->pid, thread->pid,                        death->cookie, cookie);                    break;                }                ref->death = NULL;//清除binder_ref中的death指针。                if (list_empty(&death->work.entry)) {//death work没有被加入到某个list中,也就是service died还没有被触发。                    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已经被加入到list中,也就是 service died已经触发了,修改work type。                    BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER);                    death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR;                }            }
这边根据death work有没有被加入处理的list(也就是对应的service die是否已经出发)来分成两个case分别去看,我们现在的走的else中的流程,在这里death.work(注意这个work是在death.delivered_death这个list中)被修改成了BINDER_WORK_DEAD_BINDER_AND_CLEAR。

之后,binder继续处理BC_DEAD_BINDER_DONE这个command,

case BC_DEAD_BINDER_DONE: {            struct binder_work *w;            void __user *cookie;            struct binder_ref_death *death = NULL;            if (get_user(cookie, (void __user * __user *)ptr))                return -EFAULT;            ptr += sizeof(void *);            list_for_each_entry(w, &proc->delivered_death, entry) {//根据cookie(user层的BpBinder指针)查找到对应的binder_ref_death。                struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);                if (tmp_death->cookie == cookie) {                    death = tmp_death;                    break;                }            }            binder_debug(BINDER_DEBUG_DEAD_BINDER,                     "%d:%d BC_DEAD_BINDER_DONE %p found %p\n",                     proc->pid, thread->pid, cookie, death);            if (death == NULL) {                binder_user_error("%d:%d BC_DEAD_BINDER_DONE %p not found\n",                    proc->pid, thread->pid, cookie);                break;            }            list_del_init(&death->work.entry);//从deliver_death list中删除当前的work。            if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) {                death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;//发送BINDER_WORK_CLEAR_DEATH_NOTIFICATION work去清除death。                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);                }            }        } break;

这边从delivered_death list中删除了death的work,又发了一个新的work BINDER_WORK_CLEAR_DEATH_NOTIFICATION给当前的进程。

从binder_thread_write()中退出后binder在binder_thread_read()中会接受到BINDER_WORK_CLEAR_DEATH_NOTIFICATION进行处理,这个command和前面的BINDER_WORK_DEAD_BINDER是一个case中处理,主要行为,

            if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)                cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;            else                cmd = BR_DEAD_BINDER;
            if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {                list_del(&w->entry);                kfree(death);                binder_stats_deleted(BINDER_STAT_DEATH);            }
这里又回复给user层一个BR_CLEAR_DEATH_NOTIFICATION_DONE的command,并且释放了之前申请的binder_ref_death对象。
BR_CLEAR_DEATH_NOTIFICATION_DONE在user层处理:

case BR_CLEAR_DEATH_NOTIFICATION_DONE:        {            BpBinder *proxy = (BpBinder*)mIn.readInt32();            proxy->getWeakRefs()->decWeak(proxy);        } break;
就是对BpBinder做了decrease weak的动作,这个是和BpBinder::linkToDeath()中的下列代码呼应的。
getWeakRefs()->incWeak(this);

到这,整个DeathRecipient的流程就结束了,我们从中也看到了death的回调整个流程是需要client不停的和binder去交互的,所以我们在client中要也要加上IPCThreadState::joinThreadPool()才行。对client的main函数做如下修改后,我们的deathcallback就可以被调用到了。

#if 0    do{        sleep(2);        if(deathCalled){            ALOGE("death callback called\n");            break;        }    }while(1); #else    IPCThreadState::self()->joinThreadPool(true); #endif


四,binder总结

基本上所有的点在上面已经都分析到了。这里list下kernel中的关键对象:
binder_proc:和user层ProcessState对应。
binder_thread:和user层IPCThreadState对应。
binder_node:service在binder中的代表。
binder_ref:client在binder中的代表。
binder_work:传递信息的表达。
binder_proc/binder_thread.todo:维护binder_work,用来传递信息的重要对象。


End!

-------------------------------------------

by sky
0 0
原创粉丝点击