Binder 和 AIDL
16lz
2021-01-26
Link:
IPC__ALL
前言
- Binder 是 Android中的一个类,它实现了 IBinder接口。从IPC角度说,Binder 是Android中的一种跨进程通信的方式。
- 从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager,etc)和相应ManagerService的桥梁。
- 从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务。
AIDL 支持的数据类型
- 基本数据类型
int、long、char、boolean、double 等 - String 和 CharSequence
- List:
只支持ArrayList,里面的每一个元素都必须能够被 AIDL 支持 - Map:
只支持 HashMap,里面的每一个元素都必须能够被 AIDL 支持 - Parcelable:
所有实现了 Parcelable 接口的对象 - AIDL:
所有的 AIDL 接口本身也可以在 AIDL文件中使用。
Binder 通信示意图
Binder 的工作机制
跨进程通信的接口, AIDL的包名需要与项目的包名相同, 默认生成即可.
Binder 工作原理分析
可以查看我的相关文章 代理模式
示例:
1. 添加AIDL文件
- Book.aidl
// Book.aidlpackage com.jack.jack_aidl_demo;// Declare any non-default types here with import statementsimport com.jack.jack_aidl_demo.Book;//Book 类在 AIDL 中的声明parcelable Book;
- IBookManager.aidl
// IBookManager.aidlpackage com.jack.jack_aidl_demo;// Declare any non-default types here with import statementsimport com.jack.jack_aidl_demo.Book;interface IBookManager { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); List getBookList(); void addBook(in Book b);}
Paste_Image.png 这样IDE 就能在:
C:\myWidget\temp\Jack_Aidl_demo\app\build\generated\source\aidl\debug\com\jack\jack_aidl_demo\下生成 IBookManager.java,我们看一下,注释非常详细!
注意
如果AIDL文件中用到了自定义的 Parcelable 对象,那么必须新建一个和它同名的AIDL文件,并在其中声明它为 Parcelable 类型。在上面的
IBookManager.aidl 中,我们用到了Book类,所以必须创建 Book.aidl,然后在里面添加内容。
/* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\myWidget\\temp\\Jack_Aidl_demo\\app\\src\\main\\aidl\\com\\jack\\jack_aidl_demo\\IBookManager.aidl */package com.jack.jack_aidl_demo;//代理模式——相当于抽象主题类public interface IBookManager extends android.os.IInterface { /** * Local-side IPC implementation stub class. * 代理模式——相当于真实主题类(这边是个抽象类,要服务端完成它的功能,服务端完成类才是真正的真实主题) */ public static abstract class Stub extends android.os.Binder implements com.jack.jack_aidl_demo.IBookManager { private static final java.lang.String DESCRIPTOR = "com.jack.jack_aidl_demo.IBookManager"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.jack.jack_aidl_demo.IBookManager interface, * generating a proxy if needed. * 用于将服务器 Binder 对象转化为客户端所需的 AIDL 接口类型对象 */ public static com.jack.jack_aidl_demo.IBookManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.jack.jack_aidl_demo.IBookManager))) { //1. 客户端与服务器位于同一进程,返回服务器的Stub对象本身 return ((com.jack.jack_aidl_demo.IBookManager) iin); } //2. 客户端与服务器位于不同一进程,返回系统封装的Stub.Proxy 对象 return new com.jack.jack_aidl_demo.IBookManager.Stub.Proxy(obj); } //返回当前 Binder 对象 @Override public android.os.IBinder asBinder() { return this; } /** * 运行在服务器的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装交由此方法处理。 * 1.code确定客户端请求的方法是什么 * 2.data取出目标方法所需参数,如果需要,然后执行目标方法。 * 3.目标方法执行完,向reply中写入返回值。 * 4.方法的返回值 true代表请求成功,false代表请求失败,可以用来权限认证 */ @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_getBookList: { data.enforceInterface(DESCRIPTOR); java.util.List _result = this.getBookList(); reply.writeNoException(); reply.writeTypedList(_result); return true; } case TRANSACTION_addBook: { data.enforceInterface(DESCRIPTOR); com.jack.jack_aidl_demo.Book _arg0; if ((0 != data.readInt())) { _arg0 = com.jack.jack_aidl_demo.Book.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.addBook(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } /** * 代理模式——相当于代理类 * 这是客户端的代理,客户端就是通过它实现和服务器的交互 */ private static class Proxy implements com.jack.jack_aidl_demo.IBookManager { private android.os.IBinder mRemote; /** * 代理模式——真实主题传入 * @param remote */ 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(); } } /** * 运行在客户端 * @return * @throws android.os.RemoteException */ @Override public java.util.List getBookList() throws android.os.RemoteException { //输入型对象 android.os.Parcel _data = android.os.Parcel.obtain(); //输出型对象 android.os.Parcel _reply = android.os.Parcel.obtain(); //返回值对象 java.util.List _result; try { _data.writeInterfaceToken(DESCRIPTOR); //发起RPC(远程调用),客户端线程挂起,不应该在ui线程调用 mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0); _reply.readException(); //从输出型对象取出返回值 _result = _reply.createTypedArrayList(com.jack.jack_aidl_demo.Book.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook(com.jack.jack_aidl_demo.Book b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((b != null)) { _data.writeInt(1); b.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addBook, _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_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); } /** * 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 java.util.List getBookList() throws android.os.RemoteException; public void addBook(com.jack.jack_aidl_demo.Book b) throws android.os.RemoteException;}
当客户端远程调用
这样我们应该对Binder机制了解了!
注意点
- 当客户端发起远程请求时,由于当前线程会被挂起直至服务器进程返回,所以如果一个远程方法是很耗时的,那么不能再UI线程中发起此远程请求。
- 由于服务器的 Binder 方法运行在 Binder线程池中,所以 Binder方法不管是否耗时都应该采用同步的方式去实现,因为它已经运行在一个线程中了。
示例地址
请戳我的github:Jack_Aidl_demo
参考资料:
- 任玉刚的 Android Binder机制浅析,和 《Android 开发艺术探索》。
更多相关文章
- android调用java的web service接口
- Android在线更新版本(服务端+客户端Code)
- Android(安卓)WebView中无法用JS调用Java对象的问题
- Android学习笔记:通过Android之Service实现文件断点续传下载
- Android(安卓)异步任务 设置 超时使用handler更新通知功能
- [Android]网络资源下载时断点续传的实现
- Android(安卓)Studio创建Serializable对象时自动生成serialVersi
- Android(安卓)ANR问题定位
- Android资源加载机制