Android 跨进程通信-(二)Binder机制之ServiceManager

目录

前言

一 ServiceManager

1.通过builder_open()打开Binder驱动

2.通过binder_become_context_manager()告诉Binder驱动程序该进程为ServiceManager进程

3.通过binder_loop()开启循环,等待Client进程和Server进程发来请求

4.小结

二 Binder驱动

1.初始化

2.binder_open()

3.binder_mmap()

4.binder_ioctl()

5.小结


前言

通过源码的角度来看下到底Binder机制是一个什么东西。如果不喜欢看源码,可以直接看每个章节的小结。

一 ServiceManager

在前面一篇Android 跨进程通信-(一)Binder概念引入中也总结过:Android在系统启动的时候,用户空间启动的第一个进程是init进程,ServiceManager是由init进程通过解析init.rc文件而创建的,其所对应的可执行程序/system/bin/servicemanager,所对应的源文件是framework/base/services/java/com/android/server/service_manager.c,进程名为/system/bin/servicemanager。

这样当该进程创建成功之后,后面在启动的Service都会通过ServiceManager来进程管理。ServiceManager位于frameworks/base/core/java/android/os/ServiceManager.java。

前面也提到了在Binder机制中的四大组件:Client、Server、ServiceManager以及Binder驱动,所以将这些Service的时候启动之前,其实首先要启动ServiceManager进程

该ServiceManager进程启动的时候,其实就是执行framework/native/cmds/servicemanager/servicemanager.c下对应的内容,这是Native层对ServiceManager这个功能的封装,是ServiceManager在Native层功能的体现,最终不同的方法的功能实现都包括两部分:第一部分就是Native层对Kernel层相关方法的封装;第二部分就是Kernel层具体功能实现。也就是说最终在Native层的这些方法都会调用到Kernel层的对应的方法。

int main(int argc, char** argv)
{
    struct binder_state *bs;
    union selinux_callback cb;
    char *driver;

    if (argc > 1) {
        driver = argv[1];
    } else {
        driver = "/dev/binder";
    }
    // 1.打开Binder驱动,映射内存为128k
    bs = binder_open(driver, 128*1024);
    //........
    //2.成为上下文的管理者,告诉Binder驱动该进程为ServiceManager进程
    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }
     //........
    //3.开启循环处理消息
    binder_loop(bs, svcmgr_handler);

    return 0;
}

在整个ServiceManager进程在启动的过程中,就会完成下面的三个功能: 

1.通过builder_open()打开Binder驱动

builder_open()具体实现对应framework/native/cmds/servicemanager/builder.c中的builder_open():该方法的作用不难理解,主要有这两部分的作用:

  • (1)打开设备文件"/dev/binder"获取一个文件描述bs,通过该文件描述才可以与Binder驱动进行交互;
  • (2)将该文件映射到ServiceManager进程的虚拟地址空间

进入到builder.c的builder_open()中看下里面的几个关键流程:

struct binder_state *binder_open(const char* driver, size_t mapsize)
{   
   struct binder_state *bs; 
    //......
    //1.调用内核空间的binder驱动来打开设备文件"/dev/binder"
    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    //......
    //2.检查kernel的binder版本是否一致
    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;
    }

    //3.根据传入的内存大小,为该设备文件创建对应大小的虚拟空间
    bs->mapsize = mapsize;
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    //......
    return bs;
     //......
}

(1)通过open()打开设备文件

该方法就是去打开binder的设备文件"/dev/binder",并且返回一个binder_state来记录这个设备文件的状态。其中binder_state的参数如下:

struct binder_state
{
    int fd;
    void *mapped;
    size_t mapsize;
};
  • 参数fd: 打开"/dev/binder"的返回的文件描述符,用来和Binder驱动进行交互;
  • 参数mapped:为当前的ServiceManage进程与BInder驱动进行交互分配的地址空间,用来Binder驱动为它分配内核缓冲区来保存进程间通信的数据。
  • 参数mapsize:地址空间,大小

此时open()方法会通过系统调用到Binder驱动中的binder_open()方法。具体的Binder驱动的binder_open()会在后面二 Binder驱动有介绍。

这样就从用户空间通过系统调用到了内核空间,通过Binder驱动的binder_open()打开了设备文件"/dev/binder",并且获得了一个该文件的描述符,然后通过该文件描述符与Binder驱动进行通信。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值