Android 应用开发中 Binder 的重要性有时不能体现出来。但深入理解 Binder 是确实了解 Android Framework AmS 和 PmS 这些最重要模块、提升 Android 开发能力的必经之路。从 AIDL 学习 Binder 是一个不错的切入点。
大部分 Android 应用是单进程的,常规应用开发中 Android Binder 的重要性很难体现出来。对应用开发者来说,能直接跟 Binder 打交道的唯一场景就是使用 bindService()
绑定服务。如果目标服务跟 UI 组件运行在同一个进程,这个跟 Binder 打交道的唯一场景,其实也并不真的涉及 IPC。考虑官方文档绑定服务概览 中的这个例子,正是一个没有 IPC 能力的 Binder。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class LocalService : Service () { private val binder = LocalBinder() private val mGenerator = Random() val randomNumber: Int get () = mGenerator.nextInt(100 ) inner class LocalBinder : Binder () { fun getService () : LocalService = this @LocalService } override fun onBind (intent: Intent ) : IBinder { return binder } }
这么看来,Binder IPC 机制并不是一个必需的知识。但实际并非如此,深入理解 Binder 是了解 Android Framework 中 AmS 和 PmS 这两个最重要模块、提升 Android 开发能力的必经之路。
对 Android 应用开发者来说,个人认为理解 Binder 的最佳切入点是 AIDL。
从 AIDL 到 Binder AIDL 的用法非常简单,无非就是创建 .aidl
文件、基于 aidl 生成 Java 代码、在 Service.onBind()
中向客户端暴露 Stub。具体步骤可以参考Android 接口定义语言 (AIDL) ,这里不赘述。
那么 AIDL 到底解决了什么问题?我理解最关键的有两个:
第一是通信协议 问题。Binder 是 C/S 构架,客户端和服务端需要通信,AIDL 直接在生成的代码中把数据打包和解包搞定了,为我们免去了手工这些样板代码的痛苦。
第二是编程接口 问题。如果愿意,我们也可自己从 Binder/IBinder/IIterface
这些类和接口手写 Stub
和 Proxy
从而实现”远程对象的本地代理”这一编程模式,但 AIDL 为我们生成这些编程接口岂不更好?
这里假定我们 aidl 文件是 IFakeService.aidl
,文件内容如下:
1 2 3 4 5 6 7 package com.example.myapplication.aidl;interface IFakeService { int getValue () ; void setValue (int value) ; void addValue (int value) ; }
Aidl 工具从上述文件生成对应的 IFakeService.java
文件,文件中的 IFakeService
是 Java interface,其中包括嵌套类 Stub
,而 Stub
中又有一个私有的嵌套类 Proxy
。
这些生成的代码用法很简单,而且似乎永远也不会出错。但当我们仔细审视这些代码时,就会产生很多疑问:
Stub
和 Proxy
分别代表什么?
为什么 Stub
是抽象的?
asInterface()
有什么含义?它的实现逻辑是什么?
能力模型 一开始可能有些难以理解以上问题。不过 Binder学习指南 | Weishu’s Notes 中的一种描述方式或许能让人茅塞顿开,这里借鉴一下。如果说接口代表的是一种能力,那么不同的接口对应不同的能力。
IInterface
代表通用业务能力
IBinder
代表跨进程传输能力
当我们需要在这两种能力之间转换时,使用IInterface.asBinder()
或IBinder.asInterface()
即可。
编程模型 下面的类图展示了从两个基础能力衍生出来的各个类和接口,它们是基础能力的组合。图中最重要的是 Stub
和 Proxy
。
从 IInterface
和 IBinder
这两个基础能力出发,沿着类图从上往下,剩下的类或接口就好理解多了:它们使用继承方式(包括实现接口)或者组合方式,将”跨进程传输”和”业务能力”这两个基础能力结合起来 。
Binder
是本地对象。它通过继承方式获得了 IBinder
跨进程传输能力
IFakeService
代表我们的业务能力。这种能力由 .aidl
文件来定义最为简单不过
Stub
继承 Binder
并实现了 IFakeService
,这表示它既具备跨进程传输能力,还具备业务能力。但它是抽象的,这意味着其业务能力尚未完全实现。我们在 Stub
的子类 FakeService
中实现了完整的业务能力。
最后是 Proxy
。
从接口定义来看,它具备业务能力(✅),但是看不出是否有跨进程传输能力。实际上,能否跨进程传输对 Proxy
的客户来说并不重要(客户并不关心 Proxy 是什么 )。
另一方面,从具体实现来看,Proxy
既有远程传输能力✅又有业务能力✅。这对 Proxy
客户来说就足够了(客户更关心 Proxy 能做什么 )
Proxy
跨进程传输能力
业务能力
从接口定义来看
❌
✅
从具体实现来看
✅
✅
Proxy
特别之处在于它的两种能力上都是通过组合方式得到的,它只是 mRemote
成员的代理。mRemote
正是 Binder IPC 发生关键作用的地方。
aidl 给我们生成了一个易用的编程模型,我们只需要简单地使用 Stub
和 Proxy
就能完成 Binder IPC。但问题来了,我们如何拿到这里的 mRemote
以便生成 Proxy
对象?
从 Proxy 到 mRemote
远程对象的本地代理 当我们说“远程对象的本地代理”时,我们到底指的是什么?
多数时候,我们可以笼统地认为 Proxy
就是远程对象的本地代理。但准确来说,Proxy.mRemote
才是真正的远程对象的本地代理。在发生 IPC 时, Proxy.mRemote
的真正类型是 BinderProxy 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public final class BinderProxy implements IBinder { private BinderProxy (long nativeData) { mNativeData = nativeData; } private final long mNativeData; }
所以 Proxy
类其实有两层代理关系:
第一层是 Proxy
对其成员变量 mRemote
的代理,这个成员是个 BinderProxy
对象
第二层是 BinderProxy
对某个 native IBinder 对象的代理
如何获取 mRemote
前面提到过 asInterface()
将 IBinder
转换到 IFakeService
代表的含义是将跨进程传输能力转换成业务能力。aidl 生成的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 abstract class Stub extends android .os.Binder implements IFakeService { public static IFakeService asInterface (android.os.IBinder obj) { if ((obj==null )) { return null ; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null )&&(iin instanceof com.example.myapplication.aidl.IFakeService))) { return ((com.example.myapplication.aidl.IFakeService)iin); } return new com .example.myapplication.aidl.IFakeService.Stub.Proxy(obj); } }
刚开始我感觉这个生成的代码似乎没什么逻辑性。但对照着这个图看,容易理解一些了:无非就是沿着左侧这棵树找到一个合适的、可以代表业务能力的节点。
如果没有 IPC,那么走到位置2就行了(虽然 obj
的实际类型是 Stub
),客户端拿到 IFakeService
引用就足够调用业务能力了;
如果有 IPC,那么需要走到位置3:obj
参数变成了 Proxy.mRemote
。
接下来分两种情况考虑:
应用服务中 mRemote
怎么来的
系统服务中 mRemote
怎么来的,例如 ActivityManager
应用服务
ActivityThread.handleBindService() 第14行从 Service.onBind()
拿到 IBinder 对象,随后发布服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 private void handleBindService (BindServiceData data) { CreateServiceData createData = mServicesData.get(data.token); Service s = mServices.get(data.token); if (DEBUG_SERVICE) Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind); if (s != null ) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); data.intent.prepareToEnterProcess(isProtectedComponent(createData.info), s.getAttributionSource()); try { if (!data.rebind) { IBinder binder = s.onBind(data.intent); ActivityManager.getService().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_REBIND, 0 , 0 , data.intent); } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } catch (Exception e) { if (!mInstrumentation.onException(s, e)) { throw new RuntimeException ( "Unable to bind to service " + s + " with " + data.intent + ": " + e.toString(), e); } } } }
ActiveServices.publishServiceLocked() 处理发布服务的具体过程,其中第34行执行后最终会回调 ServiceConnection.onServiceConnected()
,将 IBinder
对象给到客户端。剩余工作交由 Proxy 代码完成即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 void publishServiceLocked (ServiceRecord r, Intent intent, IBinder service) { final long origId = mAm.mInjector.clearCallingIdentity(); try { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r + " " + intent + ": " + service); if (r != null ) { Intent.FilterComparison filter = new Intent .FilterComparison(intent); IntentBindRecord b = r.bindings.get(filter); if (b != null && !b.received) { b.binder = service; b.requested = true ; b.received = true ; ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections(); for (int conni = connections.size() - 1 ; conni >= 0 ; conni--) { ArrayList<ConnectionRecord> clist = connections.valueAt(conni); for (int i=0 ; i<clist.size(); i++) { ConnectionRecord c = clist.get(i); if (!filter.equals(c.binding.intent.intent)) { if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Not publishing to: " + c); if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Bound intent: " + c.binding.intent.intent); if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Published intent: " + intent); continue ; } if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c); final ComponentName clientSideComponentName = c.aliasComponent != null ? c.aliasComponent : r.name; try { c.conn.connected(clientSideComponentName, service, false ); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + r.shortInstanceName + " to connection " + c.conn.asBinder() + " (in " + c.binding.client.processName + ")" , e); } } } } serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false , false , !Flags.serviceBindingOomAdjPolicy() || r.wasOomAdjUpdated() ? OOM_ADJ_REASON_EXECUTING_SERVICE : OOM_ADJ_REASON_NONE); } } finally { mAm.mInjector.restoreCallingIdentity(origId); } }
系统服务 Android 系统服务中也大量使用类似 Proxy.mRemote
这种套路来做 IPC。以 ActivityManager 为例,其背后其实是 IPC + AMS。ActivityManager 的 mRemote 怎么来的?
看第15行。这里获取 IBinder 对象作为 mRemote
看起来非常直观,只是一个简单的 ServiceManager.getService()
调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @UnsupportedAppUsage public static IActivityManager getService () { return IActivityManagerSingleton.get(); } @UnsupportedAppUsage private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton <IActivityManager>() { @Override protected IActivityManager create () { final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); final IActivityManager am = IActivityManager.Stub.asInterface(b); return am; } }; public boolean isBackgroundRestricted () { try { return getService().isBackgroundRestricted(mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
最后,ServiceManager 自己也是一个 Service,它也需要一个类似的 mRemote
。见第10行,直接调用 BinderInternal.getContextObject()
获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public final class ServiceManager { private static IServiceManager getIServiceManager () { if (sServiceManager != null ) { return sServiceManager; } sServiceManager = ServiceManagerNative .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); return sServiceManager; } public static IBinder getService (String name) { try { IBinder service = sCache.get(name); if (service != null ) { return service; } else { return Binder.allowBlocking(rawGetService(name)); } } catch (RemoteException e) { Log.e(TAG, "error in getService" , e); } return null ; } private static IBinder rawGetService (String name) throws RemoteException { final long start = sStatLogger.getTime(); final IBinder binder = getIServiceManager().getService2(name).getServiceWithMetadata().service; return binder; } }
总结 先从 aidl 出发,讨论了它解决的主要问题。aidl 解决的一个主要问题是给我们提供了一个易用的编程模型。这个模型中最重要是 Stub
和 Proxy
。它们都是”业务能力”和”跨进程能力”的组合。
不过 aidl 没有解决该模型中重要参数 mRemote
的输入问题(即 Proxy.mRemote
是怎么来的)。接下来对这个问题展开了讨论。
对于应用服务,Android SDK 提供对应接口保证 bindService()
调用成功后客户端可以获取到 IBinder
对象作为 Proxy.mRemote
。
对于系统服务,通过 BinderInternal.getContextObject()
方法获取 IBinder
对象作为 Proxy.mRemote
。