写点什么

Android 进阶——Android 跨进程通讯机制之 Binder、IBinder

用户头像
Android架构
关注
发布于: 2021 年 11 月 07 日

**五、简单的总结** 将前面的所有概念连接起来理解就会非常好消化知识点: 1.Linux 的虚拟内存机制导致内存的隔离,进而导致进程隔离 2.进程隔离的出现导致对内存的操作被划分为用户空间和内核空间 3.用户空间需要跨权限去访问内核空间,必须使用系统调用去实现 4.系统调用需要借助内核模块/驱动去完成 前三步决定了进程间通讯需要借助内核模块/驱动去实现,而 Binder 驱动就是内核模块/驱动中用来实现进程间通讯的 ###为什么要用 Binder Linux 提供有管道、消息队列、信号量、内存共享、套接字等跨进程方式,那为什么 Android 要选择 Binder 另起炉灶呢? **一、传输性能好** * Socket:是一个通用接口,导致其传输效率低,开销大 * 共享内存:虽然在传输时不需要拷贝数据,但其控制机制复杂 * Binder:复杂数据类型传递可以复用内存,需要拷贝 1 次数据 * 管道和消息队列:采用存储转发方式,至少需要拷贝 2 次数据,效率低 **二、安全性高** * 传统的进程:通信方式对于通信双方的身份并没有做出严格的验证,只有在上层协议上进行架设 * Binder 机制:从协议本身就支持对通信双方做身份校检,因而大大提升了安全* 性 ###Binder 通信模型 首先在理解模型之前先熟悉这几个概念: * Client 进程:跨进程通讯的客户端(运行在某个进程) * Server 进程:跨进程通讯的服务端(运行在某个进程) Binder 驱动:跨进程通讯的介质 * ServiceManager:跨进程通讯中提供服务的注册和查询(运行在 System 进程) ![](https://static001.geekbang.org/infoq/09/096da100f221b593a0f11d2b9ed87bd9.png) 这里只是个简单的模型而已,只需理解模型的通讯流程: 1.Server 端通过 Binder 驱动在 ServiceManager 中注册 2.Client 端通过 Binder 驱动获取 ServiceManager 中注册的 Server 端 3.Client 端通过 Binder 驱动和 Server 端进行通讯 ###Binder 通信原理 ![](https://upload-images.jianshu.io/upload_images/22459598-b36b3bdec1a9de99.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/ ``` 《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》 浏览器打开:qq.cn.hn/FTe 免费领取 ``` 1240) 理解完模型流程之后,开始理解模型的通讯原理: 1.Service 端通过 Binder 驱动在 ServiceManager 的查找表中注册 Object 对象的 add 方法 2.Client 端通过 Binder 驱动在 ServiceManager 的查找表中找到 Object 对象的 add 方法,并返回 proxy 对象的 add 方法,add 方法是个空实现,proxy 对象也不是真正的 Object 对象,是通过 Binder 驱动封装好的代理类的 add 方法 3.当 Client 端调用 add 方法时,Client 端会调用 proxy 对象的 add 方法,通过 Binder 驱动去请求 ServiceManager 来找到 Service 端真正对象,然后调用 Service 端的 add 方法 ###Binder 对象和 Binder 驱动 * Binder 对象:Binder 机制中进行进程间通讯的对象,对于 Service 端为 Binder 本地对象,对于 Client 端为 Binder 代理对象 * Binder 驱动:Binder 机制中进行进程间通讯的介质,Binder 驱动会对具有跨进程传递能力的对象做特殊处理,自动完成代理对象和本地对象的转换 由于 Binder 驱动会对具有跨进程传递能力的对象做特殊处理,自动完成代理对象和本地对象的转换,因此在驱动中保存了每一个跨越进程的 Binder 对象的相关信息,Binder 本地对象(或 Binder 实体)保存在 binder_node 的数据结构,Binder 代理对象(或 Binder 引用/句柄)保存在 binder_ref 的数据结构 ###Java 层的 Binder * Binder 类:是 Binder 本地对象 * BinderProxy 类:是 Binder 类的内部类,它代表远程进程的 Binder 对象的本地代理 * Parcel 类:是一个容器,它主要用于存储序列化数据,然后可以通过 Binder 在进程间传递这些数据 * IBinder 接口:代表一种跨进程传输的能力,实现这个接口,就能将这个对象进行跨进程传递 * IInterface 接口:client 端与 server 端的调用契约,实现这个接口,就代表远程 server 对象具有什么能力,因为 IInterface 接口的 asBinder 方法的实现可以将 Binder 本地对象或代理对象进行返回 Binder 类和 BinderProxy 类都继承自 IBinder,因而都具有跨进程传输的能力,在跨越进程的时候,Binder 驱动会自动完成这两个对象的转换。IBinder 是远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分,但它不仅用于远程调用,也用于进程内调用。IBinder 接口定义了与远程对象交互的协议,建议不要直接实现这个接口,而应该从 Binder 派生。Binder 实现了 IBinder 接口,但是一般不需要直接实现此类,而是跟据你的需要由开发包中的工具生成,这个工具叫 aidi。你通过 aidi 语言定义远程对象的方法,然后用 aidi 工具生成 Binder 的派生类,然后使用它 ###AIDL 由于编译工具会给我们生成一个 Stub 的静态内部类,这个类继承了 Binder, 说明它是一个 Binder 本地对象,它实现了 IInterface 接口,表明它具有远程 Server 承诺给 Client 的能力 **一、服务端** 在服务端中,我们只要实现 Stub 抽象类,和实现其方法即可 private IBinder myS = new IMyAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public int add(int num1, int num2) throws RemoteException { Log.i("Hensen", "从客户端发来的 AIDL 请求:num1->" + num1 + "::num2->" + num2); return num1 + num2; } }; **二、客户端** 在客户端中,可以通过 bindService 的回调中获取 AIDL 接口 private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { iMyAidlInterface = null; } }; public void add(View view) { try { int res = iMyAidlInterface.add(1, 2); Log.i("Hensen", "从服务端调用成功的结果:" + res); } catch (RemoteException e) { e.printStackTrace(); } } 梳理客户端的调用流程: 1.调用 Stub.asInterface 获取 BinderProxy 对象 2.调用 BinderProxy 对象的 add 方法 **三、分析原理** 1、Stub Stub 类继承自 Binder,意味着这个 Stub 其实自己是一个 Binder 本地对象,然后实现了 IMyAidlInterface 接口,IMyAidlInterface 本身是一个 IInterface,因此他携带某种客户端需要的能力(这里是方法 add)。此类有一个内部类 Proxy,也就是 Binder 代理对象 /* * This file is auto-generated. DO NOT MODIFY. * Original file: D:\\workspace5\\Boke\\app\\src\\main\\aidl\\com\\handsome\\boke\\IMyAidlInterface.aidl */ package com.handsome.boke; // Declare any non-default types here with import statements public interface IMyAidlInterface extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.handsome.boke.IMyAidlInterface { private static final java.lang.String DESCRIPTOR = "com.handsome.boke.IMyAidlInterface"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.handsome.boke.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.handsome.boke.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.handsome.boke.IMyAidlInterface))) { return ((com.handsome.boke.IMyAidlInterface) iin); } return new com.handsome.boke.IMyAidlInterface.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 { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_basicTypes: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); long _arg1; _arg1 = data.readLong(); boolean _arg2; _arg2 = (0 != data.readInt()); float _arg3; _arg3 = data.readFloat(); double _arg4; _arg4 = data.readDouble(); java.lang.String _arg5; _arg5 = data.readString(); this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); reply.writeNoException(); return true; } case TRANSACTION_add: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.handsome.boke.IMyAidlInterface { 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; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(anInt); _data.writeLong(aLong); _data.writeInt(((aBoolean) ? (1) : (0))); _data.writeFloat(aFloat); _data.writeDouble(aDouble); _data.writeString(aString); mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public int add(int num1, int num2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(num1); _data.writeInt(num2); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException; public int add(int num1, int num2) throws android.os.RemoteException; } 2、asInterface

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android进阶——Android跨进程通讯机制之Binder、IBinder