Binder native层源码分析(七):BBinder

Binder驱动部分的主要内容已经基本分析完了,现在回到native层,把之前源码分析三中未分析的部分拿出来分析一遍,注意目的是说明BBinder的作用。我把这一部分内容放在这里分析其实是有原因的,因为如果不理解Binder驱动部分的内容,那么肯定很难理解waitForResponse后面对接收到协议的处理

源码分析三我们分析了waitForResponse中发送数据的部分,我们接着看waitForResponse的后半部分。分析后半部分时,我们不能用前面服务向sm注册或客户向sm请求为例进行分析,我们必须设想另一个场景才能讲清楚BBinder的作用。

设想一下这种情形,客户端已经取得了服务端,并且向服务端发送了请求,请求的协议为BR_TRANSACTION。现在服务端准备接收这个请求,并作出处理。

waitForResponse分段2

while(1){
	//...talkWithDriver将请求读取到mIn,这部分代码略过。
	cmd = (uint32_t)mIn.readInt32();
	switch (cmd) {
		//...对case的处理,略去
		default:
		    err = executeCommand(cmd);
		    if (err != NO_ERROR) goto finish;
		    break;
	}
}

调用完talkWithDriver之后,当检查到mIn中有值时,从mIn中读取协议cmd。下面的switch case和executeCommand的作用根据协议进行相应的处理。而对BR_TRANSACTION的处理在executeCommand中。

executeCommand对BR_TRANSACTION的处理

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;
    
    switch ((uint32_t)cmd) {
    //...
    case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));//从mIn中读出binder_transaction_data
            ALOG_ASSERT(result == NO_ERROR,
                "Not enough command data for brTRANSACTION");
            if (result != NO_ERROR) break;
            
            Parcel buffer;
            //将tr恢复成Parcel
            buffer.ipcSetDataReference(
                reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                tr.data_size,
                reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
            
            const pid_t origPid = mCallingPid;
            const uid_t origUid = mCallingUid;
            const int32_t origStrictModePolicy = mStrictModePolicy;
            const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;

            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            mLastTransactionBinderFlags = tr.flags;

            int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
            if (gDisableBackgroundScheduling) {
                if (curPrio > ANDROID_PRIORITY_NORMAL) {
                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
                }
            } else {
                if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
                    set_sched_policy(mMyThreadId, SP_BACKGROUND);
                }
            }
            Parcel reply;
            status_t error;
            if (tr.target.ptr) {
                if (reinterpret_cast<RefBase::weakref_type*>(
                        tr.target.ptr)->attemptIncStrong(this)) {
                     //注意这个调用
                    error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);
                    reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
                } else {
                    error = UNKNOWN_TRANSACTION;
                }

            } else {
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }
            if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                if (error < NO_ERROR) reply.setError(error);
                sendReply(reply, 0);
            } else {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
            }
            
            mCallingPid = origPid;
            mCallingUid = origUid;
            mStrictModePolicy = origStrictModePolicy;
            mLastTransactionBinderFlags = origTransactionBinderFlags;
            
        }
        break;

忽略具体实现的细节,我们大致可以知道在对BR_TRANSACTION的处理中,首先是从mIn中读取数据恢复binder_transaction_data tr,然后再构造出Parcel Buffer,其实就是前面数据发送的逆过程,同样用一张图总结如下:
在这里插入图片描述
executeCommand中最重要的是下面这条语句。

error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);

这个cookie值是什么?答案就在源码分析五中对binder_thread_read的分析中。截取部分代码如下:

		if (t->buffer->target_node) {
		//得到sm对应的binder_node
			struct binder_node *target_node = t->buffer->target_node;
			struct binder_priority node_prio;
		//根据上篇博文的分析我们知道,ptr和cookie指向服务类
			tr.target.ptr = target_node->ptr;
			tr.cookie =  target_node->cookie;//注意这里对cookie进行赋值

当target_node不为空时,cookie值等于target_node的cookie。在源码分析四中我们知道,binder_node的cookie等于obj的cookie,而在源码分析二中我们知道,obj的cookie等于服务类例如MediaPlayerService的指针。

所以传递的数据包Parcel就交给了服务类的transact函数。而服务类是BBinder的派生类,也就相当于交给了BBinder的transact处理。

BBinder

//\frameworks\native\libs\binder\Binder.cpp
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;
}

又将数据交给了onTransact函数,onTransact都是虚函数,所以实际上处理数据的是BBinder继承者的onTransact()。比如BnMediaPlayerService的onTransact():

// \frameworks\av\media\libmedia\IMediaPlayerService.cpp
status_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        case CREATE: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            sp<IMediaPlayerClient> client =
                interface_cast<IMediaPlayerClient>(data.readStrongBinder());
            audio_session_t audioSessionId = (audio_session_t) data.readInt32();
            sp<IMediaPlayer> player = create(client, audioSessionId);
            reply->writeStrongBinder(IInterface::asBinder(player));
            return NO_ERROR;
        } break;
    //...

onTransact()就是根据code的值调用不同的函数。正如前面在分析BpBinder的transact函数时所提到的,code的值决定BBinder受到数据后会做什么样的处理。从这里就可以看出Binder通信其实就是远程过程调用的过程。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值