内容简介:Binder机制在Android系统中地位毋庸置疑,system_server就通过Binder来实现进程间的通信,从而达到管理、调用一系列系统服务的能力。本文就AIDL来解读一下Binder机制的。 先了解一下如下几个概念:还有一点需要说明一下:当一个Service向AMS进行注册时,传递的过去的以及保存在AMS中的是一个Binder对象。当Client需要跟Service进行通信,通过AMS查询到其实是一个BinderProxy,因为可以有多个Client同时跟Service进行通信。当然如果Servi
Binder机制在Android系统中地位毋庸置疑,system_server就通过Binder来实现进程间的通信,从而达到管理、调用一系列系统服务的能力。本文就AIDL来解读一下Binder机制的。 先了解一下如下几个概念:
IBinder 、 Binder 、 BinderProxy 、 IInterface
- IBinder : 根据官方的说明文档IBinder定义的是一种使对象具备远程通信能力的接口,他的子类是Binder。IBinder内部预先定义了一些IPC需要用到的接口,实现IBinder的对象可以被Binder Drivder在IPC过程中传递;
- Binder : 实现了IBinder,具备IPC通信的能力。在IPC通信过程中,Binder代表的是Server的本地对象;
- BinderProxy : BinderProxy是Binder的内部类,同样实现了IBinder,不同于Binder的是,BinderProxy是Binder对象在Client端的一个代理,用以提供Server具备的接口;
- IInterface : 代表的是Server所具备的接口;
还有一点需要说明一下:当一个Service向AMS进行注册时,传递的过去的以及保存在AMS中的是一个Binder对象。当Client需要跟Service进行通信,通过AMS查询到其实是一个BinderProxy,因为可以有多个Client同时跟Service进行通信。当然如果Service和Client在同一进程,AMS返回的还是一个Binder对象,毕竟没有必要进行IPC。 在进行IPC时,Binder Drivder会在中间帮忙转换Binder和BinderProxy。
AIDL
还是按照 Android Service详解(二) 的例子来解释
现在我们来看一下系统自动生成的aidl文件具体有些什么:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: /Users/lebens/Development/WorkSpace/jxx_workspace/Server/app/src/main/aidl/jxx/com/server/aidl/IServerServiceInfo.aidl */ package jxx.com.server.aidl; public interface IServerServiceInfo extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements jxx.com.server.aidl.IServerServiceInfo { private static final java.lang.String DESCRIPTOR = "jxx.com.server.aidl.IServerServiceInfo"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an jxx.com.server.aidl.IServerServiceInfo interface, * generating a proxy if needed. */ public static jxx.com.server.aidl.IServerServiceInfo asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof jxx.com.server.aidl.IServerServiceInfo))) { return ((jxx.com.server.aidl.IServerServiceInfo)iin); } return new jxx.com.server.aidl.IServerServiceInfo.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 { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_getServerInfo: { data.enforceInterface(descriptor); jxx.com.server.aidl.ServerInfo _result = this.getServerInfo(); reply.writeNoException(); if ((_result!=null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_setServerInfo: { data.enforceInterface(descriptor); jxx.com.server.aidl.ServerInfo _arg0; if ((0!=data.readInt())) { _arg0 = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.setServerInfo(_arg0); reply.writeNoException(); if ((_arg0!=null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements jxx.com.server.aidl.IServerServiceInfo { 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 jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); jxx.com.server.aidl.ServerInfo _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getServerInfo, _data, _reply, 0); _reply.readException(); if ((0!=_reply.readInt())) { _result = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void setServerInfo(jxx.com.server.aidl.ServerInfo serverinfo) 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 ((serverinfo!=null)) { _data.writeInt(1); serverinfo.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_setServerInfo, _data, _reply, 0); _reply.readException(); if ((0!=_reply.readInt())) { serverinfo.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getServerInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_setServerInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException; public void setServerInfo(jxx.com.server.aidl.ServerInfo serverinfo) throws android.os.RemoteException; } 复制代码
- 这个文件中,我们看到IServerServiceInfo实现了IInterface,说明IServerServiceInfo具备了IPC通信需要的接口,最底下我们也可以看到定义的getServerInfo()、setServerInfo()两个方法;
- 接着来看Stub这个对象,它是IServerServiceInfo的静态内部类,继承了Binder同时实现了IServerServiceInfo。这意味着Stub可以通过Binder Driver进行进程间传递,同时又具备了IPC所需要的接口,实际我们在Service中asBinder()返回的就是这个对象;
- Proxy对象,这又是一个代理对象,不过代理的是BinderProxy。这个对象存在的意思就是代理BinderProxy,将Client的操作转化成BinderProxy去跟Server通信。
- Proxy 和 Stub 的区别在于,Stud本身就是一个Binder对象,可以直接被Binder Driver传递,而Proxy只是代表Service提供的IPC接口,实际使用内部的被代理的mRemote来实现IPC。
Stub
关于Stub再来看几点:
- DESCRIPTOR : 这是用来唯一表示Stub的,当Stub被实例化时会通过DESCRIPTOR来保存owner对象,也就是Stub所代表的IInterface,同时在queryLocalInterface如果是在同一进程查询的话就是返回的Stub;
- TRANSACTION_getServerInfo 、 TRANSACTION_setServerInfo : 这两个用来标识Client操作的接口方法。
- asInterface : 这个方法就是将Binder,转换成Client需要的接口对象,如果Binder Driver返回的是一个BinderProxy对象,则创建一个Proxy返回给Client。
- onTransact : 这个方法跟下面的Proxy对象一同分析。
Proxy
- mRemote : 这是一个BinderProxy对象,由Binder Driver传递而来。Proxy的IPC都是通过mRemote来实现的;
- 这里我们还看到的了我们定义的接口方法,这些方法都是提供给Client使用的,用于跟Server通信;
- mRemote的transact() : 在Binder Driver的帮助下,最终会调用到Stub的onTransact()中。
onTransact()
以getServerInfo()为例来分析一下onTransact传递过程。 首先我们在Proxy的实现是这样的
@Override public jxx.com.server.aidl.ServerInfo getServerInfo() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); jxx.com.server.aidl.ServerInfo _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(IServerServiceInfo.Stub.TRANSACTION_getServerInfo, _data, _reply, 0); _reply.readException(); if ((0!=_reply.readInt())) { _result = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; } 复制代码
- _data 、 _reply 分别用于Client向Server传递参数和Server向Client返回结果,这2个内的参数都是要序列化的,毕竟IPC;
- 通过mRemote.transact开始调用Server的方法;
- 通过_reply读取Server返回的数据,并反序列化结果,将之返回;
从上面的分析可以知道,这里的mRemote其实是一个BinderProxy对象,我们去看一下这个方法
/** * Default implementation rewinds the parcels and calls onTransact. On * the remote side, transact calls into the binder to do the IPC. */ public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; } 复制代码
最终调用的是Binder内的onTransact(),也就是Stub的onTransact(),我们来看一下
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_getServerInfo: { data.enforceInterface(descriptor); jxx.com.server.aidl.ServerInfo _result = this.getServerInfo(); reply.writeNoException(); if ((_result!=null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_setServerInfo: { data.enforceInterface(descriptor); jxx.com.server.aidl.ServerInfo _arg0; if ((0!=data.readInt())) { _arg0 = jxx.com.server.aidl.ServerInfo.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.setServerInfo(_arg0); reply.writeNoException(); if ((_arg0!=null)) { reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } default: { return super.onTransact(code, data, reply, flags); } } 复制代码
在内部可以看到case TRANSACTION_getServerInfo 下的操作其实也是很简单,就是把Client需要的结果通过reply传递回Client
总结
通过上面的代码分析,AIDL我们可以快速实现IPC,我们来总结一下:
- Server需要定义提供给Client的接口,也即实现IInterface,同时还要提供一个Binder用来供Binder Driver找到Server,通过DESCRIPTOR确定;
- Client在跟Server通信之前需要获得一个Binder或者BinderProxy对象,通过Binder Driver跟Server建立联系;
- Binder Driver在通信过程中自动转换了BinderProxy 和 Binder;
通过这个例子的分析,其实系统的AMS管理各种系统服务也是同样的套路,通过2个Binder建立通信。
还有一点需要注意: Binder或者BinderProxy都是运行在他们自己的Binder池中的,也就是直接通过Binder通信的话,需要注意线程切换
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 快速失败机制 & 失败安全机制
- JavaScript线程机制与事件机制
- 区块链是怎样将分布式组网机制、合约机制、共识机制等技术结合并应用
- Java内存机制和GC回收机制-----笔记
- javascript垃圾回收机制 - 标记清除法/引用计数/V8机制
- Android 8.1 源码_机制篇 -- 全面解析 Handler 机制(原理篇)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
恰如其分的软件架构
George Fairbanks / 张逸、倪健、高翌翔 / 华中科技大学出版社 / 2013-9-1 / 88.00
本书描述了一种恰如其分的软件架构设计方法。作者建议根据项目面临的风险来调整架构设计的成本,并从多个视角阐述了软件架构的建模过程和方法,包括用例模型、概念模型、域模型、设计模型和代码模型等。本书不仅介绍方法,而且还对方法和概念进行了归类和阐述,将软件架构设计融入开发实践中,与 敏捷开发方法有机地结合在一起,适合普通程序员阅读。 . 这是一本超值的书,案例丰富有趣,言简意赅,阅读轻松。当年......一起来看看 《恰如其分的软件架构》 这本书的介绍吧!