第6章 进程间通信--Binder

Binder 是 Android 中使用最广泛的 IPC 机制。

  • Binder 驱动(路由器)
  • Service Manager(DNS)
  • Binder Client(客户端)
  • Binder Server(服务器)

6.1 智能指针

解决C/C++项目中常见的指针问题:

  1. 指针没有初始化
  2. new 了对象后没有及时 delete
  3. 野指针

6.2 进程间的数据传递载体 -- Parcel

Parcel 是一种数据的载体,具备打包和重组的能力,用于通过 IBinder 传递信息。

Parcel 可读写如下类型数据:

  • 原始数据类型以及原始数据类型数组。
  • 实现 Parcelable 接口的对象(Bundles)。
  • Active Objects(读取的是写入的实例,主要有两类:Binder,FileDescriptor)。
  • Untyped Containers(标准的任意类型的 Java 容器)。

值得注意的是,Parcel 存/取数据的方式都是一一对应的,如 writeByte(byte)/readByte()。

Binder驱动与协议

Android 系统是基于 Linux 内核的,因而 Binder 驱动也是标准的 Linux 驱动。具体而言,Binder 驱动会把自己注册成一个杂项设备(misc device),并向上层提供 /dev/binder 节点,但它并不对应真实的硬件设备。Binder 驱动运行于内核态,可提供 open()、ioctl()、mmap() 等常用文件操作。

Binder 驱动为上层提供了6个文件操作接口,分别为 binder_poll,binder_ioctl,binder_mmap,binder_open,binder_flush,binder_release。其中 binder_ioctl 实现了应用进程与 Binder 驱动之间的命令交互,承载了 Binder 驱动大部分业务。

ServiceManager(Binder Server)

SM 是在 init 程序解析 init.rc 时启动的,自身也是个 Binder Server(xx Service)。

SM 处理请求过程:

  • 从 Binder 驱动读取消息
  • 处理消息
  • 不断循环,而且永远不会主动退出(除非出现致命错误)

SM 内部维护一个 svclist 列表,用户存储所有 Server 相关信息(以 svcinfo 为数据结构),查询和注册都是基于这个表展开的。

访问 SM(Binder Server)服务的流程:

  • 打开 Binder 设备;
  • 执行 mmap;
  • 通过 Binder 驱动向 SM 发送请求(SM 的 handle 为0);
  • 获得结果

ServiceManagerProxy

当某个 Binder Server 启动时,会把自己的名称 name 与对应的 Binder 句柄保存在 SM 中。调用者通常只知道 Binder Server 的名称,所以必须先向 SM 发起查询请求,就是 getService(name)。

SM 自身也是一个 Server(句柄值为0),因而任何 Binder Client 都可以直接通过0这个 Binder 句柄创建一个 BpBinder,在通过 Binder 驱动去获取 SM 的服务。具体而言,就是调用 BinderInternal.getContextObject() 来获得 SM 的 BpBinder。BpBinder 在 Java 层以 IBinder 来表示,对 SM 而言,IBinder 的真正持有者与使用者是 ServiceManagerProxy ,它是 SM 在本地的代表。

ProcessState 与 IPCTheadState

Android 系统为程序进程使用 Binder 机制封装了两个实现类,ProcessState 与 IPCTheadState。ProcessState 与进程相关,负责打开 Binder 驱动设备,进行 mmap() 等准备工作;IPCTheadState 与线程相关,负责与 Binder 驱动进行具体的命令通信。

在 getService() 这个场景中,调用者是从 Java 层的 IBinder.transact() 开始,层层往下调用到 IPCThreadState.transact(),然后通过 waitForResponse 进入主循环,直到收到 SM 的回复后才跳出循环,并将结果再次层层回传到应用层。

Binder 驱动

Binder 驱动只需要一次复制就可以把数据从一个进程复制到另一个进程。Binder 中还保存着大量的全局以及进程相关的变量,用于管理每个进程/线程的状态、内存申请和代办事项等一系列复杂的数据信息。

Service Manager 的实现

SM 在 Android 系统启动之后就运行起来了,并通过 BINDER_SET_CONTEXT_MGR 把自己注册成 Binder “大管家”。它在做完一系列初始化后,在最后一次 iocl 的 read 操作中会进入睡眠等待,直到有 Binder Clint 发起服务请求而被 Binder 驱动唤醒。

SM 唤醒后,程序分为两条主线索:其一,SM 端将接着执行 read 操作,把调用者的具体请求读取出来,然后利用 binder_parse 解析,再根据实际情况填写 transaction 信息,最后把结果通过 BR_REPLY 命令(也是 ioctl)返回 Binder 驱动。

其二,发起 getService 请求的 Binder Client 在等待 SM 回复的过程中会进入休眠,直到被 Binder 驱动再次唤醒 -- 它和 SM 一样也是在 read 中睡眠的,因而醒来后继续执行读取操作。这一次得到的就是 SM 对请求的执行结果。程序先把结果填充到 reply 这个 Parcel 中,然后通过层层返回到 ServiceManagerProxy,再利用 Parcel.readStrongBinder 生成一个 BpBinder,最终经过类型转换为 IBinder 对象后传给调用者。

Binder客户端 -- Binder Client

binderService 启动系统其它进程提供的 Service :

  1. 应用程序填写 Intent,调用 bindService 发出请求。
  2. 收到请求的 bindService 将与 ActivityManagerService(AMS)取得联系。
  3. AMS 基于特定的“最优匹配策略”,从其内部存储的系统所有服务组件的资料中找到与 Intent 最匹配的一个,然后向它发送 Service 绑定请求,如果目标进程还不存在的话,AMS 还要负责把它启动起来。
  4. “被绑定”的服务进程需要相应绑定,执行具体操作,并在成功完成后通知 AMS;然后由 AMS 再回调发起请求的应用程序。

Android接口描述语言 -- AIDL

AIDL 是 Android Interface Description Language 的简写,是用于定义客户端/服务端通信接口的一种描述语言。

构建一个 Binder Server 所需工作如下:

  1. 启动的时机
  2. 提供一致的服务接口
  3. 与 Binder 驱动的交互方式
  4. 外界如何能访问到这个 Server 的服务
    方式一:Server 在 ServiceManager 中注册。
    方式二:通过其他 Server 作为中介(匿名Server)。

AIDL的关键字:

oneway 关键字用来同步实现远程异步调用 aidl 服务。使用该关键字时,远程调用不会阻塞;它只是发送事务数据并立即返回。接口的实现最终接收此调用时,是以正常远程调用形式将其作为来自 Binder 线程池的常规调用进行接收。 如果 oneway 用于本地调用,则不会有任何影响,调用仍是同步调用。

所有非原语参数都需要指示数据走向的方向标记,默认为 in。

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