Android通信方式篇(五)-Binder机制(Kernel层)

先从内核来总结下Binder驱动,从Binder IPC原理我们就知道了,对于进程来说,用户空间是不能共享的,而内核空间却可以。所以只能费这么大劲,在内核设计一个Binder驱动来间接打通client和server进程的通信。另外,Binder驱动是Android专用的,尽管名叫“驱动“,实际上和硬件设备没有任何关系,只是实现方式和设备驱动程序是一样的而已。

一、系统调用

在学习Binder Driver之前,先了解下系统调用流程:用户态的程序调用Kernel层驱动是需要陷入内核态,进行系统调用(syscall),比如打开Binder驱动方法的调用链为: open()(用户空间方法)-> __open()(systemCall对应方法)-> binder_open()(binder 驱动方法)。至于其他的从用户态陷入内核态的流程也基本一致。

二、主要工作函数介绍

binder_init:注册misc设备,对应于miscdevice结构体。这个不多说,简单说就是驱动的注册以及一些初始化工作。

binder_open:创建binder_proc对象,并把当前进程等信息保存到binder_proc对象,该对象管理IPC所需的各种信息并拥有其他结构体的根结构体;再把binder_proc对象保存到文件指针filp,以及把binder_proc加入到全局链表binder_procs。(Binder驱动中通过static HLIST_HEAD(binder_procs)创建了全局的哈希链表binder_procs。)

binder_mmap: 首先在内核虚拟地址空间,申请一块与用户虚拟内存相同大小的内存;然后再申请1个page大小的物理内存,再将同一块物理内存分别映射到内核虚拟地址空间和用户虚拟内存空间,从而实现了用户空间的Buffer和内核空间的Buffer同步操作的功能。

binder_ioctl: 针对不同的ioctl命令在两个进程间收发IPC数据和IPC reply数据。
通过switch接收不同的命令,对应执行不同的操作,代码如下:

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
//参数arg表示用户空间传过来的数据
{
  ...
   switch (cmd) {
   case BINDER_WRITE_READ:  //进行binder的读写操作
       ret = binder_ioctl_write_read(filp, cmd, arg, thread); //【见2.4.2】
       if (ret)
           goto err;
       break;
   case BINDER_SET_MAX_THREADS: //设置binder最大支持的线程数
       if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
           ret = -EINVAL;
           goto err;
       }
       break;
   case BINDER_SET_CONTEXT_MGR: //成为binder的上下文管理者,也就是ServiceManager成为守护进程
       ret = binder_ioctl_set_ctx_mgr(filp);
       if (ret)
           goto err;
       break;
   case BINDER_THREAD_EXIT:   //当binder线程退出,释放binder线程
       binder_free_thread(proc, thread);
       thread = NULL;
       break;
   case BINDER_VERSION: {  //获取binder的版本号
       struct binder_version __user *ver = ubuf;
       if (size != sizeof(struct binder_version)) {
           ret = -EINVAL;
           goto err;
       }
       if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
                &ver->protocol_version)) {
           ret = -EINVAL;
           goto err;
       }
       break;
   }
   default:
       ret = -EINVAL;
       goto err;
   }
    ...
   return ret;
}
三、Binder协议

Binder协议可以分为控制协议和驱动协议两类。

控制协议:用户空间进程通过ioctl与Binder驱动进行通信的协议,也叫做ioctl命令。

主要控制协议如下:

ioctl命令 操作 使用场景
BINDER_WRITE_READ 收发Binder IPC数据 Binder读写交互场景,IPC.talkWithDriver
BINDER_SET_MAX_THREADS 设置Binder线程最大个数 servicemanager进程成为上下文管理者,binder_become_context_manager()
BINDER_SET_CONTEXT_MGR 设置Service Manager节点 初始化ProcessState对象,open_driver()主动调整参数,ProcessState.setThreadPoolMaxThreadCount()

驱动协议:描述了对于Binder驱动的具体使用过程。

驱动协议又可以分为两类:

  1. BINDER_COMMAND_PROTOCOL:binder请求码,以”BC_“开头,简称BC码,用于从IPC层传递到Binder Driver层;

  2. BINDER_RETURN_PROTOCOL :binder响应码,以”BR_“开头,简称BR码,用于从Binder Driver层传递到IPC层;

列举一次完整的Binder通信过程:

BC_PROTOCOL

请求码 参数类型 作用 调用方法
BC_TRANSACTION binder_transaction_data Client向Binder驱动发送请求数据 IPC.transact()
BC_REPLY binder_transaction_data Server向Binder驱动发送请求数据 IPC.sendReply()

BR_PROTOCOL:

响应码 参数类型 作用 触发时机
BR_TRANSACTION binder_transaction_data Binder驱动向Server端发送请求数据 收到BINDER_WORK_TRANSACTION
BR_REPLY binder_transaction_data Binder驱动向Client端发送回复数据 收到BINDER_WORK_TRANSACTION
BR_TRANSACTION_COMPLETE 无参数 对请求发送的成功反馈 收到BINDER_WORK_TRANSACTION_COMPLETE

BC_TRANSACTION和BR_TRANSACTION过程是一个client请求server的完整事务过程
BC_REPLY和BR_REPLY过程是server回复client的完整事务过程。

binder_thread_write()根据不同的BC协议而执行不同的流程。 其中BC_TRANSACTION和BC_REPLY协议,会进入binder_transaction()过程。

BINDER_WORK_TRANSACTION和BINDER_WORK_TRANSACTION_COMPLETE都是binder_work类型。

注:控制协议和驱动协议不止这么点,在此只是列举了最常见的。

四、通信过程

按协议来看:

按数据转换来看

图(左)说明:

  • AMP.startService: 将数据封装到Parcel类型;
  • IPC.writeTransactionData:将数据封装到binder_transaction_data结构体;
  • IPC.talkWithDriver:将数据进一步封装到binder_write_read结构体;
    再通过ioctl()写入命令BINDER_WRITE_READ和binder_write_read结构体到驱动层
  • binder_transaction: 将发起端数据拷贝到接收端进程的buffer结构体;

图(右)说明:

  • binder_thread_read:根据binder_transaction结构体和binder_buffer结构体数据生成新的binder_transaction_data结构体,写入bwr的write_buffer,传递到用户空间。
  • IPC.executeCommand: 解析binder_transaction_data数据,找到目标BBinder并调用其transact()方法;
  • AMN.onTransact: 解析Parcel数据,然后调用目标服务的目标方法;
  • AMS.startService: 层层封装和拆分后,执行真正的业务逻辑。
五、Binder内存机制

虚拟进程地址空间(vm_area_struct)和虚拟内核地址空间(vm_struct)都映射到同一块物理内存空间。当Client端与Server端发送数据时,Client(作为数据发送端)先从自己的进程空间把IPC通信数据copy_from_user拷贝到内核空间,而Server端(作为数据接收端)与内核共享数据,不再需要拷贝数据,而是通过内存地址空间的偏移量,即可获悉内存地址,整个过程只发生一次内存拷贝。一般地做法,需要Client端进程空间拷贝到内核空间,再由内核空间拷贝到Server进程空间,会发生两次拷贝。

下面这图是从Binder在进程间数据通信的流程图,从图中更能明了Binder的内存转移关系。

所以总体来说,Binder驱动主要分两块:协议的通信 和 内存空间处理 。

参考文章:
https://blog.csdn.net/qiyei2009/article/details/78996106
http://gityuan.com/2015/11/01/binder-driver/
http://gityuan.com/2015/11/02/binder-driver-2/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352