Binder机制原理学习笔记(4)_ServiceManager启动Binder分析

ServiceManager启动Binder

在Framwork源码解析(1)_Zygote进程启动流程一文中了解过,Android系统启动Zygote进程然后创建SystemService,再创建其他服务进程,ServiceManager 进程也是在这里启动的。查看/system/core/rootdir/init.rc源码,可以找到启动servicemanager:
Binder机制原理学习笔记(4)_ServiceManager启动Binder分析_第1张图片
这里启动的是/frameworks/native/cmds/servicemanager下的service_manager.c文件,此目录下还有servicemanager.rc配置,就是被zygote启动的。
查看service_manager.c源码的main方法:

int main(int argc, char** argv){
	// ......
    if (argc > 1) {
        driver = argv[1];
    } else {
    	// 设置默认binder驱动文件路径
        driver = "/dev/binder";
    }
	// 打开binder文件,并设置映射文件大小为128KB
    bs = binder_open(driver, 128*1024);
    // 成为上下文管理者
    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }
	// ......
	// 开启binder循环
    binder_loop(bs, svcmgr_handler);
    return 0;
}

主要做了三件事:

  • 设置默认binder驱动文件路径,root过的手机可以在/dev/binder目录下找到Binder驱动文件
  • 打开binder驱动:binder_open
  • 将ServiceManager注册成为 binder 服务管理者:binder_become_context_manager
  • 开启binder循环:binder_loop

binder_open

找到同级目录下的frameworks/native/cmds/servicemanager/binder.c文件,该文件中找到binder_open方法:

struct binder_state *binder_open(const char* driver, size_t mapsize)
{
    struct binder_state *bs;
    struct binder_version vers;
    // 动态分配内存
    bs = malloc(sizeof(*bs));
    // 打开驱动文件,将文件句柄也就是c++的指针引用传给bs结构体的fd
    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    // 系统调用
    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        fprintf(stderr,
                "binder: kernel driver version (%d) differs from user space version (%d)\n",
                vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
        goto fail_open;
    }

    bs->mapsize = mapsize;
    // 创建映射,mmap函数能够将用户空间的一段内存区域映射到内核空间,用户对该段内存的修改能直接反映到内核空间,
    // 相反,内核空间的改动也可以映射到用户空间,这里将/dev/binder映射到内核空间,并赋值给bs的mapped属性,大小是128KB
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    return bs;
}
  1. bs = malloc(sizeof(*bs));
    动态分配内存
  2. bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    打开驱动文件,将文件句柄也就是c++的指针引用传给bs结构体的fd
  3. ioctl(bs->fd, BINDER_VERSION, &vers)
    ioctl(input/output control)是一个专用于设备输入输出操作的系统调用,该调用传入一个跟设备有关的请求码,系统调用的功能完全取决于请求码。ioctl 是设备驱动程序中设备控制接口函数,一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。
    详情可查看:https://blog.csdn.net/qq_19923217/article/details/82698787
  4. bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    创建映射,mmap函数能够将用户空间的一段内存区域映射到内核空间,用户对该段内存的修改能直接反映到内核空间,相反,内核空间的改动也可以映射到用户空间,这里将/dev/binder映射到内核空间,并赋值给bs的mapped属性,大小是128KB。
    注: 为什么是128KB?
    这里有个小知识,磁盘的写入单位是4KB,未到4KB的会把数据放到缓存中,等满足4KB的时候再写入磁盘,所以设置写入磁盘的大小要满足是4KB的整数倍。

binder_become_context_manager

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

源码中通过系统调用将"/dev/binder"驱动的引用传给驱动层,命令符是BINDER_SET_CONTEXT_MGR

binder_loop

1、开启binder循环

void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    // 32位,2的32次方就是128kb
    uint32_t readbuf[32];

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

    readbuf[0] = BC_ENTER_LOOPER;
    // 重置操作,将文件清空
    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);
		// 解析binder内容
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);    
    }
}

2、查看binder_parse源码,源码路径/frameworks/native/cmds/servicemanager/binder.c

int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    while (ptr < end) {
     	// ....
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            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);
                // 执行回调处理函数,将处理结果返回
                res = func(bs, txn, &msg, &reply);
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                	// 向binder驱动发送执行结果
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
            }
            ptr += sizeof(*txn);
            break;
        }
    }

    return r;
}

这里执行完回调函数res = func(bs, txn, &msg, &reply);并把结果发送binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);,再找到binder_send_reply方法:

void binder_send_reply(struct binder_state *bs,
                       struct binder_io *reply,
                       binder_uintptr_t buffer_to_free,
                       int status)
{
   // ....
    binder_write(bs, &data, sizeof(data));
}

这里又走到了binder_write方法:

int binder_write(struct binder_state *bs, void *data, size_t len)
{
    struct binder_write_read bwr;
    int res;

    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (uintptr_t) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
     // 向驱动文件写入数据,read_size = 0,也就是向驱动层写入数据,BINDER_WRITE_READ指令是读写指令,主要看read_size或wite_size谁是0
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 
    return res;
}

binder_write方法也调用了ioctl方法,命令符是BINDER_WRITE_READ,表示向驱动文件读或写入数据,read_size = 0,也就是向驱动层写入数据。

总结

  • 应用启动的时候,ServiceManager也启动,并创建驱动层文件;
  • 将ServiceManager注册成为 binder 服务管理者:binder_become_context_manager
  • 打开binder文件,创建mmap映射,并设置映射文件大小为128KB
  • 开启一个loop死循环,循环里不断的监听数据,并向驱动文件写入数据,也就是向内核空间写入数据。

https://blog.csdn.net/yiranfeng/article/details/105210069

你可能感兴趣的:(Android)