Binder机制在Android系统中地位毋庸置疑,system_server就通过Binder来实现进程间的通信,从而达到管理、调用一系列系统服务的能力。本文就AIDL来解读一下Binder机制的。 先了解一下如下几个概念:

IBinder 、 Binder 、 BinderProxy 、 IInterface

  1. IBinder : 根据官方的说明文档IBinder定义的是一种使对象具备远程通信能力的接口,他的子类是Binder。IBinder内部预先定义了一些IPC需要用到的接口,实现IBinder的对象可以被Binder Drivder在IPC过程中传递;
  2. Binder : 实现了IBinder,具备IPC通信的能力。在IPC通信过程中,Binder代表的是Server的本地对象;
  3. BinderProxy : BinderProxy是Binder的内部类,同样实现了IBinder,不同于Binder的是,BinderProxy是Binder对象在Client端的一个代理,Client通过BinderProxy间接跟Server进行通信;
  4. 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;
}
复制代码
  1. 这个文件中,我们看到IServerServiceInfo实现了IInterface,说明IServerServiceInfo具备了IPC通信需要的接口,最底下我们也可以看到定义的getServerInfo()、setServerInfo()两个方法;
  2. 接着来看Stub这个对象,它是IServerServiceInfo的静态内部类,继承了Binder同时实现了IServerServiceInfo。这意味着Stub可以通过Binder Driver进行进程间传递,同时又具备了IPC所需要的接口,实际我们在Service中asBinder()返回的就是这个对象;
  3. Proxy对象,这又是一个代理对象,不过代理的是BinderProxy。这个对象存在的意思就是代理BinderProxy,将Client的操作转化成BinderProxy去跟Server通信。
  4. Proxy 和 Stub 的区别在于,Stud本身就是一个Binder对象,可以直接被Binder Driver传递,而Proxy只是代表Service提供的IPC接口,实际使用内部的被代理的mRemote来实现IPC。

Stub

关于Stub再来看几点:

  1. DESCRIPTOR : 这是用来唯一表示Stub的,当Stub被实例化时会通过DESCRIPTOR来保存owner对象,也就是Stub所代表的IInterface,同时在queryLocalInterface如果是在同一进程查询的话就是返回的Stub;
  2. TRANSACTION_getServerInfo 、 TRANSACTION_setServerInfo : 这两个用来标识Client操作的接口方法。
  3. asInterface : 这个方法就是将Binder,转换成Client需要的接口对象,如果Binder Driver返回的是一个BinderProxy对象,则创建一个Proxy返回给Client。
  4. onTransact : 这个方法跟下面的Proxy对象一同分析。

Proxy

  1. mRemote : 这是一个BinderProxy对象,由Binder Driver传递而来。Proxy的IPC都是通过mRemote来实现的;
  2. 这里我们还看到的了我们定义的接口方法,这些方法都是提供给Client使用的,用于跟Server通信;
  3. 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;}
复制代码
  1. _data 、 _reply 分别用于Client向Server传递参数和Server向Client返回结果,这2个内的参数都是要序列化的,毕竟IPC;
  2. 通过mRemote.transact开始调用Server的方法;
  3. 通过_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,我们来总结一下:

  1. Server需要定义提供给Client的接口,也即实现IInterface,同时还要提供一个Binder用来供Binder Driver找到Server,通过DESCRIPTOR确定;
  2. Client在跟Server通信之前需要获得一个Binder或者BinderProxy对象,通过Binder Driver跟Server建立联系;
  3. Binder Driver在通信过程中自动转换了BinderProxy 和 Binder;

通过这个例子的分析,其实系统的AMS管理各种系统服务也是同样的套路,通过2个Binder建立通信。

还有一点需要注意: Binder或者BinderProxy都是运行在他们自己的Binder池中的,也就是直接通过Binder通信的话,需要注意线程切换

转载于:https://juejin.im/post/5ce26ada5188252d8f61f900

从AIDL一窥Android Binder机制相关推荐

  1. aidl使用_借助 AIDL 理解 Android Binder 机制——Binder 来龙去脉

    AIDL 是 Android Interface Definition Language(Android 接口定义语言)的缩写,它是 Android 进程间通信的接口语言.由于 Android 系统的 ...

  2. 理解Android Binder机制(3/3):Java层

    本文是Android Binder机制解析的第三篇,也是最后一篇文章.本文会讲解Binder Framework Java部分的逻辑. Binder机制分析的前面两篇文章,请移步这里: 理解Andro ...

  3. 理解Android Binder机制(1/3):驱动篇

    Binder的实现是比较复杂的,想要完全弄明白是怎么一回事,并不是一件容易的事情. 这里面牵涉到好几个层次,每一层都有一些模块和机制需要理解.这部分内容预计会分为三篇文章来讲解.本文是第一篇,首先会对 ...

  4. Android Binder机制学习笔记

    声明,学习材料:http://my.unix-center.net/~Simon_fu/?p=875,不是简单的copy 1    Android的进程间通讯机制(IPC)用的是自己的binder机制 ...

  5. Android - Binder机制 - Binder框架总结

    以下几篇文章是较深入分析binder机制. 目录 1. Android - Binder机制 - ServiceManager 2. Android - Binder机制 - 普通service注册 ...

  6. Android Binder机制情景源码分析之Binder回调注册和反注册

    我们在日常开发中,经常用到Binder来进行跨进程通信,有个比较常见的场景是向服务端注册Binder回调,比如: IActivityManager中有两个成对的方法,Client端向AMS所在的服务端 ...

  7. Android Binder机制浅析及AIDL的使用

    参考 轻松理解 Android Binder,只需要读这一篇 图文详解 Android Binder跨进程通信的原理 Android中的Parcel是什么 Android Binder IPC通信机制 ...

  8. 不得不说的Android Binder机制与AIDL

    说起Android的进程间通信,想必大家都会不约而同的想起Android中的Binder机制.而提起Binder,想必也有不少同学会想起初学Android时被Binder和AIDL支配的恐惧感.但是作 ...

  9. Android Binder机制----实现自定义的系统服务

    一.基于源码分析Binder机制: Binder机制是Android系统中实现跨进程通信(IPC)的一种重要机制.可以说,Binder机制在android系统中无处不在,所以,要研究android源码 ...

最新文章

  1. elasticsearch(es)分布式全文检索引擎 简介
  2. ubuntu清除mac缓存
  3. MVC, MVP, MVVM比较以及区别(下)
  4. php asp.net 代码量少,.NET_asp.net 反射减少代码书写量, 复制代码 代码如下:public b - phpStudy...
  5. php 邮件验证_PHP程序来验证电子邮件地址
  6. python里什么叫子图_Python中的两个子图(matplotlib)
  7. android webview 选择图片上传,Android webview打开本地图片上传实现代码
  8. 在vmplayer上扩展ubantu系统的硬盘大小,并进入ubantu进行更改
  9. 人人商城小程序下单付款报错:“服务器暂时无法处理您的请求,请稍后再试”
  10. 颜色对照表(三)(16进制、RGB、CMYK、HSV、中英文名)
  11. 《数据库原理与应用》实验一
  12. 吉利有后手,魅族没有
  13. 09-slash_backslash
  14. Systemverilog中Assertions的记录
  15. php短信接口怎么使用_PHP代码示例_PHP短信接口 | 微米-中国领先的短信彩信接口平台服务商...
  16. 转帖:谁动了它们的基因?
  17. 关于无法连接到报表服务器http://localhost/reportserver的解决方案
  18. 用sheel xmllint --xpath模块进行xml解析
  19. 室内地图在哪些方面提升了我们的生活便利性?
  20. 瞬间记忆测试c语言,脑龄测试(数字瞬间记忆脑龄测试)

热门文章

  1. 基于CSS3实现垂直轮播效果
  2. 戴尔游匣7559经常(大概半小时)断电,关机的解决办法
  3. 梯度与散度与拉普拉斯算子
  4. 多媒体计算机接口卡,多媒体技术基础 2.2多媒体接口卡 多媒体接口卡.docx
  5. php session有什么用,session有什么作用?
  6. 计算机网络系统由什么系统组成,从资源构成上看计算机网络系统由什么构成
  7. 力扣209-长度最小的子数组(Java,双指针解法)
  8. python对列表中的字典的字段进行排序
  9. mysql转移数增删改查_MySql CURD操作(数据的增删改查)
  10. Flutter学习笔记(10)--容器组件、图片组件