一, 进程通信
1, 进程隔离:
进程隔离是为保护操作系统中进程互不干扰而设计的一组不同硬件和软件的技术. 进程数据不共享, 进程 A 的虚拟地址和进程 B 的虚拟地址不同, 这样就防止进程 A 将数据信息写入进程 B, 保证了数据的安全性.
进程空间分为内核空间和用户空间, 内核空间 (Kernel) 是系统内核运行的空间. 用户空间 (User Space) 是用户程序运行的空间, 他们之间是隔离的.
内核有访问的所有权限, 用户空间也可以通过系统接口去访问内核空间. 用户空间可以通过内核空间 (类似于中介者) 进行相互访问.
2,Linux 进程间 IPC 方式:
管道
消息队列
共享内存
套接字
信号量
信号
Linux 下的传统 IPC 通信原理:
传输过程:
内存缓存区 --> 内核缓存区 --> 内存缓存区, 需要 2 次数据拷贝;
3,Binder 机制的特点
(1)传输性能
Binder 数据拷贝只需要一次, 而消息队列, 管道, Socket 等需要两次, 共享内存一次拷贝都不需要. Binder 性能仅次于共享内存.
(2)稳定性
Binder 基于 C/S 架构, Server 端和 Client 端相对独立, 稳定性好.
共享内存没有 Server 端和 Client 端的区分, 可能存在同步死锁等问题. Binder 稳定性优于共享内存.
(3)安全性
传统的 Linux 通信方式无法获取对方进程的 UID, 所以访问接入点是开放的, 不安全.
Android 为每个应用程序分配了自己的 UID, 作为自身的标识. Binder 的方式可以通过 UID 建立私有通道, Binder 的安全性更高.
二, Binder 机制实现原理
1, 内存映射
Binder IPC 正是基于内存映射 (mmap) 来实现的
Binder 通信过程:
首先 Binder 驱动在内核空间创建一个数据接收缓存区;
接着在内核空间开辟一块内核缓存区, 建立内核缓存区和内核中数据接收缓存区之间的映射关系, 以及内核中数据接收缓存区和接收进程用户空间地址的映射关系;
发送方进程通过系统调用 copy_from_user() 将数据 copy 到内核中的内核缓存区, 由于内核缓存区和接收进程的用户空间存在内存映射, 因此也就相当于把数据发送到了接收进程的用户空间, 这样便完成了一次进程间的通信.
2,Binder 通信模型
包括 Client,Server,ServiceManager,Binder 驱动.
其中 Client,Server,Service Manager 运行在用户空间, Binder 驱动运行在内核空间.
对于 Client,Binder 是 Server 本地对象的一个引用, 这个引用实际上是一个代理对象, Client 通过这个代理对象来间接访问 Server 的本地对象.
对于 Server,Binder 是提供具体实现的本地对象, 需向 ServiceManager 注册.
Binder 驱动是连接 Client 来 Server 的桥梁, 负责将代理对象转化为本地对象, 并将 Server 的执行结果返回给 Client.
ServiceManager 它保存了 Server Binder 字符名称和 Binder 引用的映射, Client 通过它来找到 Server 的 Binder 引用.
3,Binder 通信过程:
一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager;
Server 通过驱动向 ServiceManager 中注册 Binder, 表明可以对外提供服务. 驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用, 将名字以及新建的引用打包传给 ServiceManager,ServiceManger 将其填入查找表.
Client 通过名字, 在 Binder 驱动的帮助下从 ServiceManager 中获取到对 Binder 实体的引用, 通过这个引用就能实现和 Server 进程的通信.
三, AIDL
1,AIDL 使用的基本步骤
(1)生成 AIDL 接口(new->AIDL->AIDL File)
- interface MyWindowManager {
- void sysout();
- }
生成 AIDL 文件之后, 比起以前多了一个叫做 aidl 的包, 而且他的层级是和 java 包相同的.
(2)编译 MyWindowManager.aidl 生成 Java 文件
- public interface MyWindowManager extends Android.os.IInterface {
- /** Local-side IPC implementation stub class. */
- //Stub 继承 Binder, 说明它是一个 Binder 本地对象; 实现 IInterface 接口, 表明 Server 可以提供的方法
- public static abstract class Stub extends Android.os.Binder
- implements com.example.myview.binder.MyWindowManager {
- private static final java.lang.String DESCRIPTOR = "com.example.myview.binder.MyWindowManager";
- /** Construct the stub at attach it to the interface. */
- public Stub() {
- this.attachInterface(this, DESCRIPTOR);
- }
- public static com.example.myview.binder.MyWindowManager asInterface(Android.os.IBinder obj) {
- if ((obj == null)) {
- return null;
- }
- Android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
- if (((iin != null) && (iin instanceof com.example.myview.binder.MyWindowManager))) {
- return ((com.example.myview.binder.MyWindowManager) iin);
- }
- return new com.example.myview.binder.MyWindowManager.Stub.Proxy(obj);
- }
- @Override
- public Android.os.IBinder asBinder() {
- return this;
- }
- @Override
- public boolean onTransact(int code, Android.os.Parcel data, Android.os.Parcel reply, int flags)
- throws Android.os.RemoteException {
- ......
- return super.onTransact(code, data, reply, flags);
- }
- //Binder 本地代理对象
- private static class Proxy implements com.example.myview.binder.MyWindowManager {
- 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 sysout() throws Android.os.RemoteException {
- Android.os.Parcel _data = Android.os.Parcel.obtain();
- Android.os.Parcel _reply = Android.os.Parcel.obtain();
- try {
- _data.writeInterfaceToken(DESCRIPTOR);
- mRemote.transact(Stub.TRANSACTION_sysout, _data, _reply, 0);
- _reply.readException();
- } finally {
- _reply.recycle();
- _data.recycle();
- }
- }
- }
- static final int TRANSACTION_basicTypes = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
- static final int TRANSACTION_sysout = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
- }
- public void sysout() throws Android.os.RemoteException;
- }
MyWindowManager 继承了 IInterface, 是 Client 和 Server 通信的接口
Stub 为静态抽象内部类, 继承了 Binder. 其子类需要实现 MyWindowManager 接口, 是 Server 的 Binder 的本地对象
Stub.Proxy 为静态内部类, 内部包含了 IBinder 对象, 是 Server 在 Client 中的本地代理对象, 将参数序列化后交给 mRemote 处理, 实现了跟远程 Stub 的通信
asInterface 方法通常是 Client 在 bindService 成功后, 由 Client 来调用的, 作用是将绑定成功后返回的 IBinder 对象转换为具体的 IInterface 接口. Client 拿到这个 IInterface 接口后跟 Server 进行通信
(3)Server 端提供方法的具体实现
- public class MyWindowManagerService extends Service {
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return mWindowManager;
- }
- private final MyWindowManager.Stub mWindowManager = new MyWindowManager.Stub() {
- @Override
- public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble,
- String aString) throws RemoteException {
- }
- @Override
- public void sysout() throws RemoteException {
- Log.e("hj", "sysout:" );
- }
- };
- }
(4)其他进程的 Activity 实现跟 Service 的通信
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- Intent intent = new Intent(this, MyWindowManagerService.class);
- bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
- }
- ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- MyWindowManager windowManager = MyWindowManager.Stub.asInterface(service);
- try {
- windowManager.sysout();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- };
- }
2,IBinder/IInterface/Binder/BinderProxy/Stub
IBinder : IBinder 是一个接口, 代表了一种跨进程通信的能力. 只要实现了这个借口, 这个对象就能跨进程传输.
IInterface : IInterface 代表的就是 Server 进程对象提供了哪些方法
Binder : Java 层的 Binder 类, 代表的其实就是 Binder 本地对象. Proxy 类是 Binder 类的一个内部类, 它代表远程进程的 Binder 对象的本地代理; 这两个类都继承自 IBinder, 因而都具有跨进程传输的能力; 实际上, 在跨越进程的时候, Binder 驱动会自动完成这两个对象的转换.
Stub : AIDL 的时候, 编译工具会给我们生成一个名为 Stub 的静态内部类; 这个类继承了 Binder, 说明它是一个 Binder 本地对象, 它实现了 IInterface 接口, 表明它具有 Server 承诺给 Client 的能力; Stub 是一个抽象类, 具体的 IInterface 的相关实现需要自己实现.
参考文章:
Android Binder 设计与实现 - 设计篇
为什么 Android 要采用 Binder 作为 IPC 机制?
写给 Android 应用工程师的 Binder 原理剖析 https://zhuanlan.zhihu.com/p/35519585
来源: https://juejin.im/post/5c5bd0e0e51d457fa83a4d5b