Binder native层源码分析(六):sm返回查询结果

假设现在有一个客户端向sm请求MediaPlayer服务,本篇文章分析sm怎么返回服务的查询结果,即svcmgr_handler中怎么处理SVC_MGR_GET_SERVICE请求。

处理SVC_MGR_GET_SERVICE请求

case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
    //得到服务名, 这里应该是String16("media.player")
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //从service list中找到该服务名对应的handle
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        bio_put_ref(reply, handle);
        return 0;

前面的博文已经分析了,handle值代表MediaPlayerService的binder_node对应的binder_ref的红黑树键值,这里从service list找到handle后,交给bio_put_ref处理。

bio_put_ref

void bio_put_ref(struct binder_io *bio, uint32_t handle)
{
    struct flat_binder_object *obj;

    if (handle)
        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->handle = handle;
    obj->cookie = 0;
}

根据handle值创建了一个flat_binder_object对象,类型为BINDER_TYPE_HANDLE,写入bio(即reply)的offs区域。

binder_send_reply

在上篇博文的binder_parse中我们知道,当调用完svcmgr_handler处理请求后,会调用binder_send_reply。

//binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
void binder_send_reply(struct binder_state *bs,
                       struct binder_io *reply,
                       binder_uintptr_t buffer_to_free,
                       int status)
{
    struct {
        uint32_t cmd_free;
        binder_uintptr_t buffer;
        uint32_t cmd_reply;
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;

    data.cmd_free = BC_FREE_BUFFER;//第一个协议
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY;//第二个协议
    data.txn.target.ptr = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    if (status) {
        data.txn.flags = TF_STATUS_CODE;
        data.txn.data_size = sizeof(int);
        data.txn.offsets_size = 0;
        data.txn.data.ptr.buffer = (uintptr_t)&status;
        data.txn.data.ptr.offsets = 0;
    } else {
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }
    binder_write(bs, &data, sizeof(data));
}

binder_send_reply构造了两个不同协议的数据并发送,第一个协议是BC_FREE_BUFFER,数据是本进程通信空间的地址,该空间曾被用于拷贝发送方发送的数据。由于binder_parse对数据的分析已经结束,所以这里发送BC_FREE_BUFFER协议的数据的目的应该释放这一空间。

第二个协议是BC_REPLY,数据部分是由binder_io reply填充而来的binder_transaction_data。reply中记录了handle信息。

binder_transaction分段1

前面已经分析过binder_transaction对BC_TRANSACTION的处理代码了,这里只分析binder_transaction对BC_REPLY的处理代码。

	if (reply) {
		binder_inner_proc_lock(proc);
		//在上篇博文中,binder_thread_read的结尾会把读到的t放进sm的stack中,
		//这里将其取出
		in_reply_to = thread->transaction_stack;
		if (in_reply_to == NULL) {
		//错误处理...
		}
		if (in_reply_to->to_thread != thread) {
		//错误处理...
		}
		//恢复之前的transaction_stack
		thread->transaction_stack = in_reply_to->to_parent;
		binder_inner_proc_unlock(proc);
		//取出发送进程,也就是reply的目标进程
		target_thread = binder_get_txn_from_and_acq_inner(in_reply_to);
		if (target_thread == NULL) {
			return_error = BR_DEAD_REPLY;
			return_error_line = __LINE__;
			goto err_dead_binder;
		}
		if (target_thread->transaction_stack != in_reply_to) {
		//错误处理...
		}
		target_proc = target_thread->proc;
		target_proc->tmp_ref++;
		binder_inner_proc_unlock(target_thread->proc);
	} 

从transaction_stack中找到了reply的目标线程。之后就是创建binder_transaction t并对其赋值,复制数据等,和源码分析四中分析的代码大同小异。再然后就进入了for循环处理obj,而我们传入的是BINDER_TYPE_HANDLE类型的obj,处理代码如下:

		case BINDER_TYPE_HANDLE:
		case BINDER_TYPE_WEAK_HANDLE: {
			struct flat_binder_object *fp;

			fp = to_flat_binder_object(hdr);
			ret = binder_translate_handle(fp, t, thread);
			if (ret < 0) {
				return_error = BR_FAILED_REPLY;
				return_error_param = ret;
				return_error_line = __LINE__;
				goto err_translate_failed;
			}
		} break;

读取obj后交给binder_translate_handle处理。

binder_translate_handle实现服务的传递

static int binder_translate_handle(struct flat_binder_object *fp,
				   struct binder_transaction *t,
				   struct binder_thread *thread)
{
	struct binder_proc *proc = thread->proc;//即sm的binder_proc
	struct binder_proc *target_proc = t->to_proc;//即客户端的binder_proc
	struct binder_node *node;
	struct binder_ref_data src_rdata;
	int ret = 0;
	//根据handle从sm的binder_proc中得到binder_ref,再返回binder_ref->node
	node = binder_get_node_from_ref(proc, fp->handle,
			fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata);
	if (!node) {
		binder_user_error("%d:%d got transaction with invalid handle, %d\n",
				  proc->pid, thread->pid, fp->handle);
		return -EINVAL;
	}
	if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
		ret = -EPERM;
		goto done;
	}

	binder_node_lock(node);
	//如果目标进程和node进程(服务进程)一致,则进入该if。
	//不会进入该if,跳过
	if (node->proc == target_proc) {
		if (fp->hdr.type == BINDER_TYPE_HANDLE)
			fp->hdr.type = BINDER_TYPE_BINDER;
		else
			fp->hdr.type = BINDER_TYPE_WEAK_BINDER;
		fp->binder = node->ptr;
		fp->cookie = node->cookie;
		if (node->proc)
			binder_inner_proc_lock(node->proc);
		binder_inc_node_nilocked(node,
					 fp->hdr.type == BINDER_TYPE_BINDER,
					 0, NULL);
		if (node->proc)
			binder_inner_proc_unlock(node->proc);
		trace_binder_transaction_ref_to_node(t, node, &src_rdata);
		binder_debug(BINDER_DEBUG_TRANSACTION,
			     "        ref %d desc %d -> node %d u%016llx\n",
			     src_rdata.debug_id, src_rdata.desc, node->debug_id,
			     (u64)node->ptr);
		binder_node_unlock(node);
	} else {//进入该else
		struct binder_ref_data dest_rdata;

		binder_node_unlock(node);
		//源码分析四已经分析过该函数。如果忘了建议回看,这个函数非常重要。
		ret = binder_inc_ref_for_node(target_proc, node,
				fp->hdr.type == BINDER_TYPE_HANDLE,
				NULL, &dest_rdata);
		if (ret)
			goto done;

		fp->binder = 0;
		fp->handle = dest_rdata.desc;//更新handle值为desc
		fp->cookie = 0;
		trace_binder_transaction_ref_to_ref(t, node, &src_rdata,
						    &dest_rdata);
		binder_debug(BINDER_DEBUG_TRANSACTION,
			     "        ref %d desc %d -> ref %d desc %d (node %d)\n",
			     src_rdata.debug_id, src_rdata.desc,
			     dest_rdata.debug_id, dest_rdata.desc,
			     node->debug_id);
	}
done:
	binder_put_node(node);
	return ret;
}

又见到了binder_inc_ref_for_node,源码分析四中已经分析过它了,这里它的作用就是在客户端binder_proc中创建一个binder_ref指向服务的binder_node,并找一个空闲值(desc)作为该binder_ref在红黑树中的键值。

而后desc又赋给了obj的handle成员,这样当客户端得到obj时,它就得到了binder_ref的键值,也就可以取得binder_node,进而和服务端通信。当客户端用obj的handle值构造BpBinder后,就取得了服务端,这样就实现了服务从sm到客户端的传递。

binder_transaction分段2

	if (reply) {
	//tcomple放进本线程todo队列
		binder_enqueue_thread_work(thread, tcomplete);
		binder_inner_proc_lock(target_proc);
		if (target_thread->is_dead) {
			binder_inner_proc_unlock(target_proc);
			goto err_dead_proc_or_thread;
		}
		BUG_ON(t->buffer->async_transaction != 0);
		//pop目标线程的transaction_stack
		binder_pop_transaction_ilocked(target_thread, in_reply_to);
		//把t->work放进目标线程todo队列
		binder_enqueue_thread_work_ilocked(target_thread, &t->work);
		binder_inner_proc_unlock(target_proc);
		//唤醒目标线程
		wake_up_interruptible_sync(&target_thread->wait);
		binder_restore_priority(current, in_reply_to->saved_priority);
		binder_free_transaction(in_reply_to);

很简单,就是对todo队列和transaction_stack进行更新。

总结

总结一下,服务传递给客户端的过程其实就是在客户端创建引用的过程。创建过程分为两步,第一步是要得到服务的binder_node,该binder_node可以通过sm得到,因为服务向sm注册的时候会在sm留下一个binder_ref引用。第二步是创建一个指向binder_node的binder_ref引用和键值,放进客户binder_proc的红黑树中。键值就是handle值。

上述过程决定了不同进程对同一服务的handle值是不同的。handle值说白了就是binder_ref在红黑树中的键值。每个进程都有不同的红黑树,它们的键值肯定不相同。

到这里,Binder底层实现的主要代码基本上都过完了,下一篇文章将做最后的扫尾工作,介绍BBinder。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值