Server Manager 的启动

2016-5-27 chenhui Binder

SM 也是一个应用程序,所以他也有 main() 函数。


int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;
	
    // 打开 /dev/binder 并进行映射
    bs = binder_open(128*1024);
	
    // 把自己注册成 Binder 通信的上下文管理者
    if (binder_become_context_manager(bs)) {
        LOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
    // 开始等待 Client 发来的请求
    binder_loop(bs, svcmgr_handler);
    return 0;
}


binder_open() 的代码就不贴了,总之就是打开 /dev/binder,这样他会在 Binder 驱动中创造出一些数据结构并得到一个句柄,然后他再映射他,映射会导致 Binder 驱动会为他申请一个保存通信数据的缓冲区。


binder_become_context_manager() 把自己注册成上下文管理者,只有注册了,他才能成为真正的 SM。他的代码很简单:



int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}


调用 ioct() 传入 BINDER_SET_CONTEXT_MGR 就能成功注册。


最后就是 binder_loop(),这个就简单了,在本博客的另一篇 Binder 通信流程之详细分解 中讲到过 Server 的处理流程。其实 binder_loop() 干的就是这种事。


相信下面的代码不需要我详细解释也能看懂:



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

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;
    
    // 把 BC_ENTER_LOOPER 命令传输给 Binder 驱动
    // 这表示把自己注册成 Binder 线程,这样 Client 才能找到线程来传递数据
    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(unsigned));

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;

	// 开始等待 Client 传来传来工作项,取出其中的数据到输入缓冲区
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

	...
	// 解析并处理 Client 传来的通信数据
        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
        ..
    }
}






发表评论:

Copyright ©2015-2016 freehui All rights reserved