9.2 Binder系统_驱动情景分析
Posted 拉风摊主
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9.2 Binder系统_驱动情景分析相关的知识,希望对你有一定的参考价值。
1. 几个重要结构体的引入
给test_server添加一个goodbye服务, 由此引入以下概念:
进程间通信其实质也是需要三要素:源、目的、数据,源是自己,目的用handle表示;通讯的过程是源向实现进程的“服务”发数据,handle是对“服务”的引用,在不同的进程里面handle不一样,即使多个进程对同一个进程的“服务”发数据,这些多个进程里面的handle可以也不一样
总结:handle是进程A对进程B提供的服务S的引用,进程A调用binder_call把handle传递给驱动,驱动根据handle找到服务S,驱动内部会有个binder_ref结构体来描述服务S的引用,这个结构体里面有个desc,驱动程序对比一系列的binder_ref结构体里的desc,找到与handle对应的binder_ref,而对应的服务用binder_node来表示,binder_ref结构体里的node指向binder_node,根据binder_node结构体里的binder_proc可以找到进程B,可能存在多个进程A1、A2等同时向进程B请求服务,B在binder_node结构体中有个rb_root thread线程树来挂载这些线程,线程用结构体binder_thread来保存
binder_ref
binder_node
binder_proc
binder_thread
binder_buffer
(1)server出入一个flat_binder_object给驱动,在内核态驱动程序里根据flat_binder_object结构体为每个服务创建binder_node
binder_node.proc = server进程
(2)在内核态驱动程序中 service_manager创建binder_ref,其引用binder_node
其binder_ref.desc的值取一系列的binder_ref最大值加1,desc的值从1开始往上加
在用户态会创建服务链表,并未服务链表添加一项,含有name和handle,handle就等于binder_ref结构体里的desc
(3)client向service_manager查询服务,向其传入name
(4)service_manager返回handle给驱动程序
(5)驱动程序在service_manager的一些列binder_ref中根据handle找到binder_ref,在根据binder_ref.node找到binder_node,最后给client创建新的binder_ref,其执行binder_node,且binder_ref的desc值从1开始,其client中一系列的binder_ref中desc的最大值,驱动返回desc给client,它即为handle
(因此service_manager里面有一系列的binder_ref,其desc值描述的每个服务是由注册服务的顺序决定的,client里面也有一系列的binder_ref,其desc值描述的每个服务是由获取服务的顺序决定的)
(6)client发数据给handle的时候,驱动根据handle找到binder_ref,在找到binder_node,在找到server进程
数据传输过程:
client => server
client端步骤:
(1)client构造数据,调用ioctl发数据
(2)驱动里根据handle找到server进程
(3)把进程放入进程的binder_proc.todo链表中去, 并唤醒server
(4)休眠
(5)被唤醒
(6)从todo链表中取出数据,返回用户空间
server端步骤:
(1)读数据,无数据时休眠
(2)被唤醒
(3)从todo链表中取出数据,返回用户空间
(4)处理
(5)把数据写入client进程的binder_proc.todo链表,唤醒client
交互过程数据如何复制:
一般方法需要2次复制:
client构造数据,驱动copy_from_user;找到server后copy_to_user,用户态处理
binder的方法:
server程序mmap,server用户态可以直接范问驱动中某块内存;client构造数据,驱动copy_from_user数据后把数据保存到mmap分配的驱动中那块内存,这样server可以在用户态直接操作,此复制操作涉及的结构体是binder_buffer,一次复制仅指的是数据buffer,而binder_write_read结构体还是要复制两次来传递
2. IPC数据交互过程
进程间通过ioctl来传递数据,数据组织为binder_write_read结构体,其中write_buffer结构体用来保存输入的数据,当我们读数据的时候也是读到一个binder_write_read结构体,其中的read_buffer结构体用来保存读到的数据,read_buffer和write_buffer也是个结构体,其前面放着四字节表示数据类型,后面存放着数据本身。
binder驱动在:drivers/staging/android/binder.c中,应用程序中ioctl被调用时,驱动中binder_ioctl被调用,更具cmd来执行,并且调用根据条件执行binder_thread_write或binder_thread_read:
eg:binder_thread_write函数中binder_proc表示进程(结构体里的task_strcut有进程名字和ID),binder_thread表示线程,函数中的cmd表示消息类型
在我们前面写的C语言binder例子中,client向server写数据的时候,数据类型是BC_TRANSACTION,读数据的时候数据类型是BR_TRANSACTION,因此我们在分析binder_thread_write或binder_thread_read的时候仅关注这两个数据类型的分支就可以了
3. 服务注册过程(用到的数据是在驱动中打印出来的,因为应用程序会缓存消息,如果在应用程序中打印,消息的顺序可以能不准)
可以阅读下面文章以了解BC_XXX, BR_XXX
Android Bander设计与实现
http://blog.csdn.net/universus/article/details/6211589
binder驱动框架(binder驱动是调用misc_register来注册,misc_register是misc驱动提供)
(1)misc设备驱动:file_operations中只有.open = misc_open;调用register_chrdev注册
(2)binder驱动本身:构造miscdevice结构体,里面有个file_operations;调用misc_register来注册,把miscdevice结构体放入链表
进程A向进程B发送数据,A发送的数据类型是BC_TRANSACTION,B接受的消息类型是BR_TRANSACTION,A发送的和B接受的是一个消息;B处理完数据后,会回给A的消息类型是BC_REPLY,A接收到的是BR_REPLY类型,在binder中,进程与进程间通信设计的消息类型就只有上述四种,其他消息类型都是进程与驱动之间通信,用来改变和设置某些状态。
./service_manager &
service_manager进程在open的时候调用binder_open,其会创建一个binder_proc指向service_manager进程
接着会有些ioctl,在第一次ioctl中,在binder_ioctl中会创建biner_thread,并且设置它
service_manager (1362, 1362), binder_thread_write : BC_ENTER_LOOPER//在在binder_ioctl中会根据BC_ENTER_LOOPER来设置biner_thread的成员looper来改变状态
service_manager (1362, 1362), binder_thread_read : BR_NOOP //service_manager发起一个读操作,没数据的时候休眠,读所有的读操作,数据头部都是BR_NOOP,读出的数据是binder_write_read结构体,里面的readbuf数据格式为:BR_NOOP|cmd+数据|cmd+数据.......
./test_server &
test_server (1363, 1363), binder_thread_write : BC_TRANSACTION //test_server发起一个写操作,数据里面肯定有服务的名称,数据会放入service_manager的todo链表,并且唤醒service_manager,(todo链表在binder_proc结构体中),server在svcmgr_publish函数中组织数据并调用ioctl传输数据,数据放在iodata这个buf中,通过binder_io结构体来管理数据格式,iodata数据buf格式如下:
(1)在bio_init中把iodata前面16字节空出来,binder_io的offs指向iodata起始地址,data指向iodata起始地址+16字节;
(2)bio_put_uint32(&msg,0)设置data区域四字节00 00 00 00
(3)bio_put_string16_x(&msg,SVC_MGR_NAME)//SVC_MGR_NAME宏定义为"android.os.IServiceManager",先放字符串长度,用四字节表示,接着存放字符,每个字符用两字节表示
(4)bio_put_string16_x(&msg,name)//name在这里是字符串hello,在iodate中接着上面的字符串存放,先放长度
(5)bio_put_obj(&msg,ptr);//分配一个flat_binder_object结构体,设置这个结构体,并且把结构体的数据保存到iodata中,并且在iodata前面空出来的16个字节中用四字节保存flat_binder_object结构体的偏移,总共可以保存4个flat_binder_object结构体
(6)接着调用binder_call,其调用ioctl传输数据,数据类型是BC_TRANSACTION,在binder_call中组织binder_write_read结构体,其中数据保存在结构体里面的binder_transaction_data结构体中
其中data_size是iodata中除去前面16字节剩下数据域的长度,offsets_size是前面16字节中保存有flat_binder_object结构体的长度,data.ptr.buffer保存iodata+16字节的位置,data.ptr.offsets保存iodata起始地址
(7)进入驱动binder_ioctl把数据放入service_manager进程的todo链表,并唤醒service_manager;把数据放入service_manager之前,驱动需要根据handle找到目的进程即service_manager;接着把数据copy_from_user(数据的复制过程是在binder_thread_write中,在调用其之前还有个copy_from_user,其只会复制头部)放入mmap指向的空间,在binder_thread_write中根据数据类型调用binder_transaction函数,对于BC_TRANSACTION其中会根据handle找到binder_ref结构体,根据结构体里的node->proc找到目的进程service_manager,然后把数据放到目的进程空间,并把flat_binder_object数据处理后放入todo链表,接着唤醒service_manager;
(8)flat_binder_object结构体的第一个数据是type,表示当前传输的结构体是实体(BINDER_TYPE_BINDER)还是引用(BINDER_TYPE_HANDLE),只有server的提供者可以传输实体,server_manager和client只能是引用,server_manager接受数据后会修改flat_binder_object结构体的数据,就是下面对flat_binder_object数据的处理过程,可以见service_manager (1362, 1362), binder_thread_read : BR_TRANSACTION的收到的数据;第二个数据flag可以不用关心;第三个数据是根据第一个数据来的,当第一个数据是实体的时候,第三个数据是binder,是一个指针,可以保存服务的执行函数,在总执行函数中更handle执行不同的服务函数;如果第一个参数是引用,第三个参数是handle,即binder_refs->desc参数,第四个参数没用到。并且会给server创建binder_node节点,给server_manager创建binder_ref
(9)处理flat_binder_object的过程就是针对该对象的个数(服务数)创建binder_node
binder: 1363:1363 BC_TRANSACTION 2 -> 1362 - node 1, data beca6a5c-beca6a4c size 96-4
test_server (1363, 1363), binder_transaction , print data :
0000: 00 . 00 . 00 . 00 . 1a . 00 . 00 . 00 . 61 a 00 . 6e n 00 . 64 d 00 . 72 r 00 .
0016: 6f o 00 . 69 i 00 . 64 d 00 . 2e . 00 . 6f o 00 . 73 s 00 . 2e . 00 . 49 I 00 .
0032: 53 S 00 . 65 e 00 . 72 r 00 . 76 v 00 . 69 i 00 . 63 c 00 . 65 e 00 . 4d M 00 .
0048: 61 a 00 . 6e n 00 . 61 a 00 . 67 g 00 . 65 e 00 . 72 r 00 . 00 . 00 . 00 . 00 .
0064: 05 . 00 . 00 . 00 . 68 h 00 . 65 e 00 . 6c l 00 . 6c l 00 . 6f o 00 . 00 . 00 .
0080: 85 . 2a * 62 b 73 s 7f . 01 . 00 . 00 . e0 . 88 . 00 . 00 . 00 . 00 . 00 . 00 .
test_server (1363, 1363), binder_thread_read : BR_NOOP
service_manager (1362, 1362), binder_thread_read : BR_TRANSACTION //service_manager被唤醒后读到BR_TRANSACTION类型的数据,数据里面含有服务的名称“hello”,service_manager调用ioctl去读数据,没数据的时候休眠,被唤醒后从进程或者线程的todo链表中取出数据,把数据传给用户空间的时候把数据类型标记为BR_TRANSACTION ,并且根据binder_transaction来构造binder_transaction_data,然后返回到server_manager,server_manager去解析数据,从数据中取出服务名字,并从flat_binder_object中取出handle,server注册的第一个服务器handle为1,第二个为2
service_manager (1362, 1362), binder_thread_read , print data :
0000: 00 . 00 . 00 . 00 . 1a . 00 . 00 . 00 . 61 a 00 . 6e n 00 . 64 d 00 . 72 r 00 .
0016: 6f o 00 . 69 i 00 . 64 d 00 . 2e . 00 . 6f o 00 . 73 s 00 . 2e . 00 . 49 I 00 .
0032: 53 S 00 . 65 e 00 . 72 r 00 . 76 v 00 . 69 i 00 . 63 c 00 . 65 e 00 . 4d M 00 .
0048: 61 a 00 . 6e n 00 . 61 a 00 . 67 g 00 . 65 e 00 . 72 r 00 . 00 . 00 . 00 . 00 .
0064: 05 . 00 . 00 . 00 . 68 h 00 . 65 e 00 . 6c l 00 . 6c l 00 . 6f o 00 . 00 . 00 .
0080: 85 . 2a * 68 h 73 s 7f . 01 . 00 . 00 . 01 . 00 . 00 . 00 . 00 . 00 . 00 . 00 .
test_server (1363, 1363), binder_thread_read : BR_INCREFS
test_server (1363, 1363), binder_thread_read : BR_ACQUIRE
test_server (1363, 1363), binder_thread_read : BR_TRANSACTION_COMPLETE
service_manager (1362, 1362), binder_thread_write : BC_ACQUIRE
test_server (1363, 1363), binder_thread_read : BR_NOOP
service_manager (1362, 1362), binder_thread_write : BC_REQUEST_DEATH_NOTIFICATION
service_manager (1362, 1362), binder_thread_write : BC_FREE_BUFFER
service_manager (1362, 1362), binder_thread_write : BC_REPLY //service_manager处理完数据后,发送一个BC_REPLY类型的数据,表示其处理完了
binder: 1362:1362 BC_REPLY 5 -> 1363:1363, data bed9fa4c-bed9fa3c size 4-0
service_manager (1362, 1362), binder_transaction , print data :
0000: 00 . 00 . 00 . 00 .
test_server (1363, 1363), binder_thread_read : BR_REPLY //test_server读到BR_REPLY类型数据
test_server (1363, 1363), binder_thread_read , print data :
0000: 00 . 00 . 00 . 00 .
service_manager (1362, 1362), binder_thread_read : BR_NOOP
test_server (1363, 1363), binder_thread_write : BC_FREE_BUFFER
service_manager (1362, 1362), binder_thread_read : BR_TRANSACTION_COMPLETE
service_manager (1362, 1362), binder_thread_read : BR_NOOP
test_server (1363, 1363), binder_thread_write : BC_ENTER_LOOPER
test_server (1363, 1363), binder_thread_read : BR_NOOP
svcmgr: add_service(\'hello\'), handle = 1
数据分析见图片:Binder系统_驱动情景分析2_服务注册过程.jpg
以上是关于9.2 Binder系统_驱动情景分析的主要内容,如果未能解决你的问题,请参考以下文章
9.6 Binder系统_驱动情景分析_server的多线程实现
9.5 Binder系统_驱动情景分析_transaction_stack机制
Android : 跟我学Binder --- 驱动情景分析