ServiceManager启动Binder

在Framwork源码解析(1)_Zygote进程启动流程一文中了解过,Android系统启动Zygote进程然后创建SystemService,再创建其他服务进程,ServiceManager 进程也是在这里启动的。查看/system/core/rootdir/init.rc源码,可以找到启动servicemanager:

这里启动的是/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

更多相关文章

  1. Android升级到2.3之后遇到的问题
  2. android 蓝牙文件
  3. Android使用xml文件中的array资源
  4. Android挂载本地硬盘为SD卡操作指南
  5. Android平台下简单Widget的搭建过程
  6. android dataBinding详解
  7. 通过Android命令自动编译出build.xml文件
  8. Android安装服务installd源码分析
  9. iperf3 arm交叉编译补充

随机推荐

  1. android单元测试 配置注意
  2. 将android应用部署到真实手机上
  3. Hello Android
  4. Android基于CGroup的memory子系统HAL层分
  5. Android调用js传过来的值,Android触发调起
  6. android上改变listView的选中颜色
  7. android中的数据库操作ZZ
  8. 系出名门Android(4) - 活动(Activity),
  9. Android 自动编译、打包生成apk文件 2 -
  10. android UI开发及常用控件