Binder实现分析
来源:互联网 发布:西安美林数据 怎么样 编辑:程序博客网 时间:2024/06/08 05:25
我在之前的一篇文章AIDL最佳实践中通过AIDL接口成功完成了进程间通信。那今天就从应用层的角度分析一下,来加深对Binder机制的了解。
首先来看AIDL最佳实践中的AIDL文件,IMyAidl.aidl:
interface IMyAidl { int add(int num1,int num2); List<Dog> addDog(in Dog dog);}
以及编译器根据AIDL文件生成的.java文件,IMyAidl.java:
public interface IMyAidl extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.aidl.tsnt.server.IMyAidl { private static final java.lang.String DESCRIPTOR = "com.aidl.tsnt.server.IMyAidl"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.aidl.tsnt.server.IMyAidl interface, * generating a proxy if needed. */ public static com.aidl.tsnt.server.IMyAidl asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.aidl.tsnt.server.IMyAidl))) { return ((com.aidl.tsnt.server.IMyAidl) iin); } return new com.aidl.tsnt.server.IMyAidl.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_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; } case TRANSACTION_addDog: { data.enforceInterface(DESCRIPTOR); com.aidl.tsnt.server.Dog _arg0; if ((0 != data.readInt())) { _arg0 = com.aidl.tsnt.server.Dog.CREATOR.createFromParcel(data); } else { _arg0 = null; } java.util.List<com.aidl.tsnt.server.Dog> _result = this.addDog(_arg0); reply.writeNoException(); reply.writeTypedList(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.aidl.tsnt.server.IMyAidl { 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 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; } @Override public java.util.List<com.aidl.tsnt.server.Dog> addDog(com.aidl.tsnt.server.Dog dog) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.aidl.tsnt.server.Dog> _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((dog != null)) { _data.writeInt(1); dog.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_addDog, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(com.aidl.tsnt.server.Dog.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_addDog = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public int add(int num1, int num2) throws android.os.RemoteException; public java.util.List<com.aidl.tsnt.server.Dog> addDog(com.aidl.tsnt.server.Dog dog) throws android.os.RemoteException;}
从上述自动生成的代码可以看出,IMyAidl.java继承了IInterface 接口,当然它自己也是一个接口。所有可以在Binder机制中传输的接口都需要继承IInterface 。
这个接口的结构实际上还是很清晰的,它声明了两个方法add()和addDog(),显然这是我们在IMyAidl.aidl中所声明的方法。同时它还声明了两个整型标识符TRANSACTION_add和TRANSACTION_addDog用于在onTransact()中区别客户端所请求的方法。
它还声明了一个内部类Stub,它就是一个Binder类。当客户端和服务端位于同一进程时,方法调用不会走跨进程的transact();而当客户端和服务端位于不同进程时,方法调用需要走transact(),这个逻辑由Stub的内部代理类Proxy来完成。
这么来看IMyAidl这个接口很简单,这个接口的核心实现就是它的内部类Stub和Stub的内部代理类Proxy。
下面来介绍其中的方法和标识符:
DESCRIPTOR: Binder的唯一标识,一般用当前Binder的类名来表示,这里就是“com.aidl.tsnt.server.IMyAidl”。
asInterface():
/** * Cast an IBinder object into an com.aidl.tsnt.server.IMyAidl interface, * generating a proxy if needed. */ public static com.aidl.tsnt.server.IMyAidl asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.aidl.tsnt.server.IMyAidl))) { return ((com.aidl.tsnt.server.IMyAidl) iin); } return new com.aidl.tsnt.server.IMyAidl.Stub.Proxy(obj); }
从方法上的注释就可以看出,这个方法用来将服务端的Binder对象转化为客户端所需要的AIDL接口类型的对象。这种转换是区分进程的,如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的Stub对象本身,否则返回的是系统封装后的Stub.Proxy对象。
asBinder():
@Override public android.os.IBinder asBinder() { return this; }
用来返回Stub(Binder)对象本身。
onTransact():
@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_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; } case TRANSACTION_addDog: { data.enforceInterface(DESCRIPTOR); com.aidl.tsnt.server.Dog _arg0; if ((0 != data.readInt())) { _arg0 = com.aidl.tsnt.server.Dog.CREATOR.createFromParcel(data); } else { _arg0 = null; } java.util.List<com.aidl.tsnt.server.Dog> _result = this.addDog(_arg0); reply.writeNoException(); reply.writeTypedList(_result); return true; } } return super.onTransact(code, data, reply, flags); }
这个方法运行在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。服务端根据code可以确定客户端请求的方法是什么,接着从data中取出目标方法所需要的参数,然后执行目标方法。当目标方法执行完毕后,再向reply中写入返回值。如果此方法返回false,那么客户端请求会失败,我们可以利用这个特性来对权限进行验证。
transact():
我们在Stub.Proxy的add()和addDog()两个方法中都看到了 mRemote.transact(),可以猜测这个transact()应该最终就是调用onTransact()。然后我们看到Binder的onTransact()的注释:
/** * Default implementation is a stub that returns false. You will want * to override this to do the appropriate unmarshalling of transactions. * * <p>If you want to call this, call transact(). */ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { …… }
果然,注释最后一行表达的意思就是如果你要调用onTransact(),请调用transact()。
通过上面的分析,我们大概从应用层了解了Binder的工作机制。
如果要从内核和framework层更深入地了解,可以看这几篇文章:
1.Binder进程间通信机制概述(Android系统源代码情景分析学习笔记)
2.Binder系统中的数据结构(Android系统源代码情景分析学习笔记)
3.Android Binder设计与实现 - 设计篇
还有两点要注意的是:
当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法很耗时,那就不能在UI线程中发起请求。
服务端的Binder方法运行在Binder线程池中,所以Binder中的方法不管是否耗时都应该采用同步的方法去实现,因为它已经运行在一个单独的线程中了。
实现分析到此完毕,当然我们也可以不借助AIDL,自己实现Binder。
- Binder实现分析
- 如何使用Binder实现分析
- Binder实现机制--应用分析
- binder 分析
- binder分析
- binder 分析
- Android Binder 修炼之道(三)Binder 系统C++实现 BpXXX代理类分析
- Binder 核心分析
- Android Binder IPC分析
- binder 实例分析
- Android Binder IPC分析
- Android Binder IPC分析
- Android Binder机制分析
- android binder分析
- Android Binder IPC分析
- binder 实例分析
- Binder通信流程分析
- Android - Binder应用分析
- undefined 以及 is not defined
- C++的输出入cin/cout和scanf/printf谁比较快?
- D
- cxf 服务端生成客户端的代码
- Java面试准备
- Binder实现分析
- 相机的使用
- ElasticSearch聚合
- 树莓派3设置samba文件共享
- 简易多线程编程
- Spring AOP增强小例子
- Java序列化(实现Serializable接口)作用
- 技术点-ActiveMQ-概念性总结
- 升级到xcode8.3.3后,Apple Mach-O Linker Error 看不到详细信息了