失眠必读系列——ServiceManager启动流程

1,108 阅读3分钟

ServiceManager启动流程大致分以下三步:

  • binder_open(打开binder驱动,进行mmap空间映射)
  • binder_become_context_manager(注册自己为服务管家)
  • binder_loop(循环等待处理Client的请求)

源码阅读地址参考:

www.androidos.net.cn/android/10.…

WechatIMG137.png


main()

ServiceManager是init进程解析init.rc文件时启动的

/system/core/rootdir/init.rc

start servicemanager  //319行 ,启动servicemanager.rc脚本

/frameworks/native/cmds/servicemanager/servicemanager.rc

service servicemanager /system/bin/servicemanager
……

servicemanager是以服务形式启动的,启动路径/system/bin/servicemanager,对应源文件service_manager.c,找到main函数: /frameworks/native/cmds/servicemanager/service_manager.c

int main(int argc, char** argv){
    ……
    struct binder_state *bs;
    driver = "/dev/binder";
    bs = binder_open(driver, 128*1024);
    ……
    if (binder_become_context_manager(bs)) {
            ALOGE("cannot become context manager (%s)\n", strerror(errno));
            return -1;
    }
    ……
    binder_loop(bs, svcmgr_handler);
}

我们可以看到三个主要函数:

  • binder_open打开binder设备文件/dev/binder,函数会返回映射的地址和空间,保存在binder_state类型的bs对象中
  • binder_become_context_manager将自己注册为servicemanager, handle为0,其他Client可以通过这个0号引用获取到Service Manager
  • binder_loop循环等待+处理 Client 请求(Service注册请求+代理对象获取请求)

binder_open

/frameworks/native/cmds/servicemanager/binder.c

struct binder_state{
    int fd;//文件描述符
    void *mapped;//起始地址
    size_t mapsize;//空间大小
};

struct binder_state *binder_open(const char* driver, size_t mapsize{
    ……
    bs = malloc(sizeof(*bs));
    ……
    //其中bs的类型为binder_state
    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    ……
    bs->mapsize = mapsize;
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    ……
}
  • 调用binder.c的binder_open,函数内部调用open打开设备文件,为当前进程创建binder_state结构体
  • 接着调用mmap函数,请求binder驱动申请128K大小的内核缓冲区,映射到servicemanager的进程空间,映射后的起始地址和空间大小,均保存在binder_state结构体中
  • 最后bs返回servicemanager

open()mmap()最后都是调用kernel层Binder驱动的binder_open()binder_mmap(),具体细节自行查看吧


binder_become_context_manager

/frameworks/native/cmds/servicemanager/binder.c

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

调用kernel层binder.c的ioctl方法 /kernel/3.4/xref/drivers/staging/android/binder.c

static struct binder_node *binder_context_mgr_node;
……
static struct binder_node *binder_new_node(……)
……
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
    ……
    case BINDER_SET_CONTEXT_MGR:
        ……
        binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
        ……
}

使用binder_new_node创建了servicemanager对应的binder_node结点,保存在了binder_context_mgr_node变量中

也就是说其他所有Client均可以通过binder.c的binder_context_mgr_node变量拿到servicemanager对应的binder_node结点


binder_loop

/frameworks/native/cmds/servicemanager/binder.c

void binder_loop(struct binder_state *bs, binder_handler func){
    ……
    //数据置空 
    bwr.write_size = 0; 
    bwr.write_consumed = 0; 
    bwr.write_buffer = 0;
    
    readbuf[0] = BC_ENTER_LOOPER;
    //通过binder_write,即ioctl向binder驱动层写入数据
    //通知binder驱动,servicemanager开启loop循环了
    //第一次写入数据
    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) {
        fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
        goto fail;
        }
        
        res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0);
        
        if (res == 0) return 0;
        if (res < 0) goto fail;
    }
    ……
}
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;
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    if (res < 0) {
        fprintf(stderr,"binder_write: ioctl failed (%s)\n",
                strerror(errno));
    }
    return res;
}

可以看出:
第一次写入write_buffer = BC_ENTER_LOOPER
第二次写入read_buffer = BC_ENTER_LOOPER

/kernel/3.4/xref/drivers/staging/android/binder.c

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
    ……
    case BINDER_WRITE_READ: {
        ……
        //将用户空间的数据拷贝到内核空间
        if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { 
            ret = -EFAULT; goto out; 
        }
        //第一次进入到这里
        if (bwr.write_size > 0) {
            ret = binder_thread_write(proc, thread,bwr.write_buffer,bwr.write_size,&bwr.write_consumed);
            ……
        }
        //第二次进入到这里
        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);
            ……
        }
        ……
    }
}

第一次binder_thread_write()主要是设置一个START标志

static int binder_thread_write(……){
    ……
    //循环获取buffer中的数据 
    while (……) {
        ……
        case BC_ENTER_LOOPER:
             //设置线程的looper = BINDER_LOOPER_STATE_ENTERED
            thread->looper |= BINDER_LOOPER_STATE_ENTERED;
            break;
        ……
    }
}

第二次已经开启死循环了,不断调用binder_thread_read()

static int binder_thread_read(……){
    ……
    //如果没有请求,则阻塞在此次,直到有请求,再次唤醒
    ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    ……
}

只是贴了主要代码,具体细节还请自行查看源码


结尾:

失眠必读系列未完待续,有任何错误,虚心讨教,欢迎指正...


参考资料:

blog.csdn.net/super_marie…
www.jianshu.com/p/5d1b95a63…