概述
进程隔离
在操作系统中,进程与进程间的内存和数据都是不共享的。两个进程互不干扰,各自为政。这样做是为了避免进程间相互操作数据的现象发生,从而引起各自的安全问题。为了实现进程隔离,虚拟采用了虚拟地址空间,两个进程各自的虚拟地址不同,从逻辑上来实现彼此间的隔离。
用户/内核空间
一个进程的内存空间包括用户空间和内核空间。
- 用户空间:运行用户代码与相关库
- 内核空间:运行内核相关的代码。
虽然各进程的用户空间相互独立,但运行在内核空间中的任务数据、代码都是共享的。所以,两个拥有独立空间的进程需要通过内核传递数据,而Binder就是使用运行在内核空间中的抽象驱动程序Binder Driver实现进程间通信的。
Android进程中,用户代码与相关库运行在用户空间的代码区域、数据区域,而内核空间的代码则运行在内核空间的各个区域中。虽然各进程的用户空间相互独立,但运行在内核空间中的任务数据、代码都是共享的。所以,两个拥有独立空间的进程需要通过内核传递数据。
各个进程的用户空间是无法共享的,为实现进程间的通信,Binder使用运行在内核空间中的抽象驱动程序Binder Driver实现进程间通信。
跨进程通信(IPC)方法
(1) 管道
在内存中创建一个共享文件(管道),从而使通信双方利用这个共享文件来传递信息。由于这种方式具有单向传递数据的特点,所以这个作为传递消息的共享文件就叫做“管道”。包括匿名管道(PIPE)和命名管道(FIFO)。
(2) 消息队列
消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识,并且允许一个或多个进程向它写入与读取消息
创建函数:int msgctl(int msgid, int command, struct msgid_ds *buf);
(3) 共享内存
多个进程可以可以直接读写同一块内存空间。为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间。进程就可以直接读写这一块内存而不需要进行数据的拷贝,从而大大提高效率。
但共享内存不提供同步机制。
(4) 套接字(socket)
通过套接字,基于客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行。它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。
套接字的特性由3个属性确定,它们分别是:域、类型和协议。
(5) 信号量
信号量是一个计数器,用于多线程之间的同步。常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源。并不是用来交换大批数据的通信方式。
(6) 信号
用于通知接收进程某个事件已经发生,是软件层次上对中断机制的一种模拟。号可以在用户空间进程和内核之间直接交互,内核可以利用信号来通知用户空间的进程发生了哪些系统事件。
为什么使用Binder?
Binder是Android系统提供的一种IPC(进程间通信)机制,Android系统可以看作是基于Binder通信的C/S架构,Binder像网络一样把系统各个部分连接在了一起。
(1) 性能方面
Binder数据拷贝只需要一次,管道、消息队列、Socket都需要2次,但共享内存方式一次内存拷贝都不需要。从性能角度看,Binder性能仅次于共享内存。
(2) 稳定性方面
Binder是基于C/S架构的,Server端与Client端相对独立,稳定性较好;而共享内存实现方式复杂,没有客户与服务端之别, 需要充分考虑到访问临界资源的并发同步问题,否则可能会出现死锁等问题。从稳定性角度看,Binder架构优于共享内存。
(3) 安全方面
- UID/PID是鉴别进程身份的重要标志,传统IPC只能由用户在数据包里填入UID/PID,而基于Android的Binder的身份标记由IPC机制本身在内核中添加。
- 传统IPC访问接入点是开放的,无法建立私有通道。
而Android设备中包含大量用户的隐私信息,对安全问题十分敏感,所以使用Binder能有效保障进程通信的安全性。
(4) 语言方面
Binder符合面向对象的思想,它将进程间通信转化为通过对某个Binder对象的引用并调用该对象的方法,且Binder对象是一个可以跨进程引用的对象,它的实体位于一个进程中,而它的引用却遍布于系统的各个进程之中。
所以Binder更适合基于面向对象语言的Android系统。
常用术语
- IPC :即Inter-Process Communication,含义为进程间通信,是指两个进程之间进行数据交换的过程,通常指在本地的两个进程之间的通信
- RPC :即(Reomote Procedure Call),远程过程调用,隐藏了过程调用时客户端与服务端实际通信细节的IPC方法
- 服务管理器(Service Server):指运行系统服务的进程,相当于前面提到的System Server 或 Media Server。
- 服务客户端(Server Client):指使用系统服务的进程。
- 上下文管理器(Context Manager):是一个管理系统服务的系统进程,它管理安装在系统中的各种系统服务的位置信息Handle,这些Handle用来指定Binder IPC的目的地址。
- Binder Driver: Binder是Android中为支持IPC而采用的机制,它以Android Linux内核的Device Driver形态存在。
- Binder IPC:它是Android中进程间通过Binder Driver交换数据的方式。
- Binder RPC:服务会向使用者提供基于特定服务接口的函数,服务使用者通过Binder IPC调用这些函数,就像调用自身函数一样(RPC屏蔽了调用过程中的细节)。
Binder模型
模型简介
Binder框架主要有四个角色:
(1) Server:服务端,提供服务。
(2) Client:客户端,使用服务;
(3) Service Manager(简称SMgr)。
管理服务的系统进程。它的主要作用为:
- 维护一个服务目录链表svclist(Android 11之前版本),为每个服务分配一个称为Handle的编号(Service Manager自身的Handle值被设置为0);
- 提供服务的添加、检索等管理功能。
(4) Binder Driver
虽然名为驱动,但和硬件设备没有任何关系,只是实现方式和设备的驱动程序是一样的。工作于内核态,提供open(),mmap(),ioctl()等标准文件操作。Binder Driver负责实际的数据传递、Binder对象实体及引用的管理等任务。
注:Service Manager也通常被称为Context Manager。
Server,Client,SMgr运行于用户空间,Binder驱动运行于内核空间。这四个角色的关系和互联网类似:Client是客户终端(产生需求),Server是服务器(处理需求),SMgr是域名服务器(使需求能找到具体的服务),驱动是路由器(数据的转发及传输)。
它们的关系如下:
注:图片来自gityuan。虚线表示逻辑上的调用关系,但并不是直接传递数据的,它们都要通过Binder Driver来传递数据。
(1) 注册服务
服务注册是指将Server中的服务注册到Service Manager的服务目录中,其中涉及到Server与Service Manager两个进程。
(2) 查询服务
客户端在使用服务时,会向Service Manager请求服务的编号,这一过程称为服务检索。
(3) 使用服务
获得服务的编号后,即知道了服务的地址,此时就可以调用服务了。
系统调用
以上各种角色之间相互通信就要传递数据,它们无法直接进行交互,都是通过Binder Driver来传递数据的。Binder Driver位于内核,所以需要发起系统调用。
用户空间给Binder drive传递IPC数据过程为:
- 首先进行open()系统调用,获取Binder Driver的文件描述符;
- 随后,通过mmap()系统调用,在内核中开辟一块区域,以便存放接收的IPC数据;
- 最后,调用ioctl()函数,将IPC数据作为参数,传递给Binder Driver。
ioctl()是一个专用于设备输入输出操作的系统调用,它的具体实现是根据命令执行的一个switch语句,在用户空间进行调用时,ioctl()函数形式为ioctl(fd,cmd,args)。
- fd:文件描述符,在调用open()函数打开Binder Driver时返回;
- cmd:用户与设备之间的交互协议,设备驱动将根据cmd 执行对应操作;
- args:参数,根据ioctl命令的不同也有所不同;
- 返回值:执行成功时返回 0,失败则返回-1。
Binder 协议
Binder协议就是Binder在进行ioctl操作所支持的一些命令以及参数。Binder协议基本格式是(命令+数据),使用ioctl(fd, cmd, arg)函数实现交互。命令由参数cmd承载,数据由参数arg承载。
可以分为控制协议和驱动协议两类。
(1) 控制协议
控制协议用于传输与Binder Driver相关的控制信息,该协议包含以下几种常用命令:
| ioctl命令 | 含义 | 参数 |
|---|---|---|
| BINDER_WRITE_READ | 向Binder写入或读取数据 | struct binder_write_read |
| BINDER_SET_MAX_THREADS | 该命令告知Binder驱动接收方(通常是Server端)线程池中最大的线程数。由于Client是并发向Server端发送请求的,Server端必须开辟线程池为这些并发请求提供服务。告知驱动线程池的最大值是为了让驱动发现线程数达到该值时不要再命令接收端启动新的线程。 | int max_threads; |
| BINDER_SET_CONTEXT_MGR | 将当前进程注册为SMgr。系统中同时只能存在一个SMgr。只要当前的SMgr没有调用close()关闭Binder驱动就不能有别的进程可以成为SMgr。 | — |
| BINDER_THREAD_EXIT | 通知Binder驱动当前线程退出了。Binder会为所有参与Binder通信的线程(包括Server线程池中的线程和Client发出请求的线程)建立相应的数据结构。这些线程在退出时必须通知驱动释放相应的数据结构。 | — |
| BINDER_VERSION | 获取Binder协议的版本 | struct binder_version |
以常用命令BINDER_WRITE_READ为例,该命令向Binder写入或读取数据。该命令的数据类型为结构体binder_write_read。
struct binder_write_read {
signed long write_size;
signed long write_consumed;
unsigned long write_buffer;
signed long read_size;
signed long read_consumed;
unsigned long read_buffer;
};
参数分为两段:写部分和读部分。Binder Driver先处理写部分再处理读部分。这样安排的好处是应用程序可以很灵活地处理命令的同步或异步。
- 如果write_size不为0就先将write_buffer里的数据写入Binder;
- 如果read_size不为0再从Binder中读取数据存入read_buffer中。
- write_consumed和read_consumed表示操作完成时Binder驱动实际写入或读出的数据个数。
(2) 驱动协议
Binder的驱动协议描述了对于Binder驱动的具体使用过程。根据传递方向,驱动协议可以分为两类:
- 从IPC层传递给Binder Driver的“BINDER COMMAND PROTOCOL”,以 “BC_“开头;
- 从 Binder Driver 传递给IPC层的“ BINDER RETURN PROTOCOL ”,以 “BR_“开头。
使用BINDER_WRITE_READ命令后,需要进行实际的读写操作。以写操作为例,Binder写操作的数据时格式同样也是(命令+数据)。这时候命令和数据都存放在binder_write_read 结构write_buffer域指向的内存空间里,多条命令可以连续存放。数据紧接着存放在命令后面,格式根据命令不同而不同。
Binder写操作命令:
| cmd | 含义 | args |
|---|---|---|
| BC_TRANSACTION | Client向Server发送请求数据 | struct binder_transaction_data |
| BC_REPLY | Server向Client发送回复(应答)数据 | struct binder_transaction_data |
| BC_FREE_BUFFER | 释放一块映射的内存。Binder接收方通过mmap()映射一块较大的内存空间,应用程序处理完这片数据后必须尽快使用该命令释放缓存区,否则会因为缓存区耗尽而无法接收新数据。 | 指向需要释放的缓存区的指针;该指针位于收到的Binder数据包中 |
| BC_INCREFS BC_ACQUIRE | 增加Binder实体引用计数时,驱动向Binder实体所在的进程发送BR_INCREFS, BR_ACQUIRE消息; | 32位Binder引用号 |
| BC_RELEASE BC_DECREFS | 减少Binder实体引用计数时,驱动向Binder实体所在的进程发送BC_RELEASE, BC_DECREFS消息; | 32位Binder引用号 |
| BC_INCREFS_DONE BC_ACQUIRE_DONE | Binder实体所在的进程处理完引用计数增加或减少是回复BC_INCREFS_DONE,BC_ACQUIRE_DONE | void *ptr:Binder实体在用户空间中的指针 void *cookie:与该实体相关的附加数据 |
| 。。。 | 。。。 |
Binder读操作命令:
| cmd | 含义 | args |
|---|---|---|
| BC_TRANSACTION | 表示接收的是请求数据 | struct binder_transaction_data |
| BR_REPLY | 表示接受的是回复数据 | struct binder_transaction_data |
| BR_ERROR | 发生内部错误(如内存分配失败) | — |
| BR_DEAD_REPLY | 交互过程中如果发现对方进程或线程已经死亡则返回该消息 | — |
| 。。。 | 。。。 |
binder_transaction_data是一个struct对象,承载接收和发送的数据,其定义位于/kernel/$(CPU架构)/include/uapi/linux/android/binder.h文件中。该结构是Binder接收/发送数据包的标准格式,每个成员定义如下:
struct binder_transaction_data {
union { //指明接收方
size_t handle; // 对Binder实体的引用
void *ptr; // 指向Binder实体
} target;
void *cookie; // 与Binder指针相关的额外信息
unsigned int code; // 收发双方约定的命令码
unsigned int flags; // 与交互相关的标志位
pid_t sender_pid; // 发送方的进程ID
uid_t sender_euid; // 发送方的用户ID
size_t data_size; // data.ptr.buffer指向的缓冲区存放的数据长度
size_t offsets_size;// data.ptr.buffer中有多少个Binder引用
union {
struct {
const void *buffer; // 存放要发送或接收到的数据
const void *offsets;// 指向Binder偏移位置数组
} ptr;
uint8_t buf[8]; // 保证data的大小为8B
} data;
};
| cmd | 含义 |
|---|---|
| union { size_t handle; void *ptr; } target | 对于发送方,用于指明目的地。由于目的是在远端,所以这里填入的是对Binder实体的引用,存放在target.handle中。 当数据包到达接收方时,驱动已将该成员修改成Binder实体(Binder驱动保存有接收方的实体指针),即指向Binder对象内存的指针,使用target.ptr来获得。 |
| void *cookie | 该成员存放的是创建Binder实体时由该接收方自定义的任意数值,做为与Binder指针相关的额外信息存放在驱动中。 |
| unsigned int code | 该成员存放收发双方约定的命令码,驱动完全不关心该成员的内容。通常是Server端定义的公共接口函数的编号。 |
| unsigned int flags | 与交互相关的标志位 |
| pid_t sender_pid uid_t sender_euid | 存放发送方的进程ID和用户ID,由驱动负责填入,接收方可以读取该成员获知发送方的身份。 |
| size_t data_size | 表示data.ptr.buffer指向的缓冲区存放的数据长度。发送数据时由发送方填入,表示即将发送的数据长度。 |
| size_t offsets_size | 表示在data.ptr.buffer中有多少个Binder引用。 驱动需要为Binder引用维护引用计数,如果在data.ptr.buffer中有Binder引用对象则需要将其相对data.ptr.buffer的偏移位置指出来让驱动知道。 有可能存在多个Binder引用同时在数据中传递,所以需要用数组表示所有引用的偏移位置。而offsets_size就表示该数组的大小,从而可以知道用多少个引用。 |
| union { struct { const void *buffer; const void *offsets; } ptr; uint8_t buf[8]; } data; | bufer指向要发送或接收到的数据; offsets指向表示Binder引用的偏移位置的数组,该数组可以位于data.ptr.buffer中,也可以在另外的内存空间中,并无限制。 buf[8]是为了无论保证32位还是64位平台,成员data的大小都是8个字节。 |
关于offsets_size与data.ptr.offsets的详细说明:
Binder采用面向对象的设计思想,一个Binder实体(位于Server)可以发送给其它进程从而建立许多跨进程的引用;另外这些引用也可以在进程之间传递,就象java里将一个引用赋给另一个引用一样。
为Binder在不同进程中建立引用必须有驱动的参与,由驱动在内核创建并注册相关的数据结构后接收方才能使用该引用。而且这些引用可以是强类型,需要驱动为其维护引用计数。
然而这些跨进程传递的Binder引用混杂在应用程序发送的数据包里,数据格式由用户定义,如果不把它们一一标记出来告知驱动,驱动将无法从数据中将它们提取出来。于是就使用数组data.ptr.offsets存放用户数据中每个Binder引用相对data.buffer的偏移量,用offsets_size表示这个数组的大小。驱动在发送数据包时会根据data.ptr.offsets和offset_size将散落于data.ptr.buffer中的Binder引用找出来并一一为它们创建相关的数据结构。在数据包中传输的Binder引用是类型为struct flat_binder_object的结构体。
对于接收方来说,该结构体只相当于一个定长的消息头,真正的用户数据存放在data.ptr.buffer所指向的缓存区中。
IPC数据流
客户端在调用服务端某个服务中的函数时,它会把与调用的函数相关的信息生成相应的IPC数据,其中与调用服务相关的IPC数据包括:
- RPC代码:用于指定待调用的函数;
- RPC数据:是要传入函数的参数;
- Handle 值:表示接收该IPC数据的服务。
IPC数据即是ioctl(fd,cmd,args)中的args。
Android系统提供了几种抽象层,将数据进行包装并传递。

(1) 服务层
该层包含一系列提供特定功能的服务函数。 服务客户端虚拟调用特定的服务函数,而实际调用是由 Server进行的。
(2) RPC层
- 客户端在该层生成用于调用服务函数的RPC代码与RPC数据;
- Server会根据传递过来的RPC代码查找相应的函数,并将RPC数据传递给查找到的函数。
(3) IPC层
将RPC层生成的RPC代码与RPC数据封装成Binder IPC数据,以便将它们传递给Binder Driver„
(4) Binder Driver层
接收来自IPC层的Binder IPC数据,查找包含指定服务的Server,并将IPC数据传递给查找到的Server。
Binder的运行流程-简单介绍
注册服务
服务注册是指将Service Server中的服务注册到Context Manager的服务目录中,其中涉及到Service Server与Context Manager两个进程。
在这一过程中,Server是调用Context Manager服务函数的客户端,而Context Manager则是提供服务的一端(Context Manager是提供注册服务的 Server)。
在Binder IPC过程中各进程的作用及顺序(服务注册阶段):
| IPC主体 | 作用 | |
|---|---|---|
| IPC数据 | IPC应答数据 | |
| Server(客户端) | ① 发送 | ④ 接收 |
| Context Manager(服务端) | ② 接收 | ③ 发送 |
下图描述了 Context Manager与Server相互作用的具体过程。
| 序号 | 操作 |
|---|---|
| 1 | Service Manager:发起系统调用open(),返回一个Binder Driver的文件描述符; |
| 2 | Service Manager:调用mmap()函数,在内核空间中开辟一块用于接收IPC数据的Buffer |
| 3 | Service Manager:调用ioctl()函数进入待机状态,等待接收IPC数据 |
| 4 | Server:发起系统调用open() |
| 5 | Server:调用mmap()函数 |
| 6 | Server:生成IPC数据,其内容包括: ···Binder协议为BC_TRANSACTION; ···Handle等于0; ···RPC代码为ADD_SERVICE; ···RPC数据为要注册的具体服务名。 |
| 7 | Server:调用ioctl()函数,传递IPC数据,然后进入待机状态 |
| 8 | Binder Driver:将收到的IPC数据传递给Service Manager; 将BC_TRANSACTION修改为BR_TRANSACTION协议,发出。 |
| 9 | Service Manager:分析IPC数据并调用服务注册函数addService() |
| 10 | Service Manager:生成IPC应答数据(BC_REPLY)并传递给Server以告知服务已注册 |
| 11 | Server:收到应答数据并处理 |
获取服务
客户端在使用 Server的服务前,首先会向Service Manager请求服务的编号,这一过程称为获取服务或服务检索。在服务检索阶段,涉及Client和Service Manager两个进程。
在这一过程中,Client是调用Context Manager服务函数的客户端,而Context Manager则是提供服务的一端(Context Manager是提供查询服务的 Server)。
在Binder IPC过程中各进程的作用及顺序(获取服务阶段):
| 序号 | 操作 |
|---|---|
| 1 | Service Manager:等待接收Binder Driver传递来的消息 |
| 2 | Client:发起系统调用open() |
| 3 | Client:调用mmap()函数 |
| 4 | Client:生成IPC数据 ·Binder协议为BC_TRANSACTION; ···Handle等于0; ···RPC代码为要获取的具体服务(函数)名; ···RPC数据为函数参数。 |
| 5 | Client:调用ioctl()函数,传递IPC数据,然后进入待机状态 |
| 6 | Binder Driver:将收到的IPC数据传递给Service Manager,Service Manager进行分析 |
| 7 | Service Manager:调用服务检索函数getService(),在服务目录中进行检索 |
| 8 | Service Manager:生成IPC应答数据并传递给Client以告知完成检索 |
| 9 | Client:收到应答数据并处理 |
使用服务
在使用服务阶段,涉及Client和Service Manager两个进程。
在这一过程中,Client是调用Server服务函数的客户端,而Server则是提供服务的一端。
| 序号 | 操作 |
|---|---|
| 1 | Server:等待接收Binder Driver传递来的消息 |
| 2 | Client:生成使用服务的IPC数据; ···Binder协议为BC_TRANSACTION; ···Handle等于检索服务时获得的服务端的Handle值; ···RPC代码为要调用的具体服务(函数)名; ···RPC数据为函数参数。 |
| 3 | Client:发起系统调用open()->mmap()->ioctl(),传递IPC数据,然后等待 |
| 4 | Binder Driver:将收到的IPC数据传递给Server,Server根据IPC数据调用相应的服务函数 |
| 5 | Servger:生成IPC应答数据并传递给Client以告知服务函数执行完毕 |
| 6 | Client:收到应答数据并处理 |
代理者模式
在服务使用者看来,Client获取Server中某个对象(object)就像是获取本地对象一样,这一过程是通过代理者模式来实现的。
跨进程通信的过程都有Binder驱动的参与,因此在数据流经Binder驱动的时候驱动会对数据做一层转换。以Client使用Server中的服务为例:
- Client获取Server中的object对象,但实际调用的是一个跟object看起来一模一样的代理对象objectProxy;
- objectProxy中并没有实现Server中object对象的那些方法,objectProxy中的方法只需要把把请求参数交给驱动即可。对于Client进程来说和直接调用object中的方法是一样的。
- Binder驱动接收到Client的调用消息后,发现这是个objectProxy就去查询自己维护的表单,查询出这是Server中的object。
- Binder驱动通知Server进程调用object的方法,并要求Server进程把返回结果发给自己。当驱动拿到返回结果后就会转发给Client进程,一次通信就完成了。
所以,从不同的进程来看,它们直接接触到的Binder对象是不同的:
- 从Server进程的角度看,Binder 指的是Server中的Binder实体对象;
- 从Client进程的角度看,Binder 指的是对Binder代理对象,是Binder实体对象的一个远程代理。
而从其它角度来看:
- 从进程间通信的角度看,Binder是一种进程间通信的机制;
- 从传输过程的角度看,Binder是一个可以跨进程传输的对象。Binder 驱动会对这个跨越进程边界的对象做一些特殊处理,自动完成代理对象和本地对象之间的转换。
其它
Binder的oneway属性
oneway意为单向的,在Binder中就是只有客户端向服务的传参数,而不会有返回值。
oneway接口是异步的,请求完成前就可以返回。非oneway接口是同步的,客户端线程在服务端完成binder请求前会阻塞。
Aidl中的接口如果不声明为oneway,默认都是非oneway的。oneway接口的返回值都应该定义为void,否则在编译时会报错。
interface IMyService {
oneway String funcA();
String funB();
}
上面的funcA()方法会报错:oneway method ‘funcA’ cannot return a value。
以IMyService.aidl为例:
interface IMyService {
oneway void funcA();
String funB();
}
其中funcA()是oneway接口,funB()是非oneway接口。
private static class Proxy implements com.demoapp.binderdemo.IMyService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void funcA() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_funcA, _data, null, android.os.IBinder.FLAG_ONEWAY);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().funcA();
return;
}
}
finally {
_data.recycle();
}
}
@Override public java.lang.String funB() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_funB, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().funB();
}
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.demoapp.binderdemo.IMyService sDefaultImpl;
}
可以看出,oneway接口是没有回应_reply和返回值_result的,其中_reply是客户端获取到服务后发给服务的的响应,_result是客户端需要的运算结果。
Binder接口的buffer
(1) 非oneway(同步)通信
非oneway通信的缓存空间buffer的大小定义在frameworks/native/libs/binder/ProcessState.cpp中。
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
对于非oneway(同步)通信,数据传输最大值为1MB-8KB。
(2) oneway(异步)通信
oneway通信的缓存空间buffer的大小定义在/drivers/staging/android/binder.c中。
所以对于oneway(异步)通信,数据传输最大值为(1MB-8KB)/2。