🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 概要 ![](https://img.kancloud.cn/8e/2b/8e2bbf0ac592f8f25eeb5d4ec3d13be4_1288x502.png) ## AIDL ### 使用方法 服务端:1.创建接口,2.定义binder,实现接口,3.创建服务,返回binder; 客户端:1.绑定服务,2.实现ServiceConnection绑定监听,3.在绑定成功的回调中,将IBinder转换成AIDL的接口代理对象。 客户端和服务端绑定成功后,就可以通过AIDL的接口代理对象,就像直接调用本地方法一样,调用服务端的方法了。需要注意的是,AIDL间传递的对象要实现Parcelable接口。 ### 绑定过程 客户端先调用bindService方法,发起绑定服务的请求,通过ServiceManager,拿到ActivityManagerService,也就是AMS,然后通过AMS向服务端发起bindService的请求。然后服务端接收到绑定请求,以Handler消息机制的方式,发送一个绑定服务的Message,然后在ActivityThread中处理这个绑定请求,调用onBind函数,并返回对应的IBinder对象。这个返回IBinder对象的操作,基本就和绑定过程的通过ServiceManager、AMS类似了。 ### AIDL和Binder的关系 AIDL的使用实质就是对Binder机制的封装,主要就是将Binder封装成一个代理对象proxy,从用户的角度看,就像是客户端直接调用了服务端的代码。 ## oneway ### 主要有两个特性: oneway 主要有两个特性:异步调用和串行化处理。异步调用是指应用向 binder 驱动发送数据后不需要挂起线程等待 binder 驱动的回复,而是直接结束。像一些系统服务调用应用进程的时候就会使用 oneway,比如 AMS 调用应用进程启动 Activity,这样就算应用进程中做了耗时的任务,也不会阻塞系统服务的运行。 ### binder 协议 非oneway ![](https://img.kancloud.cn/49/1a/491a646523ad76742f0c54cfa6599992_1200x830.png) 如果是 oneway 的话,客户端就不需要挂起线程等待: ![](https://img.kancloud.cn/bd/ee/bdee05a63e30486474fe6ee0151427f4_1200x560.png) 涉及到的 binder 命令也有规律,由外部发送给 binder 驱动的都是 BC\_ 开头,由 binder 驱动发往外部的都是 BR\_开头。 ### 怎么理解客户端线程挂起等待呢?有没有实际占用 CPU 的调度? 这里的挂起相当于 Thread 的 sleep,是真正的"休眠",底层调用的是 waiteventinterruptible() Linux 系统函数。 ### waiteventinterruptible函数 Handle 中最关键的地方就是 Looper 的阻塞与唤醒,阻塞是调用了 nativePollOnce() 方法,当时对它的底层实现感兴趣,就去了解了一下,也学习到 Linux 用来实现阻塞/唤醒的 select、poll 和 epoll 机制 ## Intent 直接传 Bitmap Bitmap 太大会抛 TransactionTooLargeException 异常,原因是:底层判断只要 Binder Transaction 失败,且 Intent 的数据大于 200k 就会抛这个异常了。(见:android\_util\_Binder.cpp 文件 signalExceptionForError 方法) ### Intent 传值会有大小限制。 应用进程在启动 Binder 机制时会映射一块 1M 大小的内存,所有正在进行的 Binder 事务共享这 1M 的缓冲区 。当使用 Intent 进行 IPC 时申请的缓存超过 1M - 其他事务占用的内存时,就会申请失败抛 TransactionTooLargeException 异常了 ### 绕开这个限制呢? 通过 AIDL 使用 Binder 进行 IPC 就不受这个限制,具体代码如下: ``` Bundle bundle = new Bundle(); bundle.putBinder("binder", new IRemoteGetBitmap.Stub() { @Override public Bitmap getBitMap() throws RemoteException { return mBitmap; } }); intent.putExtras(bundle); ``` ### 总结 较大的 bitmap 直接通过 Intent 传递容易抛异常是因为 Intent 启动组件时,系统禁掉了文件描述符 fd 机制 , bitmap 无法利用共享内存,只能拷贝到 Binder 映射的缓冲区,导致缓冲区超限, 触发异常; 而通过 putBinder 的方式,避免了 Intent 禁用描述符的影响,bitmap 写 parcel 时的 allowFds 默认是 true , 可以利用共享内存,所以能高效传输图片。 # 参考资料 [Android 深入浅出AIDL(二)](https://blog.csdn.net/qian520ao/article/details/78074983) [看你简历上写熟悉 AIDL,说一说 oneway 吧](https://juejin.cn/post/6844904147947356173) [Android Binder 原理分析](https://juejin.cn/post/6874616109266370568) [跨进程传递大图,你能想到哪些方案呢?](https://juejin.cn/post/6844904182126739470)