logo资料库

Android Binder设计与实现——设计篇.pdf

第1页 / 共18页
第2页 / 共18页
第3页 / 共18页
第4页 / 共18页
第5页 / 共18页
第6页 / 共18页
第7页 / 共18页
第8页 / 共18页
资料共18页,剩余部分请下载后查看
1 引言
2 面向对象的 Binder IPC
3 Binder 通信模型
3.1 Binder 驱动
3.2 ServiceManager 与实名Binder
3.3 Client 获得实名Binder的引用
3.4 匿名 Binder
4 Binder 协议
4.1 BINDER_WRITE_READ 之写操作
4.2 BINDER_WRITE_READ :从Binder读出数据
4.3 struct binder_transaction_data :收发数据包结构
5 Binder 的表述
5.1 Binder 在应用程序中的表述
5.1.1 Binder 在Server端的表述 – Binder实体
5.1.2 Binder 在Client端的表述 – Binder引用
5.2 Binder 在传输数据中的表述
5.2.1 文件形式的 Binder
5.3 Binder 在驱动中的表述
5.3.1 Binder 实体在驱动中的表述
5.3.2 Binder 引用在驱动中的表述
6 Binder 内存映射和接收缓存区管理
7 Binder 接收线程管理
8 数据包接收队列与(线程)等待队列管理
9 总结
Android Binder 设计与实现 ——设计篇 1 Android Binder 设计与实现 ——设计篇 关键词 Binder Android IPC Linux 内核 驱动 摘要 Binder 是 Android 系统进程间通信(IPC)方式之一。Linux 已经拥有管道,system V IPC,socket 等 IPC 手段,却还要倚赖 Binder 来实现进程间通信,说明 Binder 具有无可比拟的优势。深入了解 Binder 并 将之与传统 IPC 做对比有助于我们深入领会进程间通信的实现和性能优化。本文将对 Binder 的设计细节做一 个全面的阐述,首先通过介绍 Binder 通信模型和 Binder 通信协议了解 Binder 的设计需求;然后分别阐 述 Binder 在系统不同部分的表述方式和起的作用;最后还会解释 Binder 在数据接收端的设计考虑,包括 线程池管理,内存映射和等待队列管理等。通过本文对 Binder 的详细介绍以及与其它 IPC 通信方式的对比, 读者将对 Binder 的优势和使用 Binder 作为 Android 主要 IPC 方式的原因有深入了解。 1 引言 基于 Client-Server 的通信方式广泛应用于从互联网和数据库访问到嵌入式手持设备内部通信等各个领域。 智能手机平台特别是 Android 系统中,为了向应用开发者提供丰富多样的功能,这种通信方式更是无处不在 , 诸如媒体播放,视音频频捕获,到各种让手机更智能的传感器(加速度,方位,温度,光亮度等)都由不同的 Server 负责管理,应用程序只需做为 Client 与这些 Server 建立连接便可以使用这些服务,花很少的时间 和精力就能开发出令人眩目的功能。Client-Server 方式的广泛采用对进程间通信(IPC)机制是一个挑战。 目前 linux 支持的 IPC 包括传统的管道,System V IPC,即消息队列/共享内存/信号量,以及 socket 中只有 socket 支持 Client-Server 的通信方式。当然也可以在这些底层机制上架设一套协议来实现 Client-Server 通信,但这样增加了系统的复杂性,在手机这种条件复杂,资源稀缺的环境下可靠性也难 以保证。 另一方面是传输性能。socket 作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和 本机上进程间的低速通信。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的 缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程。共享内存虽然无需拷贝,但控制 复杂,难以使用。 表 1 各种 IPC 方式数据拷贝次数 IPC 数据拷贝次数 0 共享内存 1 Binder Socket/管道/消息队列 2 还有一点是出于安全性考虑。Android 作为一个开放式,拥有众多开发者的的平台,应用程序的来源广泛,确 保智能终端的安全是非常重要的。终端用户不希望从网上下载的程序在不知情的情况下偷窥隐私数据,连接无 线网络,长期操作底层设备导致电池很快耗尽等等。传统 IPC 没有任何安全措施,完全依赖上层协议来确保。 首先传统 IPC 的接收方无法获得对方进程可靠的 UID/PID(用户 ID/进程 ID),从而无法鉴别对方身份 。 Android 为每个安装好的应用程序分配了自己的 UID,故进程的 UID 是鉴别进程身份的重要标志。使用传统
Android Binder 设计与实现 ——设计篇 2 IPC 只能由用户在数据包里填入 UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由 IPC 机制本身在内核中添加。其次传统 IPC 访问接入点是开放的,无法建立私有通道。比如命名管道的名称, system V 的键值,socket 的 ip 地址或文件名都是开放的,只要知道这些接入点的程序都可以和对端建立 连接,不管怎样都无法阻止恶意程序通过猜测接收方地址获得连接。 基于以上原因,Android 需要建立一套新的 IPC 机制来满足系统对通信方式,传输性能和安全性的要求,这 就是 Binder。Binder 基于 Client-Server 通信模式,传输过程只需一次拷贝,为发送发添加 UID/PID 身 份,既支持实名 Binder 也支持匿名 Binder,安全性高。 2 面向对象的 Binder IPC Binder 使用 Client-Server 通信方式:一个进程作为 Server 提供诸如视频/音频解码,视频捕获,地址 本查询,网络连接等服务;多个进程作为 Client 向 Server 发起服务请求,获得所需要的服务。要想实现 Client-Server 通信据必须实现以下两点:一是 server 必须有确定的访问接入点或者说地址来接受 Client 的请求,并且 Client 可以通过某种途径获知 Server 的地址;二是制定 Command-Reply 协议来 传输数据。例如在网络通信中 Server 的访问接入点就是 Server 主机的 IP 地址+端口号,传输协议为 TCP 协 议。对 Binder 而言,Binder 可以看成 Server 提供的实现某个特定服务的访问接入点, Client 通过这个 ‘ ’地址 向 Server 发送请求来使用该服务;对 Client 而言,Binder 可以看成是通向 Server 的管道入口, 要想和某个 Server 通信首先必须建立这个管道并获得管道入口。 与其它 IPC 不同,Binder 使用了面向对象的思想来描述作为访问接入点的 Binder 及其在 Client 中的入 口:Binder 是一个实体位于 Server 中的对象,该对象提供了一套方法用以实现对服务的请求,就象类的成 员函数。遍布于 client 中的入口可以看成指向这个 binder 对象的 指针 ,一旦获得了这个 指针 就可以调用 ’指针 调用其提供的方法和通过指针调用其它任何 该对象的方法访问 server。在 Client 看来,通过 Binder‘ 本地对象的方法并无区别,尽管前者的实体位于远端 Server 中,而后者实体位于本地内存中。 指针 是 C++ ’ 的术语,而更通常的说法是引用,即 Client 通过 Binder 的引用访问 Server 。而软件领域另一个术语 句柄 也可以用来表述 Binder 在 Client 中的存在方式。从通信的角度看,Client 中的 Binder 也可以看作是 Server Binder 提供服务。本文中会使用 引用 或 句柄 这个 两广泛使用的术语。 的 代理 ,在本地代表远端 Server 为 Client ‘ ’ ‘ ‘ ’ ’ ‘ ‘ ’ ’ ‘ ‘ ’ 面向对象思想的引入将进程间通信转化为通过对某个 Binder 对象的引用调用该对象的方法,而其独特之处 在于 Binder 对象是一个可以跨进程引用的对象,它的实体位于一个进程中,而它的引用却遍布于系统的各 个进程之中。最诱人的是,这个引用和 java 里引用一样既可以是强类型,也可以是弱类型,而且可以从一个 进程传给其它进程,让大家都能访问同一 Server,就象将一个对象或引用赋值给另一个引用一样。Binder 模糊了进程边界,淡化了进程间通信过程,整个系统仿佛运行于同一个面向对象的程序之中。形形色色的 Binder 对象以及星罗棋布的引用仿佛粘接各个应用程序的胶水,这也是 Binder 在英文里的原意。 当然面向对象只是针对应用程序而言,对于 Binder 驱动和内核其它模块一样使用 C 语言实现,没有类和对 象的概念。Binder 驱动为面向对象的进程间通信提供底层支持。
Android Binder 设计与实现 ——设计篇 3 Binder 通信模型 3 Binder 框架定义了四个角色:Server,Client,ServiceManager(以后简称 SMgr)以及 Binder 驱动。 其中 Server,Client,SMgr 运行于用户空间,驱动运行于内核空间。这四个角色的关系和互联网类似: Server 是服务器,Client 是客户终端,SMgr 是域名服务器(DNS),驱动是路由器。 3.1 Binder 驱动 ‘ ’ 和路由器一样,Binder 驱动虽然默默无闻,却是通信的核心。尽管名叫 驱动 ,实际上和硬件设备没有任何关 系,只是实现方式和设备驱动程序是一样的:它工作于内核态,提供 open(),mmap(),poll(),ioctl() 等标准文件操作,以字符驱动设备中的 misc 设备注册在设备目录/dev 下,用户通过/dev/binder 访问它。 驱动负责进程之间 Binder 通信的建立,Binder 在进程之间的传递,Binder 引用计数管理,数据包在进程 之间的传递和交互等一系列底层支持。驱动和应用程序之间定义了一套接口协议,主要功能由 ioctl()接口实 现,不提供 read(),write()接口,因为 ioctl()灵活方便,且能够一次调用实现先写后读以满足同步交 互 , 而 不 必 分 别 调 用 write() 和 read() 。 Binder 驱 动 的 代 码 位 于 linux 目 录 的 drivers/misc/binder.c 中。 3.2 ServiceManager 与实名 Binder 和 DNS 类似,SMgr 的作用是将字符形式的 Binder 名字转化成 Client 中对该 Binder 的引用,使得 Client 能够通过 Binder 名字获得对 Server 中 Binder 实体的引用。注册了名字的 Binder 叫实名 Binder,就象每个网站除了有 IP 地址外还有自己的网址。Server 创建了 Binder 实体,为其取一个字符形 式,可读易记的名字,将这个 Binder 连同名字以数据包的形式通过 Binder 驱动发送给 SMgr,通知 SMgr 注册一个名叫张三的 Binder,它位于某个 Server 中。驱动为这个穿过进程边界的 Binder 创建位于内核中 的实体节点以及 SMgr 对实体的引用,将名字及新建的引用打包传递给 SMgr。SMgr 收数据包后,从中取出名 字和引用填入一张查找表中。 细心的读者可能会发现其中的蹊跷:SMgr 是一个进程,Server 是另一个进程,Server 向 SMgr 注册 Binder 必然会涉及进程间通信。当前实现的是进程间通信却又要用到进程间通信,这就好象蛋可以孵出鸡前 提却是要找只鸡来孵蛋。Binder 的实现比较巧妙:预先创造一只鸡来孵蛋:SMgr 和其它进程同样采用 Binder 通信,SMgr 是 Server 端,有自己的 Binder 对象(实体),其它进程都是 Client,需要通过这个 Binder 的引用来实现 Binder 的注册,查询和获取。SMgr 提供的 Binder 比较特殊,它没有名字也不需要注 册,当一个进程使用 BINDER_SET_CONTEXT_MGR 命令将自己注册成 SMgr 时 Binder 驱动会自动为它创建 Binder 实体(这就是那只预先造好的鸡)。其次这个 Binder 的引用在所有 Client 中都固定为 0 而无须通过 其它手段获得。也就是说,一个 Server 若要向 SMgr 注册自己 Binder 就必需通过 0 这个引用号和 SMgr 的 Binder 通信。类比网络通信,0 号引用就好比域名服务器的地址,你必须预先手工或动态配置好。要注意这里 说的 Client 是相对 SMgr 而言的,一个应用程序可能是个提供服务的 Server,但对 SMgr 来说它仍然是个 Client。
Android Binder 设计与实现 ——设计篇 4 3.3 Client 获得实名 Binder 的引用 Server 向 SMgr 注册了 Binder 实体及其名字后,Client 就可以通过名字获得该 Binder 的引用了 。 Client 也利用保留的 0 号引用向 SMgr 请求访问某个 Binder:我申请获得名字叫张三的 Binder 的引用 。 SMgr 收到这个连接请求,从请求数据包里获得 Binder 的名字,在查找表里找到该名字对应的条目,从条目 中取出 Binder 的引用,将该引用作为回复发送给发起请求的 Client。从面向对象的角度,这个 Binder 对 象现在有了两个引用:一个位于 SMgr 中,一个位于发起请求的 Client 中。如果接下来有更多的 Client 请 求该 Binder,系统中就会有更多的引用指向该 Binder,就象 java 里一个对象存在多个引用一样。而且类似 的这些指向 Binder 的引用是强类型,从而确保只要有引用 Binder 实体就不会被释放掉。通过以上过程可以 看出,SMgr 象个火车票代售点,收集了所有火车的车票,可以通过它购买到乘坐各趟火车的票-得到某个 Binder 的引用。 3.4 匿名 Binder 并不是所有 Binder 都需要注册给 SMgr 广而告之的。Server 端可以通过已经建立的 Binder 连接将创建的 Binder 实体传给 Client,当然这条已经建立的 Binder 连接必须是通过实名 Binder 实现。由于这个 Binder 没有向 SMgr 注册名字,所以是个匿名 Binder。Client 将会收到这个匿名 Binder 的引用,通过这 个引用向位于 Server 中的实体发送请求。匿名 Binder 为通信双方建立一条私密通道,只要 Server 没有把 匿名 Binder 发给别的进程,别的进程就无法通过穷举或猜测等任何方式获得该 Binder 的引用,向该 Binder 发送请求。 下图展示了参与 Binder 通信的所有角色,将在以后章节中一一提到。 图 1 Binder 通信示例
Android Binder 设计与实现 ——设计篇 4 Binder 协议 5 Binder 协议基本格式是(命令+数据),使用 ioctl(fd, cmd, arg)函数实现交互。命令由参数 cmd 承载, 数据由参数 arg 承载,随 cmd 不同而不同。下表列举了所有命令及其所对应的数据: 表 2 Binder 通信命令字 命令 BINDER_WRITE_READ 含义 该命令向 Binder 写入或读取数据。参数分为 两段:写部分和读部分。如果 write_size 不为 0 就先将 write_buffer 里的数据写 入 Binder;如果 read_size 不为 0 再从 Binder 中读取数据存入 read_buffer 中 。 write_consumed 和 read_consumed 表 示操作完成时 Binder 驱动实际写入或读出 的数据个数。 arg 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; }; int max_threads; BINDER_SET_MAX_THREADS 该命 令 告知 Binder 驱动接收方 (通 常 是 Server 端)线程池中最大的线程数。由于 Client 是 并 发 向 Server 端 发 送 请 求 的 , Server 端必须开辟线程池为这些并发请求 提供服务。告知驱动线程池的最大值是为了让 驱动发现线程数达到该值时不要再命令接收 端启动新的线程。 BINDER_THREAD_EXIT BINDER_SET_CONTEXT_MGR 将当前进程注册为 SMgr。系统中同时只能存 在一个 SMgr。只要当前的 SMgr 没有调用 close()关闭 Binder 驱动就不能有别的进 程可以成为 SMgr。 通知 Binder 驱动当前线程退出了。Binder 会为 所 有 参 与 Binder 通信的线程 ( 包括 Server 线程池中的线程和 Client 发出请 求的线程)建立相应的数据结构。这些线程在 退出时必须通知驱动释放相应的数据结构。 获得 Binder 驱动的版本号。 BINDER_VERSION --- --- --- 这其中最常用的命令是 BINDER_WRITE_READ。该命令的参数包括两部分数据:一部分是向 Binder 写入的数 据,一部分是要从 Binder 读出的数据,驱动程序先处理写部分再处理读部分。这样安排的好处是应用程序可 以很灵活地处理命令的同步或异步。例如若要发送异步命令可以只填入写部分而将 read_size 置成 0;若要 只从 Binder 获得数据可以将写部分置空即 write_size 置成 0;若要发送请求并同步等待返回数据可以将 两部分都置上。
Android Binder 设计与实现 ——设计篇 6 4.1 BINDER_WRITE_READ 之写操作 Binder 写操作的数据时格式同样也是(命令+数据)。这时候命令和数据都存放在 binder_write_read 结 构 write_buffer 域指向的内存空间里,多条命令可以连续存放。数据紧接着存放在命令后面,格式根据命 令不同而不同。下表列举了 Binder 写操作支持的命令: cmd BC_TRANSACTION BC_REPLY 表 3 Binder 写操作命令字 含义 BC_TRANSACTION 用于 Client 向 Server 发送请求 数据;BC_REPLY 用于 Server 向 Client 发送回复 ( 应 答 ) 数 据 。 其 后 面 紧 接 着 一 个 binder_transaction_data 结构体表明要写入的数 据。 暂未实现 BC_ACQUIRE_RESULT BC_ATTEMPT_ACQUIRE BC_FREE_BUFFER BC_INCREFS BC_ACQUIRE BC_RELEASE BC_DECREFS BC_INCREFS_DONE BC_ACQUIRE_DONE BC_REGISTER_LOOPER BC_ENTER_LOOPER BC_EXIT_LOOPER BC_REQUEST_DEATH _NOTIFICATION 释放一块映射的内存。Binder 接收方通过 mmap()映 射一块较大的内存空间,Binder 驱动基于这片内存采 用最佳匹配算法实现接收数据缓存的动态分配和释放, 满足并发请求对接收缓存区的需求。应用程序处理完这 片数据后必须尽快使用该命令释放缓存区,否则会因为 缓存区耗尽而无法接收新数据。 这组命令增加或减少 Binder 的引用计数,用以实现强 指针或弱指针的功能。 第一次增加 Binder 实体引用计数时,驱动向 Binder 实体所在的进程发送 BR_INCREFS,BR_ACQUIRE 消 息 ; Binder 实 体 所 在 的 进 程 处 理 完 毕 回 馈 BC_INCREFS_DONE,BC_ACQUIRE_DONE 这 组 命 令 同 BINDER_SET_MAX_THREADS 一 道 实 现 Binder 驱 动 对 接 收 方 线 程 池 管 理 。 BC_REGISTER_LOOPER 通知驱动线程池中一个线程已 经创建了;BC_ENTER_LOOPER 通知驱动该线程已经 进入主循环,可以接收数据;BC_EXIT_LOOPER 通知 驱动该线程退出主循环,不再接收数据。 获 得 Binder 引 用 的 进 程 通 过 该 命 令 要 求 驱 动 在 Binder 实体销毁得到通知。虽说强指针可以确保只要 有引用就不会销毁实体,但这毕竟是个跨进程的引用, 谁也无法保证实体由于所在的 Server 关闭 Binder 驱 动或异常退出而消失,引用者能做的是要求 Server 在 此刻给出通知。 arg struct binder_transaction_data --- 指向需要释放的缓存区的指针; 该指针位于收到的 Binder 数 据包中 32 位 Binder 引用号 void *ptr:Binder 实体在 用户空间中的指针 void *cookie:与该实体相 关的附加数据 --- uint32 *ptr; 需要得到死亡 通知的 Binder 引用 void **cookie: 与 死 亡 通 知相关的信息,驱动会在发出 死亡通知时返回给发出请求的 进程。 void **cookie BC_DEAD_BINDER_DONE 收到实体死亡通知书的进程在删除引用后用本命令告知 驱动。 在这些命令中,最常用的是 BC_TRANSACTION/BC_REPLY 命令对,Binder 请求和应答数据就是通过这对
Android Binder 设计与实现 ——设计篇 7 命令发送给接收方。这对命令所承载的数据包由结构体 struct binder_transaction_data 定义 。 Binder 交互有同步和异步之分,利用 binder_transaction_data 中 flag 域区分。如果 flag 域的 TF_ONE_WAY 位为 1 则为异步交互,即 Client 端发送完请求交互即结束, Server 端不再返回 BC_REPLY 数据包;否则 Server 会返回 BC_REPLY 数据包,Client 端必须等待接收完该数据包方才完成一次交互。 4.2 BINDER_WRITE_READ :从 Binder 读出数据 从 Binder 里读出的数据格式和向 Binder 中写入的数据格式一样,采用(消息 ID+数据)形式,并且多条消 息可以连续存放。下表列举了从 Binder 读出的命令字及其相应的参数: 表 4 Binder 读操作消息 ID 含义 发生内部错误(如内存分配失败) 操作完成 消息 BR_ERROR BR_OK BR_NOOP BR_SPAWN_LOOPER 该消息用于接收方线程池管理。当驱动发现接收 方所有线程都处于忙碌状态且线程池里的线程 总数没有超过 BINDER_SET_MAX_THREADS 设 置的最大线程数时,向接收方发送该命令要求 创建更多线程以备接收数据。 这 两 条 消 息 分 别 对 应 发 送 方 的 BC_TRANSACTION 和 BC_REPLY,表示当前接 收的数据是请求还是回复。 尚未实现 交互过程中如果发现对方进程或线程已经死亡 则返回该消息 发送 方通过 BC_TRANSACTION 或 BC_REPLY 发送完一个数据包后,都能收到该消息做为成 功发送的反馈。这和 BR_REPLY 不一样,是驱动 告知发送方已经发送成功,而不是 Server 端 返回请求数据。所以不管同步还是异步交互接收 方都能获得本消息。 这一组消息用于管理强/弱指针的引用计数。只 有提供 Binder 实体的进程才能收到这组消息。 向获得 Binder 引用的进程发送 Binder 实体 死亡通知书;收到死亡通知书的进程接下来会 返回 BC_DEAD_BINDER_DONE 做确认 如果发送非法引用号则返回该消息 BR_TRANSACTION BR_REPLY BR_ACQUIRE_RESULT BR_ATTEMPT_ACQUIRE BR_FINISHED BR_DEAD_REPLY BR_TRANSACTION _COMPLETE BR_INCREFS BR_ACQUIRE BR_RELEASE BR_DECREFS BR_DEAD_BINDER BR_CLEAR_DEATH _NOTIFICATION_DONE BR_FAILED_REPLY 参数 --- --- --- binder_transaction_data --- --- --- void *ptr: Binder 实体在用户空间 中的指针 void *cookie: 与该实体相关的附加 数据 void **cookie: 在 使 用 BC_REQUEST_DEATH_NOTIFICATION 注册死亡通知时的附加参数。 --- 和 写 数 据 一 样 , 其 中 最 重 要 的 消 息 是 BR_TRANSACTION 或 BR_REPLY , 表 明 收 到 了 一 个 格 式 为 binder_transaction_data 的请求数据包(BR_TRANSACTION)或返回数据包(BR_REPLY)。
Android Binder 设计与实现 ——设计篇 8 4.3 struct binder_transaction_data :收发数据包结构 该结构是 Binder 接收/发送数据包的标准格式,每个成员定义如下: 表 5 Binder 收发数据包结构:binder_transaction_data 成员 union { size_t handle; void *ptr; } target; void *cookie; unsigned int code; unsigned int flags; pid_t sender_pid; uid_t sender_euid; size_t data_size; size_t offsets_size; union { struct { const void *buffer; const void *offsets; } ptr; uint8_t buf[8]; } data; 含义 对于发送数据包的一方,该成员指明发送目的地。由于目的是在远端,所以这里 填入的是对 Binder 实体的引用,存放在 target.handle 中。如前述,Binder 的引用在代码中也叫句柄(handle)。 当数据包到达接收方时,驱动已将该成员修改成 Binder 实体,即指向 Binder 对象内存的指针,使用 target.ptr 来获得。该指针是接收方在将 Binder 实体 传输给其它进程时提交给驱动的,驱动程序能够自动将发送方填入的引用转换成 接收方 Binder 对象的指针,故接收方可以直接将其当做对象指针来使用(通常 是将其 reinterpret_cast 成相应类)。 发送方忽略该成员;接收方收到数据包时,该成员存放的是创建 Binder 实体时 由该接收方自定义的任意数值,做为与 Binder 指针相关的额外信息存放在驱动 中。驱动基本上不关心该成员。 该成员存放收发双方约定的命令码,驱动完全不关心该成员的内容。通常是 Server 端定义的公共接口函数的编号。 与交互相关的标志位,其中最重要的是 TF_ONE_WAY 位。如果该位置上表明这次 交互是异步的,Server 端不会返回任何数据。驱动利用该位来决定是否构建与返 回有关的数据结构。另外一位 TF_ACCEPT_FDS 是出于安全考虑,如果发起请求 的一方不希望在收到的回复中接收文件形式的 Binder 可以将该位置上。因为收 到一个文件形式的 Binder 会自动为数据接收方打开一个文件,使用该位可以防 止打开文件过多。 该成员存放发送方的进程 ID 和用户 ID,由驱动负责填入,接收方可以读取该成 员获知发送方的身份。 该成员表示 data.buffer 指向的缓冲区存放的数据长度。发送数据时由发送方 填入,表示即将发送的数据长度;在接收方用来告知接收到数据的长度。 驱动一般情况下不关心 data.buffer 里存放什么数据,但如果有 Binder 在其 中传输则需要将其相对 data.buffer 的偏移位置指出来让驱动知道。有可能存 在多个 Binder 同时在数据中传递,所以须用数组表示所有偏移位置。本成员表 示该数组的大小。 data.bufer 存放要发送或接收到的数据;data.offsets 指向 Binder 偏移 位置数组,该数组可以位于 data.buffer 中,也可以在另外的内存空间中,并 无限制。buf[8]是为了无论保证 32 位还是 64 位平台,成员 data 的大小都是 8 个字节。 这里有必要再强调一下 offsets_size 和 data.offsets 两个成员,这是 Binder 通信有别于其它 IPC 的 地方。如前述,Binder 采用面向对象的设计思想,一个 Binder 实体可以发送给其它进程从而建立许多跨进 程的引用;另外这些引用也可以在进程之间传递,就象 java 里将一个引用赋给另一个引用一样。为 Binder
分享到:
收藏