Android Binder 入门介绍
Posted Jason_Wang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Binder 入门介绍相关的知识,希望对你有一定的参考价值。
背景
如今,操作系统都支持多进程,进程与进程之间如何通信(交换数据,相互调用),即跨进程通信(Inter-Process Communication)。 Linux中,已有好几种IPC方法:
- Signals: 最早的IPC方法,一个进程通过发送信号给另一个有相同UID/GID 进程或者在同一进程组的进程
- Pipes(包括 named pipes): Pipes是一个单向的用于连接一个进程的标准输出与另一个进程的标准输入的字节流通道
- Sockets: 双向的通道,两个进程通过打开同一个socket进行通信
- Message queues: 一个进程将消息写入消息队列,另一个进程从改队列中读取消息
- Semaphores: 信号量是一个可以被多个进程读写的共有变量
- Shared Memeory: 一个系统的内存区域,通过将其映射到两个不同进程的虚拟地址空间,因此每个进程都可以访问该地址空间
在了解Binder 的具体机制之前,先来看看android系统组件。我们都知道,Android主要有Activity, Service, Content Provider BroadCast Receiver 四大组件。使用这四种组件都需要在应用的manifest文件AndroidManifest.xml
中进行配置声明。
Activity是一个应用的UI界面,它主要负责前台与用户进行交互;Service一般用于执行后台长时间的任务; Content Provider 用于保存用户需要长久保存的数据,它为 本地或者远端的数据提供了一个统一的操作接口; Broadcaset Receiver用于接收系统级别的消息,告知应用系统的状态与事件,如短息、来电以及低电量。
图1 Android组建系统结构
那么,如何让不同进程中的组件进行数据的交换了?Android提供了 Intents 用于组件的通信。一个 Intent由 URI 和 一个 action组成,URI用于定位目标组件,而action则用于标识执行的操作。事实上,Intent本质是基于 Binder 架构来进行消息的传递的。
Binder 术语
与Binder相关的术语见下图:
图2 Binder 术语图
Binder Driver
用于跨进程通信的Kernel 层驱动
Binder protocol
用于与Binder 驱动交互的数据交换协议(ioctl-based)
IBinder interface
每个 Binder对象都需要实现的 接口
Binder Token
用于标识Binder对象的32bit的整数
AIDL
Android Interface Definition Language 用于描述在IBinder接口上的操作
Proxy
An implementation of the AIDL interface that un/marshals and maps methods calls to transactions submitted via a wrapped IBinder reference to the Binder object
Stub
A partial implementation of the AIDL interface that maps transactions to Binder service method calls while un/marshals data
Context Manager
即 ServiceManager, 特殊的Binder对象,注册时的句柄值为0,用于其他Binder 对象的注册与查找(name -> handle mapping)
什么是Binder
Binder起源于由Dianne Hackborn 主导的OpenBinder,OpenBinder“是一个系统层的组件架构,在OS系统服务之上提供一个高层次、丰富的抽象接口”,Android Binder在OpenBinder的基础上做了修改,但其基本的思想仍然保持一样。
那么,Binder有哪些不一样的特点?
- Binder是一个实现了IPC机制的内核驱动
- Binder提供了轻量级的 RPC(Remote Procedure Communication) 机制
- 每一个进程都有一个线程池来处理Binder 请求
为什么需要Binder
考虑到安全(security)、稳定性(stability)以及内存管理等因素,Android 应用程序和系统服务运行在不同的进程中,因而需要通信与交换数据,即通常IPC方法需要解决的问题。
- 安全: 每个进程都有自己唯一的系统ID(UID,GID,PID),并且在沙箱(sandbox)中运行
- 稳定: 如果一个进程崩溃,不会影响到其他进程
- 内存管理:每个进程管理自己的内存资源,不需要时会释放出来给需要的进程使用
但Android的 libc(bionic) 并不支持 SystemV IPC,
- 没有SystemV IPC 方法,如 semaphores, shared memory, message queues
- 当进程退出时忘记释放共享的IPC资源时,SystemV IPC 方法容易泄露kernel资源
Binder 通过内建的引用计数机制以及death-notification,确保IPC过程没有资源泄露:当一个binder service 不在被任何 clients引用时,binder的管理者会被通知销毁改binder service,因此 Binder 可以很好的适应低内存、低功耗等移动设备。
Binder的特点:
支持 线程迁移(thread migration):
- 线程池自动化管理
- 支持远程调用
- 支持同步和异步(oneway) 调用
通过UID/PID 来识别调用者(clients)
- 可以跨进程发送文件描述符
- 支持常用数据类型的marshalling/unmarshalling
- 简单的AIDL接口
- 如果 client/service 在同一进程,同样可以使用
基本概念
通信模型
Binder 架构通信基于Client/Server模型:client(进程A)向Binder发起通信请求,并等待server的响应。在Client端,Binder为其提供了一个Proxy的接口;server(进程B)收到请求后,由线程池启动的线程对请求进行处理:
图3 Binder 通信模型
这里可以看到, Binder通信进程需要跨越三个层次:
- Binder 内核驱动的通信( C )
- 中间件(middleware)的通信( C++ )
- 应用层的通信 ( Java )
应用层Binder通信
Java应用层主要通过AIDL接口来描述Client与Service之间的通信接口。 AIDL定义了远程service的调用接口,其在Client端产生一个Proxy类,在Server端产生一个Stub类。 有关 AIDL的具体说明请参考:
有了接口之后,那么client要如何向server发送数据了?在Android中,一个进程向另一个进程发送数据,该过程称为Transaction(交易),交易所传递的数据,则称为transaction data, 在Java 应用层,交易数据就是一个Parcel对象。 Parcel可以用来传递flatted data,可以用于传递Parcelable对象,也可以用于传递IBinder对象的引用。
Parcel提供了诸如 writeByte/readByte
,writeDouble/readDouble
,writeInt/readInt
等一系列接口用于写入、读取Java中的基本数据类型。通常, 从一个对象创建一个parcel的过程被称为编组一个对象(marshalling),而将从Parcel重建一个对象的过程称为解组一个对象(unmarshalling)。
我们知道,Android的四个组件之间的通信都是依赖于Intent的,正是Intent将数据从一个组件传递到了另一个组件。从Intent的定义可以看出,其本质上是一个可以被编组与解组的Parcel对象,因而可以实现跨组件、跨进程的数据通信。
public class Intent implements Parcelable, Cloneable ...
中间件层Binder通信
中间件层的编程语言主要是C++,其作用是:
- 管理用于处理Binder请求的线程池
- 对相关数据进行 marshalling/unmarshalling
- 与Binder内核驱动进行交互
通过 /android/frameworks/native/include/binder/IServiceManager.h
中定义的接口:
sp<IServiceManager> defaultServiceManager()
可以获取到全局的变量 sp<IServiceManager>
,可以添加与获取相应的系统服务。
有关中间件更详细的介绍请参考: http://blog.csdn.net/luoshengyang/article/details/6627260
内核驱动层的Binder通信
Binder驱动定义了对外的操作接口: open, mmap, release, poll, 以及系统调用ioctl。 ioctl接口的定义:
ioctl(int binderFD, BINDER_WRITE_READ, &bwd)
这里, &bwd
为写入Binder驱动的一个数据结构,如下:
struct binder_write_read
binder_size_t write_size;
binder_size_t write_consumed;
binder_uintptr_t write_buffer;
binder_size_t read_size;
binder_size_t read_consumed;
binder_uintptr_t read_buffer;
;
ioctl
主要有以下几个命令,其中 :
BINDER_WRITE_READ
用于写入或者读取内存中的交易数据的(最常用的一个命令)BINDER_SET_MAX_THREADS
用于设置线程池支持的最大线程数目(一般的service都设置为15)BINDER_SET_CONEXT_MGR
设置 Context(Service) manager
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
Binder Client与Server 通信流程
这里,再来回顾下,Android中基于 Binder 架构,Client与Server之间的通信流程。
(图片来自 《deep dive into Android Binder Framework》
参考文献
以上是关于Android Binder 入门介绍的主要内容,如果未能解决你的问题,请参考以下文章
千里马Android Framework实战开发-binder驱动常见binder_open,binder_mmap介绍
千里马Android Framework实战开发-binder驱动常见binder_open,binder_mmap介绍
千里马Android Framework实战开发-binder驱动常见binder_open,binder_mmap介绍