android binder机制,注册系统服务--服务端servicemanager binder驱动

3 服务端servicemanager binder驱动

前面分析过Servicemanager进程中的main方法步骤,

1,调用binder_open方法打开binder驱动。

2,调用binder_become_context_manager方法注册成为binder服务的大管家。

3,调用binder_loop方法进入无限循环, 处理binder驱动发来的请求。

 

其中binder_loop调用流程图如下,


3.1 读取驱动信息

binder.c的binder_loop方法如下,

void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

readbuf[0] = BC_ENTER_LOOPER;
//将BC_ENTER_LOOPER命令发送给binder驱动
    binder_write(bs, readbuf, sizeof(uint32_t));

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
         // 读取驱动的命令
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }
         // 解析命令
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}

binder_loop方法主要分为3个阶段,

1,首先调用binder_write方法向binder驱动发送BC_ENTER_LOOPER命令, 告诉binder驱动“本线程要进入循环

状态了”。

2,然后调用ioctl方法读取binder驱动信息。

3,读取驱动信息之后,调用binder_parse方法进行解析。

其中第二步在Servicemanager进程那一章节中也详细论述了,已经在binder驱动的binder_thread_read方法中处

于等待状态了,上一章唤醒就是指唤醒该线程, 继续执行binder_thread_read方法,这个地方比较难懂,有点晦涩,

但是是关键点。

通俗的讲,逻辑原理如下,

1,首先一个厨师将所有菜都买好了,但是没有炒菜,然后就去睡觉了。

2,客人来了点一个菜之后,将厨师叫醒,厨师就去炒客人需要的菜。

这其中涉及到应用进程和Servicemanager进程,用户态和内核态,通过在内核态中的内存共享的方式进行跨进程

通信。流程图如下,


应用进程传入数据时的命令是BINDER_WORK_TRANSACTION, binder_thread_read对该命令的处理如下,

1,首先获取客户进程发送过来的事务,然后复制到结构体binder_transaction_data Tr中。

case BINDER_WORK_TRANSACTION: {
	t = container_of(w, struct binder_transaction, work);
} break;
•••
if (t->buffer->target_node) {
			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 {
			tr.target.ptr = 0;
			tr.cookie = 0;
			cmd = BR_REPLY;
		}
		tr.code = t->code;
		tr.flags = t->flags;
		tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);

2,将内核态的数据复制到用户态中,此时命令是BR_TRANSACTION

tr.data_size = t->buffer->data_size;
		tr.offsets_size = t->buffer->offsets_size;
		tr.data.ptr.buffer = (binder_uintptr_t)(
					(uintptr_t)t->buffer->data +
					proc->user_buffer_offset);
		tr.data.ptr.offsets = tr.data.ptr.buffer +
					ALIGN(t->buffer->data_size,
					    sizeof(void *));

		if (put_user(cmd, (uint32_t __user *)ptr))
			return -EFAULT;
		ptr += sizeof(uint32_t);
		if (copy_to_user(ptr, &tr, sizeof(tr)))
			return -EFAULT;
		ptr += sizeof(tr);

把tr的内容拷贝到用户传进来的缓冲区去了,指针ptr指向这个用户缓冲区的地址。

这样ServiceManager进程在用户空间就真正得到了客户进程发送过来的服务注册信息。接着将客户进程

发送过来的事务项添加到当前线程的事务堆栈中,交给当前线程处理。

if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
			t->to_parent = thread->transaction_stack;
			t->to_thread = thread;
			thread->transaction_stack = t;
		} else {
			t->buffer->transaction = NULL;
			kfree(t);
			binder_stats_deleted(BINDER_STAT_TRANSACTION);
		}

binder_thread_read方法执行完成之后,回到binder_ioctl方法中,

if (bwr.read_size > 0) {
			ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
			trace_binder_read_done(ret);
			if (!list_empty(&proc->todo))
				wake_up_interruptible(&proc->wait);
			if (ret < 0) {
				if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
					ret = -EFAULT;
				goto err;
			}
		}
		
		if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
			ret = -EFAULT;
			goto err;
		}
		break;

把本地变量struct binder_write_read bwr的内容拷贝回到用户传进来的缓冲区中,就返回到用户态的binder_loop方法中,

for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
         // 读取驱动的命令
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }
         // 解析命令
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }

返回来的数据都放在readbuf中,接着调用binder_parse进行解析。

这一系列实质都是binder_loop方法由用户态到内核态的逆过程。有点难懂,所以要反复折腾。

3.2 解析信息

binder_parse方法中会处理各种类型的消息,现在主要看BR_TRANSACTION类型消息的处理,主要包含服务的注册和获取。

相关代码如下,

case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                ALOGE("parse: txn too small!\n");
                return -1;
            }
            binder_dump_txn(txn);
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;

                bio_init(&reply, rdata, sizeof(rdata), 4);
                bio_init_from_txn(&msg, txn); //从txn解析出binder_io信息
                res = func(bs, txn, &msg, &reply);
                binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
            }
            ptr += sizeof(*txn);
            break;
        }

1,首先从txn解析出binder_io信息。

2,回调svcmgr_handler方法进行处理,func指向的是service_manager.c中的svcmgr_handler方法,binder驱动的

  请求会回调该方法。

3,处理完成之后通知处理结果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值