ContextManager(二)——Android Binder

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

ContextManager(二)——Android Binder_第1张图片

可以看到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()
1
2
3
4
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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访问到进程上下方信息了。

你可能感兴趣的:(ContextManager(二)——Android Binder)