一、Service 开启和停止
二、Service 执行耗时工作
三、IPC常用方式
四、AIDL(一)同一应用中使用AIDL及原理
五、AIDL(二)不同应用中使用、自定义数据类型及定向Tag
六、AIDL(三)实现回调
七、AIDL(四)获取服务及绑定和Binder传递流程
文章目录
IPC常用方式
在平时的开发中,大部分时候都在编写单个App
,每个App
就是个进程。如果App
之间需要通信,即进程间通信(IPC
,InterProcess Communication
)。实现进程间通信通常有两种方法:共享物理内存、通过内核中转。
3.1 Linux IPC 方法
3.1.1 共享内存
共享内存,属于共享物理内存方式,多个进程可以共享同一段物理内存,当某个进程改变内存内容时,其它进程都能够知道。此种方式无需拷贝内容,但是需要信号量进行进程间同步。
3.1.2 通过内核中转
管道、消息队列、套接字(socket
)
先将A
发送的内容拷贝到内核,这过程可以理解为存储,再从内核拷贝到B
的用户空间,这过程可以理解为转发,因此一次"存储-转发"过程需要两次内容拷贝。
3.2 BInder
进程A
给进程B
发送一段信息,流程如下:
- 进程
A
通过系统调用拷贝内容到内核空间。 - 由于内核空间与进程
B
做了内存映射,因此进程B
能够知道内核空间的信息。
从上可知,通过Binder
,进程A
给进程B
发送信息只进行了一次数据拷贝。
- 效率:传输效率主要影响因素是内存拷贝的次数,拷贝次数越少,传输速率越高。从
Android
进程架构角度分析:对于消息队列、Socket
和管道来说,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共两次拷贝。对于Binder
来说,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同 一块物理地址的,节省了一次数据拷贝的过程:共享内存不需要拷贝,Binder
的性能仅次于共享内存。 - 稳定性:上面说到共享内存的性能优于
Binder
,那为什么不采用共享内存呢,因为共享内存需要处理并发同步问题,容易出现死锁和资源竞争,稳定性较差。Binder
基于C/S架构 ,Server
端与Client
端相对独立,稳定性较 好。 - 安全性:传统
Linux IPC
的接收方无法获得对方进程可靠的UID/PID
,从而无法鉴别对方身份;而Binder
机制为每个进程分配了UID/PID
,且在Binder
通信时会根据UID/PID
进行有效性检测。
3.3 基于 Binder 实现跨进程通信案例
3.3.1 功能介绍
如下图,实现一个简单四则运算功能,输入两个数字,绑定服务后,点击对应的运算符按钮,客户端把计算的两个数字和计算方法发送给服务端,服务端将结果计算出来并返回给客户端,最后客户端将结果展现在界面上。
动画功能演示如下:
3.3.2 UML 类图
UML
类图如下:
运行流程:
- 客户端发起绑定请求(界面点击
bind calculator binder service
按钮,调用bindService
函数); - 服务器接收绑定请求,调用
onBind
函数,在onBind
函数中将CalculatorServiceBinder
引用返回; - 客户端调用
onServiceConnected
函数,拿到CalculatorServiceBinder
引用(与服务端返回的CalculatorServiceBinder
不是同一个); - 点击四个运算符按钮(调用
calculatorServiceBinder.transact
函数,将请求发送给服务端); - 服务端调用
onTransact
实现逻辑,并将结果返回;
3.3.3 案例代码
详情代码请参见: