ContextManager(二)——Android Binder

来源:互联网 发布:海岛奇兵雕像数据 编辑:程序博客网 时间:2024/06/05 23:01

每当Service Server注册服务时,Context Manager都会把服务的名称与Binder节点编号注册到自身的服务目录中,该服务目录通过根文件系统下的/system/service程序即可查看。 下图即为在华为某型号手机上使用service list命令查看到的服务列表:

service_list

可以看到MediaPlayer Service以及Camera Service等。

1.启动运行Context Manager的main()函数

Context Manager与其他Android服务不同,它采用C语言编写,以便使其与Binder Driver紧密衔接。Context Manager的源码在/frameworks/base/cmds/servicemanager目录下的service_manager.c中。main()函数如下所示:

service_manager.c
<span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">1</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">2</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">3</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">4</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">5</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">6</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">7</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">8</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">9</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">10</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">11</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">12</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">13</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">14</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">15</span><span class="line-number" style="margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; color: rgb(88, 110, 117) !important;">16</span>
int main(int argc, char**argv){    struct binder_state *bs;    void *svcmgr=BINDER_SERVICE_MANAGER;    bs=binder_open(128*1024);    if(binder_become_context_manager(bs)){        LOGE("cannot become context manager (%s)\n",strerror(errno));        return -1;    }    svcmgr_handle=svcmgr;    binder_loop(bs,svcmgr_handler);    return 0;}

上面的代码按功能可以分为以下3部分:

  • 调用binder_open()函数,将引起open()与mmap()函数调用,调用open()函数打开Binder Driver,而调用mmap()函数则生成接收IPC数据的Buffer. Context Manager使用大小为128KB的Buffer来接收IPC数据;

  • 与Service Server和服务客户端不同,这是Context Manager特有的语句,用于访问Binder Driver,并将自身的Binder节点设置为0号节点。在binder_become_context_manager()中,仅有一条调用ioctl()函数的语句,如下所示:

binder_become_context_manager()
1234
int binder_become_context_manager(struct binder_state*bs){    return ioctl(bs->fd,BINDER_SET_CONTEXT_MGR,0);}
  • Context Manager将自身的Binder节点设置好后,就进入循环,不断等待接收IPC数据,那就是binder_loop()的作用。

下面将详细讲解这3个部分。

2.binder_open()函数分析

2.1 驱动函数注册

在分析binder_open()方法之前,我们先了解一下驱动函数是如何被调用的,我们先看一下下面的代码:

binder.c
123456789101112131415161718192021222324
static const struct file_operations binder_fops={    .owner=THIS_MODULE,    .poll=binder_poll,    .unlocked_ioctl=binder_ioctl,    .mmap=binder_mmap,    .open=binder_open,    .flush=binder_flush,    .release=binder_release,};static struct miscdevice binder_miscdev={    .minor=MISC_DYNAMIC_MINOR,    .name="binder",    .fops=&binder_fops,}static int __init binder_init(void){    ...    ret=misc_register(&binder_miscdev);    ...}device_initcall(binder_init);

上面的代码在drivers/staging/android/binder.c中。我们知道,Android是基于Linux 2.6内核开发的,所以驱动的注册和Linux中也一样。

  • device_initcall(binder_init)的作用是将binder_init()函数注册到kernel的初始化函数列表中。当kernel启动后,会按照一定的次序调用初始化函数列表,也就会执行binder_init()函数,执行binder_init()时便会加载Binder驱动;

  • binder_init()函数中会通过misc_register(&binder_miscdev)将Binder驱动注册到文件节点/dev/binder上。在Linux中,一切都是文件。将Binder驱动注册到文件节点上之后,就可以通过操作文件节点进而对Binder驱动进行操作。而该文件节点/dev/binder的设备信息是binder_miscdev这个结构体对象。

  • binder_miscdev变量是struct miscdevice类型。minor是次设备号,这个我们不关心;name是Binder驱动对应在/dev虚拟文件系统下的设备节点名称,也就是/dev/binder中的"binder";fops是该设备节点的文件操作对象,它是我们需要重点关注的.

  • binder_fops变量是struct file_operations类型。其中owner标明了该文件操作变量的拥有者,就是该驱动;poll则指定了poll函数指针,当我们对/dev/binder文件节点执行poll操作时,实际上调用的就是binder_poll()函数;同理,mmap()对应binder_mmap(),open()对应binder_open(),ioctl()对应binder_ioctl

2.2 binder_open()

binder_open()方法的主要代码如下:

binder_open()
12345678910111213141516171819
struct binder_state *binder_open(unsigned mapsize){    struct binder_state *bs;    bs = malloc(sizeof(*bs));    ...    bs->fd = open("/dev/binder", O_RDWR);    ...    bs->mapsize = mapsize;    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);    ...    return bs;}

该代码在/frameworks/base/cmds/servicemanager/binder.c中.

2.2.1 驱动中的binder_oepn()

通过2.1的分析,我们知道open(“/dev/binder”,O_RDWR);其实就是调用Binder驱动中的binder_open(),其代码如下:

binder_open()
123456789101112131415161718192021222324252627282930313233343536
static int binder_open(struct inode *nodp, struct file *filp){    struct binder_proc *proc;    binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",             current->group_leader->pid, current->pid);    //为proc分配内存    proc = kzalloc(sizeof(*proc), GFP_KERNEL);    if (proc == NULL)        return -ENOMEM;    get_task_struct(current);    //将proc->tsk指向当前线程    proc->tsk = current;    //初始化proc的待处理事务列表    INIT_LIST_HEAD(&proc->todo);    //初始化proc的待处理事务列表    init_waitqueue_head(&proc->wait);    //设置proc的进程优先级设置为当前线程的优先级    proc->default_priority = task_nice(current);    mutex_lock(&binder_lock);    binder_stats_created(BINDER_STAT_PROC);    //将该进程上下文信息proc保存到binder_procs中    hlist_add_head(&proc->proc_node, &binder_procs);    //设置进程id    proc->pid = current->group_leader->pid;    INIT_LIST_HEAD(&proc->delivered_death);    //将proc设置为flip的私有数据中,从而 使mmap(),ioctl()等函数都可以通过私有数据获取到proc,即该进程的context信息    filp->private_data = proc;    mutex_unlock(&binder_lock);    if (binder_debugfs_dir_entry_proc) {        char strbuf[11];        snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);        proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,            binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);    }    return 0;}

tips: 结构体binder_proc用于记录进程上下文信息。它的详细介绍可参考博客Android Binder机制中的数据结构分析.

结合注释,很容易发现该函数的主要伤脑筋其实就是新建了一个binder_proc指针,并为其分配内存,再设置其属性(如tsk,todo,default_priority等),最后将其赋值给flip的private_data属性,这样以后就可以通过flip->private_data访问到进程上下方信息了。

0 0
原创粉丝点击