🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] 官方文档:[https://developer.android.com/guide/components/bound-services?hl=zh-cn](https://developer.android.com/guide/components/bound-services?hl=zh-cn) [https://developer.android.com/guide/components/aidl?hl=zh-cn](https://developer.android.com/guide/components/aidl?hl=zh-cn) 本文部分转载自:[Binder学习指南--weishu](http://weishu.me/2016/01/12/binder-index-for-newer/) Binder 是 Android 中非常重要的机制,本篇文章从 AIDL 入手分析 Binder 的原理,主要是进行宏观上的理解,暂不纠结细节及底层源码。 # 基础知识 本文部分转载自:[Binder学习指南--weishu](http://weishu.me/2016/01/12/binder-index-for-newer/) ## 进程隔离 > 进程隔离是为保护操作系统中进程互不干扰而设计的一组不同硬件和软件的技术。这个技术是为了避免进程A写入进程B的情况发生。 进程的隔离实现,使用了虚拟地址空间。进程A的虚拟地址和进程B的虚拟地址不同,这样就防止进程A将数据信息写入进程B。 > 操作系统的不同进程之间,数据不共享;对于每个进程来说,它都天真地以为自己独享了整个系统,完全不知道其他进程的存在;(有关虚拟地址,请自行查阅)因此一个进程需要与另外一个进程通信,需要某种系统机制才能完成。 ## 用户空间/内核空间 > Linux Kernel是操作系统的核心,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。 > 对于Kernel这么一个高安全级别的东西,显然是不容许其它的应用程序随便调用或访问的,所以需要对Kernel提供一定的保护机制,这个保护机制用来告诉那些应用程序,你只可以访问某些许可的资源,不许可的资源是拒绝被访问的,于是就把Kernel和上层的应用程序抽像的隔离开,分别称之为Kernel Space和User Space。 ## 系统调用/内核态/用户态 > 虽然从逻辑上抽离出用户空间和内核空间;但是不可避免的的是,总有那么一些用户空间需要访问内核的资源;比如应用程序访问文件,网络是很常见的事情,怎么办呢? > 用户空间访问内核空间的唯一方式就是**系统调用**;通过这个统一入口接口,所有的资源访问都是在内核的控制下执行,以免导致对用户程序对系统资源的越权访问,从而保障了系统的安全和稳定。用户软件良莠不齐,要是它们乱搞把系统玩坏了怎么办?因此对于某些特权操作必须交给安全可靠的内核来执行。 > 当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)此时处理器处于特权级最高的(0级)内核代码中执行。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。处理器在特权等级高的时候才能执行那些特权CPU指令。 ## 内核模块/驱动 > 通过系统调用,用户空间可以访问内核空间,那么如果一个用户空间想与另外一个用户空间进行通信怎么办呢?很自然想到的是让操作系统内核添加支持;传统的Linux通信机制,比如Socket,管道等都是内核支持的;但是Binder并不是Linux内核的一部分,它是怎么做到访问内核空间的呢?Linux的动态可加载内核模块(Loadable Kernel Module,LKM)机制解决了这个问题;模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行。这样,Android系统可以通过添加一个内核模块运行在内核空间,用户进程之间的通过这个模块作为桥梁,就可以完成通信了。 > 在Android系统中,这个运行在内核空间的,负责各个用户进程通过Binder通信的内核模块叫做**Binder驱动**。 > 驱动就是操作硬件的接口,为了支持Binder通信过程,Binder使用了一种“硬件”,因此这个模块被称之为驱动。 ## 为什么使用Binder? Android使用的Linux内核拥有着非常多的跨进程通信机制,比如管道,System V,Socket等;为什么还需要单独搞一个Binder出来呢?主要有两点,性能和安全。在移动设备上,广泛地使用跨进程通信肯定对通信机制本身提出了严格的要求;Binder相对出传统的Socket方式,更加高效;另外,传统的进程通信方式对于通信双方的身份并没有做出严格的验证,只有在上层协议上进行架设;比如Socket通信ip地址是客户端手动填入的,都可以进行伪造;而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。这个也是Android权限模型的基础。 # Binder通信模型 > 对于跨进程通信的双方,我们姑且叫做Server进程(简称Server),Client进程(简称Client);由于进程隔离的存在,它们之间没办法通过简单的方式进行通信,那么Binder机制是如何进行的呢? > 回想一下日常生活中我们通信的过程:假设A和B要进行通信,通信的媒介是打电话(A是Client,B是Server);A要给B打电话,必须知道B的号码,这个号码怎么获取呢? > 先查阅通信录,拿到B的号码;才能进行通信;否则,怎么知道应该拨什么号码?回想一下古老的电话机,如果A要给B打电话,必须先连接通话中心,说明给我接通B的电话;这时候通话中心帮他呼叫B;连接建立,就完成了通信。 > 另外,光有电话和通信录是不可能完成通信的,没有基站支持;信息根本无法传达。 > 我们看到,一次电话通信的过程除了通信的双方还有两个隐藏角色:通信录和基站。Binder通信机制也是一样:两个运行在用户空间的进程要完成通信,必须借助内核的帮助,这个运行在内核里面的程序叫做**Binder驱动**,它的功能类似于基站;通信录呢,就是一个叫做**ServiceManager**的东西(简称SM) > OK,Binder的通信模型就是这么简单,如下图: [![](http://weishu.dimensionalzone.com/binder-model.png)](http://weishu.dimensionalzone.com/binder-model.png) > 整个通信步骤如下: > 1. SM建立(建立通信录);首先有一个进程向驱动提出申请为SM;驱动同意之后,SM进程负责管理Service(注意这里是Service而不是Server,因为如果通信过程反过来的话,那么原来的客户端Client也会成为服务端Server)不过这时候通信录还是空的,一个号码都没有。 > 2. 各个Server向SM注册(完善通信录);每个Server端进程启动之后,向SM报告,我是zhangsan, 要找我请返回0x1234(这个地址没有实际意义,类比);其他Server进程依次如此;这样SM就建立了一张表,对应着各个Server的名字和地址;就好比B与A见面了,说存个我的号码吧,以后找我拨打10086; > 3. Client想要与Server通信,首先询问SM;请告诉我如何联系zhangsan,SM收到后给他一个号码0x1234;Client收到之后,开心滴用这个号码拨通了Server的电话,于是就开始通信了。 > 那么Binder驱动干什么去了呢?这里Client与SM的通信,以及Client与Server的通信,都会经过驱动,驱动在背后默默无闻,但是做着最重要的工作。驱动是整个通信过程的核心,因此完成跨进程通信的秘密全部隐藏在驱动里面;这个我们稍后讨论。 > OK,上面就是整个Binder通信的基本模型;做了一个简单的类比,当然也有一些不恰当的地方,(比如通信录现实中每个人都有一个,但是SM整个系统只有一个;基站也有很多个,但是驱动只有一个);但是整体上就是这样的;我们看到其实整个通信模型非常简单。 # Binder机制跨进程原理 > 上文给出了Binder的通信模型,指出了通信过程的四个角色: Client, Server, SM, driver; 但是我们仍然不清楚**Client到底是如何与Server完成通信的**。 > 两个运行在用户空间的进程A和进程B如何完成通信呢?内核可以访问A和B的所有数据;所以,最简单的方式是通过内核做中转;假设进程A要给进程B发送数据,那么就先把A的数据copy到内核空间,然后把内核空间对应的数据copy到B就完成了;用户空间要操作内核空间,需要通过系统调用;刚好,这里就有两个系统调用:`copy_from_user`,`copy_to_user`。 > 但是,Binder机制并不是这么干的。讲这么一段,是说明进程间通信并不是什么神秘的东西。那么,Binder机制是如何实现跨进程通信的呢? > Binder驱动为我们做了一切。 > 假设Client进程想要调用Server进程的`object`对象的一个方法`add`;对于这个跨进程通信过程,我们来看看Binder机制是如何做的。 (通信是一个广泛的概念,只要一个进程能调用另外一个进程里面某对象的方法,那么具体要完成什么通信内容就很容易了。) [![Alt text](http://weishu1.dimensionalzone.com/2016binder-procedure.png)](http://weishu1.dimensionalzone.com/2016binder-procedure.png "Alt text") > 首先,Server进程要向SM注册;告诉自己是谁,自己有什么能力;在这个场景就是Server告诉SM,它叫`zhangsan`,它有一个`object`对象,可以执行`add`操作;于是SM建立了一张表:`zhangsan`这个名字对应进程Server; > 然后Client向SM查询:我需要联系一个名字叫做`zhangsan`的进程里面的`object`对象;这时候关键来了:进程之间通信的数据都会经过运行在内核空间里面的驱动,驱动在数据流过的时候做了一点手脚,它并不会给Client进程返回一个真正的`object`对象,而是返回一个看起来跟`object`一模一样的代理对象`objectProxy`,这个`objectProxy`也有一个`add`方法,但是这个`add`方法没有Server进程里面`object`对象的`add`方法那个能力;`objectProxy`的`add`只是一个傀儡,它唯一做的事情就是把参数包装然后交给驱动。(这里我们简化了SM的流程,见下文) > 但是Client进程并不知道驱动返回给它的对象动过手脚,毕竟伪装的太像了,如假包换。Client开开心心地拿着`objectProxy`对象然后调用`add`方法;我们说过,这个`add`什么也不做,直接把参数做一些包装然后直接转发给Binder驱动。 > 驱动收到这个消息,发现是这个`objectProxy`;一查表就明白了:我之前用`objectProxy`替换了`object`发送给Client了,它真正应该要访问的是`object`对象的`add`方法;于是Binder驱动通知Server进程,*调用你的object对象的`add`方法,然后把结果发给我*,Sever进程收到这个消息,照做之后将结果返回驱动,驱动然后把结果返回给`Client`进程;于是整个过程就完成了。 > 由于驱动返回的`objectProxy`与Server进程里面原始的`object`是如此相似,给人感觉好像是**直接把Server进程里面的对象object传递到了Client进程**;因此,我们可以说**Binder对象是可以进行跨进程传递的对象** > 但事实上我们知道,Binder跨进程传输并不是真的把一个对象传输到了另外一个进程;传输过程好像是Binder跨进程穿越的时候,它在一个进程留下了一个真身,在另外一个进程幻化出一个影子(这个影子可以很多个);Client进程的操作其实是对于影子的操作,影子利用Binder驱动最终让真身完成操作。 > 理解这一点非常重要;务必仔细体会。另外,Android系统实现这种机制使用的是*代理模式*, 对于Binder的访问,如果是在同一个进程(不需要跨进程),那么直接返回原始的Binder实体;如果在不同进程,那么就给他一个代理对象(影子);我们在系统源码以及AIDL的生成代码里面可以看到很多这种实现。 > 另外我们为了简化整个流程,隐藏了SM这一部分驱动进行的操作;实际上,由于SM与Server通常不在一个进程,Server进程向SM注册的过程也是跨进程通信,驱动也会对这个过程进行暗箱操作:SM中存在的Server端的对象实际上也是代理对象,后面Client向SM查询的时候,驱动会给Client返回另外一个代理对象。Sever进程的本地对象仅有一个,其他进程所拥有的全部都是它的代理。 > 一句话总结就是:**Client进程只不过是持有了Server端的代理;代理对象协助驱动完成了跨进程通信。** 总结: * 一个进程向驱动申请为 ServiceManager,来管理 Service * 各个 Server 依次向 ServiceManager 进行注册 * Client 想同 Server 通信,向 ServiceManager 请求 * ServiceManager 返回给 Client 的是 Server 的代理对象 * Client 调用代理对象的方法,传给 ServiceManager * ServiceManager 通知 Server,拿到 Server 的返回值交给 Client # Binder到底是什么? > 我们经常提到Binder,那么Binder到底是什么呢? > Binder的设计采用了面向对象的思想,在Binder通信模型的四个角色里面;他们的代表都是“Binder”,这样,对于Binder通信的使用者而言,Server里面的Binder和Client里面的Binder没有什么不同,一个Binder对象就代表了所有,它不用关心实现的细节,甚至不用关心驱动以及SM的存在;这就是抽象。 > * 通常意义下,Binder指的是一种通信机制;我们说AIDL使用Binder进行通信,指的就是**Binder这种IPC机制**。 > * 对于Server进程来说,Binder指的是**Binder本地对象** > * 对于Client来说,Binder指的是**Binder代理对象**,它只是**Binder本地对象**的一个远程代理;对这个Binder代理对象的操作,会通过驱动最终转发到Binder本地对象上去完成;对于一个拥有Binder对象的使用者而言,它无须关心这是一个Binder代理对象还是Binder本地对象;对于代理对象的操作和对本地对象的操作对它来说没有区别。 > * 对于传输过程而言,Binder是可以进行跨进程传递的对象;Binder驱动会对具有跨进程传递能力的对象做特殊处理:自动完成代理对象和本地对象的转换。 > 面向对象思想的引入将进程间通信转化为通过对某个Binder对象的引用调用该对象的方法,而其独特之处在于Binder对象是一个可以跨进程引用的对象,它的实体(本地对象)位于一个进程中,而它的引用(代理对象)却遍布于系统的各个进程之中。最诱人的是,这个引用和java里引用一样既可以是强类型,也可以是弱类型,而且可以从一个进程传给其它进程,让大家都能访问同一Server,就象将一个对象或引用赋值给另一个引用一样。Binder模糊了进程边界,淡化了进程间通信过程,整个系统仿佛运行于同一个面向对象的程序之中。形形色色的Binder对象以及星罗棋布的引用仿佛粘接各个应用程序的胶水,这也是Binder在英文里的原意。 > 我们现在知道,Server进程里面的Binder对象指的是Binder本地对象,Client里面的对象值得是Binder代理对象;在Binder对象进行跨进程传递的时候,Binder驱动会自动完成这两种类型的转换;因此Binder驱动必然保存了每一个跨越进程的Binder对象的相关信息;在驱动中,Binder本地对象的代表是一个叫做`binder_node`的数据结构,Binder代理对象是用`binder_ref`代表的;有的地方把Binder本地对象直接称作Binder实体,把Binder代理对象直接称作Binder引用(句柄),其实指的是Binder对象在驱动里面的表现形式;读者明白意思即可。 > OK,现在大致了解Binder的通信模型,也了解了Binder这个对象在通信过程中各个组件里面到底表示的是什么。 # 理解Java层的Binder > 我们使用AIDL接口的时候,经常会接触到这些类,那么这每个类代表的是什么呢? > * IBinder是一个接口,它代表了**一种跨进程传输的能力**;只要实现了这个接口,就能将这个对象进行跨进程传递;这是驱动底层支持的;在跨进程数据流经驱动的时候,驱动会识别IBinder类型的数据,从而自动完成不同进程Binder本地对象以及Binder代理对象的转换。 > * IBinder负责数据传输,那么client与server端的调用契约(这里不用接口避免混淆)呢?这里的IInterface代表的就是远程server对象具有什么能力。具体来说,就是aidl里面的接口。 > * Java层的Binder类,代表的其实就是**Binder本地对象**。BinderProxy类是Binder类的一个内部类,它代表远程进程的Binder对象的本地代理;这两个类都继承自IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder驱动会自动完成这两个对象的转换。 > * 在使用AIDL的时候,编译工具会给我们生成一个Stub的静态内部类;这个类继承了Binder, 说明它是一个Binder本地对象,它实现了IInterface接口,表明它具有远程Server承诺给Client的能力;Stub是一个抽象类,具体的IInterface的相关实现需要我们手动完成,这里使用了策略模式。 # AIDL 分析(Android 接口定义语言) ## IBinder IBinder 是一个接口,代表一种跨进程传输的能力,实现了这个接口的对象就可以拥有跨进程传输能力 ## IInterface 在定义 Server 所具有能力的接口(具体就是 aidl 里面的接口)时,需继承自 IInterface,IInterface接口定义如下: ```java public interface IInterface { public IBinder asBinder(); } ``` ## demo **1、定义 AIDL 接口** ![](https://img.kancloud.cn/f8/8a/f88a3b7f9e271a5cc81a0de48fc6f5af_300x318.png) ```java // ICompute.aidl package com.markxu.aidltest; // Declare any non-default types here with import statements interface ICompute { int add(int a, int b); } ``` **2、系统自动生成ICompute类** 编译后,在 app/build/generated/aidl_source_output_dir/ 目录下,系统会自动为我们生成 ICompute.java 类,源码如下: ```java // ICompute.java public interface ICompute extends android.os.IInterface { /** * Default implementation for ICompute. */ public static class Default implements com.markxu.aidltest.ICompute { @Override public int add(int a, int b) throws android.os.RemoteException { return 0; } @Override public android.os.IBinder asBinder() { return null; } } /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.markxu.aidltest.ICompute { private static final java.lang.String DESCRIPTOR = "com.markxu.aidltest.ICompute"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.markxu.aidltest.ICompute interface, * generating a proxy if needed. */ public static com.markxu.aidltest.ICompute asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.markxu.aidltest.ICompute))) { return ((com.markxu.aidltest.ICompute) iin); } return new com.markxu.aidltest.ICompute.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_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; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.markxu.aidltest.ICompute { 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 a, int b) 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(a); _data.writeInt(b); boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().add(a, b); } _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public static com.markxu.aidltest.ICompute sDefaultImpl; } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public static boolean setDefaultImpl(com.markxu.aidltest.ICompute impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.markxu.aidltest.ICompute getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } public int add(int a, int b) throws android.os.RemoteException; } ``` **3、Server端代码:** ```java public class AIDLService extends Service { private ICompute.Stub mCompute = new ICompute.Stub() { @Override public int add(int a, int b) throws RemoteException { return a + b; } }; public AIDLService() { } @Override public IBinder onBind(Intent intent) { return mCompute; } } ``` **4、Client端代码:** ```java findViewById(R.id.cl_main).setOnClickListener(new View.OnClickListener() { private ICompute mICompute; @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, AIDLService.class); bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mICompute = ICompute.Stub.asInterface(service); try { int value = mICompute.add(1, 99); Toast.makeText(MainActivity.this, String.valueOf(value), Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }, BIND_AUTO_CREATE); } }); ``` **5、总结** * 在Server的onBind方法中,直接返回Stub对象即可 * Stub类继承自Binder,说明Stub是一个Binder本地对象;Stub类实现ICompute接口,说明Stub携带某种Client需要的的能力(方法add) * 在Client的onServiceConnected回调中,调用Stub类的asInterface获取到远程Server ## 源码分析 将ICompute的代码精简下: ```java public interface ICompute extends android.os.IInterface { /** * Default implementation for ICompute. */ public static class Default implements com.markxu.aidltest.ICompute { //... } /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.markxu.aidltest.ICompute { //... } public int add(int a, int b) throws android.os.RemoteException; } ``` ICompute是一个接口,继承自IInterface,描述了远程Server所拥有的功能。ICompute内包含了 * Default类:一个内部静态类,也就是ICompute的默认实现类 * Stub类:一个静态抽象类,继承自Binder,实现ICompute接口 * add方法:一个接口方法 可以理解为ICompute是一个接口,声明了Server具有的能力add方法;Stub类和Default类都是静态内部类,可以理解为恰巧声明在了ICompute内部,和ICompute关系不大。 **1、Stub类** Stub类的代码如下: ```java // ICompute.java public static abstract class Stub extends android.os.Binder implements com.markxu.aidltest.ICompute { private static final java.lang.String DESCRIPTOR = "com.markxu.aidltest.ICompute"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.markxu.aidltest.ICompute interface, * generating a proxy if needed. */ public static com.markxu.aidltest.ICompute asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.markxu.aidltest.ICompute))) { return ((com.markxu.aidltest.ICompute) iin); } return new com.markxu.aidltest.ICompute.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_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; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.markxu.aidltest.ICompute { //... } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public static boolean setDefaultImpl(com.markxu.aidltest.ICompute impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.markxu.aidltest.ICompute getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } ``` 首先将代码精简下: ```java public static abstract class Stub extends android.os.Binder implements com.markxu.aidltest.ICompute { // Binder 类的唯一标识 private static final java.lang.String DESCRIPTOR = "com.markxu.aidltest.ICompute"; public Stub() { this.attachInterface(this, DESCRIPTOR); } // 通过这个方法,Client 可以拿到远程的 Server 对象 public static com.markxu.aidltest.ICompute asInterface(android.os.IBinder obj) { //... } // 返回当前 Binder 对象 @Override public android.os.IBinder asBinder() { return this; } // 处理 Client 传递来的方法,下面详细分析 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { //... } // Binder代理对象 private static class Proxy implements com.markxu.aidltest.ICompute { //... } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public static boolean setDefaultImpl(com.markxu.aidltest.ICompute impl) { //... } public static com.markxu.aidltest.ICompute getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } ``` 1、asInterface方法:通过此方法,Client可以拿到Server对象。 ```java // ICompute.java#Stub public static com.markxu.aidltest.ICompute asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } // 查找是否为本地对象 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.markxu.aidltest.ICompute))) { // 说明 Client 和 Server 在一个进程 // 返回 Server 的 Binder 本地对象 Stub return ((com.markxu.aidltest.ICompute) iin); } // 不在一个进程,new 一个远程代理对象 return new com.markxu.aidltest.ICompute.Stub.Proxy(obj); } ``` 参数obj对象是驱动给我们的,当obj 为 Binder 时,queryLocalInterface方法源码如下: ```java // Binder.java public IInterface queryLocalInterface(String descriptor) { if (mDescriptor.equals(descriptor)) { return mOwner; } return null; } ``` 当obj 为 BinderProxy 时,queryLocalInterface方法源码如下: ```java // BinderProxy.java public IInterface queryLocalInterface(String descriptor) { return null; } ``` 所以,asInterface方法会尝试在obj中查找Binder本地对象,如果找到说明Client和Server在同一个进程,参数直接就是本地对象,直接类型转换并返回;如果找不到说明obj是BinderProxy,也就是说Client和Server不在同一个进程。 2、Stub 的 onTransact 方法运行在 Server 的 Binder 线程池中,展开看下: * 通过 code 确定 Client 所请求的目标方法 * 然后从 data 中取出目标方法所需的参数 * 执行目标方法 * 向 reply 中写入返回值 * 返回 false 时,客户端请求失败 ```java @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; // 通过 code 确定 Client 所请求的目标方法 switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_add: { data.enforceInterface(descriptor); // 从 data 中取出目标方法所需的参数 int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); // 执行目标方法 int _result = this.add(_arg0, _arg1); reply.writeNoException(); // 向 reply 中写入返回值 reply.writeInt(_result); return true; } default: { return super.onTransact(code, data, reply, flags); } } } ``` **2、Proxy类** 接下来看看 Binder 代理对象 Proxy 类,ServiceManager 和 Client 拿到的都是 Binder 代理对象,通过调用代理对象的方法,经过 Binder driver 的转换后最终调用到 Binder 本地对象的方法。 ```java // ICompute.java#Proxy private static class Proxy implements com.markxu.aidltest.ICompute { 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 a, int b) 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(a); _data.writeInt(b); boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().add(a, b); } _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public static com.markxu.aidltest.ICompute sDefaultImpl; } ``` 下面看看 Binder 代理对于方法的处理,以 add()方法为例: * 首先用 Parcel 把数据序列化 * 传递给 Binder driver,Binder driver 再传递给 Server * Server 执行方法并返回结果 ```java @Override public int add(int a, int b) throws android.os.RemoteException { // 用 Parcel 把数据序列化 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); // 此处发起调用请求,当前线程挂起,Server 端的 onTransact 方法会被调用 // 传递给 Binder driver 处理 // 此处的 mRemote 为 Binder Proxy boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().add(a, b); } // 远程调用结束,从 _reply 读取返回结果 _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } // 返回结果 return _result; } ``` 看看 Binder Proxy 的 transact 方法: ```java // BinderProxy.java public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); } return transactNative(code, data, reply, flags); } ``` 调用了 transactNative 方法,在此,Client 将方法传递给了 Binder driver。 ```java // BinderProxy.java public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException; ``` ## 总结 ### Binder总结 * 从IPC角度来说,Binder是Android中的一种跨进程通信方式;Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在Linux中没有 * 从Android Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager等)和相应ManagerService的桥梁 * 从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService时,**服务端会返回一个包含了服务端业务调用的Binder对象**,通过这个Binder对象,客户端就可以获取服务端提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。 ### AIDL总结 1、IBinder是一个接口,代表一种跨进程传输的能力,由系统驱动提供支持 2、IInterface也是一个接口,代表远程Server可以转化为Binder对象(asBinder方法)。ICompute继承自IInterface,声明了远程Server新增的能力(add方法) 3、编写AIDL文件声明远程Server的接口后,系统会自动生成ICompute接口及Stub类和Proxy类。 4、Stub类继承自Binder,因此具有跨进程传输的能力;实现了ICompute接口,因此拥有远程Server的能力 5、在Server的onBind方法中,创建一个Stub对象并返回,可以跨进程传输,且拥有Server的能力。创建Stub对象时,将Binder的所有者mOwner设置为Stub对象 6、在Client的回调中,拿到IBinder对象。 * 当Client与Server在同一个进程时,IBinder是Binder对象,通过asInterface方法直接拿到mOwner强转为远程Server对象,接下来Client可以直接调用Server的方法。 * 当Client与Server不在同一个进程时,IBinder是BinderProxy对象,此时通过asInterface拿不到mOwner,需根据BinderProxy对象创建一个Proxy对象,并返回给Client。Proxy对象可以理解为远程Server对象的代理。 * 当Client调用Proxy对象的方法(代表Server能力的方法)时,首先将参数Parcel序列化,再传递给底层Binder驱动层,Binder驱动层传递给Server,Server执行方法后返回结果给Client。 > 备注 在[【专题分析】Service](http://www.androidwiki.site/1657723)一文中,绑定Service使用的也是Binder机制,只不过是默认当前Activity和Service在同一个进程,不涉及进程间通信,所以在拿到IBinder对象后,直接强转为远程Server。 ## 实际应用 Android中Window的添加、移除、更新都有使用到AIDL。 在[Window的添加](http://www.androidwiki.site/1640753)源码分析时,最终是通过ViewRootImplk更新界面,完成Window的添加: ```java // ViewRootImpl.java public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { // ... mView = view; requestLayout(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets); // ... } ``` 其中mWindowSession的类型是IWindowSession,mWindowSession是一个Binder代理对象,addToDisplay是一个跨进程调用: ```plain // IWindowSession.aidl interface IWindowSession { int add(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets, out InputChannel outInputChannel); int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, out Rect outOutsets, out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel); int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets); int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outContentInsets, out Rect outStableInsets); void remove(IWindow window); } ``` ```java // Session.java // 文件所在目录: frameworks/base/services/core/java/com/android/server/wm/Session.java public class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { //... @Override public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel); } } ``` ```java // WindowManagerService.java public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { //... public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { //... } } ``` # 参考文档 [Binder 学习指南 -- Weishu](http://weishu.me/2016/01/12/binder-index-for-newer/) [Android 开发艺术探索 -- 任玉刚](http://www.google.com) [可能是讲解 Binder 机制最好的文章](https://juejin.im/entry/5786afbb8ac2470060665499)