1、上篇概述
上一篇的文章架构·微服务架构详细描述微服务架构相关的理论基础,为这一篇文章打好了理论基础。这篇文章将站在 Android Framework 设计者的角度上,剖析在 Android 中应用的微服务架构。
因为只有理论结合实践,才能帮助我们更好的理解微服务架构这一难点。
2、假设由你主导架构设计
微服务架构向客户端暴露服务,而客户端可以通过远程访问协议去访问服务端暴露的服务。当下,我们先不考虑 Android 是如何实现微服务架构,仅以我们的角度去思考:我们利用微服务架构时会遇到哪些问题?
2.1、设计应用场景
1、当程序启动时,所有的服务会预先注册。
2、客户端可以通过查询服务的注册中心,查询到服务的注册状态。
3、客户端主动 connect 服务端,打开通讯的管道。
4、客户端可以向服务端 push 数据。
5、服务端可以向客户端 push 数据。
6、客户端可以主动 disconnect 服务端,或当服务端不可用时客户端应知晓。
2.2、角色划分
1、服务注册中心:用于注册服务端的所有服务,并向客户端提供服务的唯一标识符,以便于客户端能正确发现服务。
2、客户端:……。
3、服务端:独立的业务单元。
4、包裹对象:封装可序列化的数据,用于客户端与服务端的双向数据推送。
5、通讯机制:用于将包裹对象丢到服务端或客户端。
直到目前为止,我们并没有接触 ANDROID 的源码。所以上述的构想都是源于自己的设计,与 ANDROID 本身的设计并不相同。
因为我们对场景已经有了一番思索,所以接下去在源码中遨游的时候就不容易迷失方向。上述的思考将成为分析源码的主线索,可以预料的是:这些思索与源码中的设计必然存在大量的差异。但相比迷失在源码里面,它给我们带来的益处远大于弊处。
3、分析 ANDROID 源码
由于之前在分析View·InputEvent 的事件派发时, 接触到 WindowManagerService
这个类。在当时的文章中 WindowManagerService
并不是主线索,因而就没有对此展开分析,那么此刻是旧事重提的时候了。
3.1、WindowManagerService的创建历程
老样子从构造器作为起点,发现是私有构造器。所以对象一定是经由内部创建的,多半情况服务是单例的。
// WindowManagerService.class
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
}
经由main
方法的验证,发现其提供了容量为 1 的 WindowManagerService[]
。通过静态main()
方法创建了WindowManagerService
的实例。
这里使用数组的原因可能是 ANDROID 的设计者们认为服务可能存在多个。
// WindowManagerService.class
public static WindowManagerService main(final Context context,
final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
final WindowManagerService[] holder = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
holder[0] = new WindowManagerService(context, im,
haveInputMethods, showBootMsgs, onlyCore);
}
}, 0);
return holder[0];
}
3.2、WindowManagerService注册到服务中心
此刻我们先不关注内部的实现,转而观察 main()
方法是在哪里被调用的,最终在SystemServer
中发现了下面代码。
SystemServer
在启动其他服务时将创建WindowManagerService
实例,并将其注册到ServiceManager
中。
// SystemServer.class
private void startOtherServices() {
// 省略无关代码
WindowManagerService wm = null;
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
// 省略无关代码
}
继续跟进startOtherServices ()
方法,观察其服务注册的流程是怎样的。
// SystemServer.class
private void run() {
// 省略无关代码
try {
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
// 省略无关代码
}
分析上段代码,我们得到了几个信息:
1、run()是私有方法
2、服务分为3种:启动项服务、核心服务、其它服务。(WindowManagerService 属于其它服务)
依然我们不脱离主线索,不去分析服务的种类等等,感兴趣的同学自行阅读源码。
// SystemServer.class
public static void main(String[] args) {
new SystemServer().run();
}
好吧,看来我们已经追述到尽头了。这是 Java 的入口函数,由 zygote 发起调用。
关于 Native 层如何启动服务,不再本章的范畴。
到此为止我们发现了两件事情,这两件事情与我们之前的构想几乎没有出入。
1、服务是被 SystemServer 创建并注册到服务中心的。
2、SystemServer是开机时即会启动的。
3.3、服务中心的日常(ServiceManager)
服务中心提供了管理服务的基础方法,基于类结构我们关注addService() 的流程
。
// ServiceManager.java
/**
* Place a new @a service called @a name into the service
* manager.
*
* @param name 新服务的名称
* @param service 服务对象
*/
public static void addService(String name, IBinder service) {
try {
getIServiceManager().addService(name, service, false);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
观察到sServiceManager
对象是由ServiceManagerNative.asInterface()
方法创建的,而传入的参数正是 IBinder
。
由此可见
ServiceManager
对象本身也是一个远程服务,它与客户端通过Binder
进行通讯。
IServiceManager
提供了:
- 添加 —— addService
- 检查 ——checkService
- 获取与具体服务通讯的 Binder ——getService
- 列举已注册的服务 —— listServices
- 设置权限控制器功能。—— setPermissionController
由此可见客户端访问服务是通过访问IServiceManager
的实例(即ServiceManager
),来获取到具体服务的通讯对象(Binder)的实例来达到通讯的目的的。
所以我们可以将 ServiceManager 理解为 DNS 服务。
3.4、如何连接服务中心
由 3.3 章节,我们发现WindowManagerService
其实是通过向�ServiceManager
查询服务得到Binder
对象的。
所以问题的关键是如何连接上服务中心?
在一番思索后我们将问题定位到Binder
对象,ServiceManager 中的 Binder 对象从BinderInternal.getContextObject()
中得到的。
// com.android.internal.os.BinderInternal
/**
* 返回系统的全局“上下文对象”。
* 这通常是IServiceManager的实现,
* 您可以使用它来查找其他服务。
*/
public static final native IBinder getContextObject();
Binder
对象的创建来源于 Native 层,那么我们不得不中断对Binder
底层创建的分析。那么后续对于ServiceManager
的创建时机都将无从考究。(因为我并不打算深入到 Native 层)
3.5、Binder 的数据传输过程
/**
* 使用对象执行一个通用操作。
*
* @param code 待执行的行为码。范围限定在 0x0与0xffffff之间。
* @param data 编组数据(非空)发送到目标。如果您不发送任何数据,您必须创建一个空的Parcel在这里给出。
* @param reply 要从目标接收的已编组数据。如果你对返回值不感兴趣,可以为null。
*
* @param flags 附加操作标志,0表示RPC, or {@link #FLAG_ONEWAY} 表示单向RPC.
*
*/
public boolean transact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException;
Binder
的 transact()
方法真正的触发了数据的传输,传输的具体实现可以参考BinderProxy
。
final class BinderProxy implements IBinder {
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags);
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
}
数据传输细节也被掩藏在 Native 之下,看来 Android 的设计者们,很关心 Binder 的性能。因为 Android 的服务端与客户端,其实都是部署到机器本地的,而这也恰恰是 Android 不重用其他的远程访问协议,而重复造轮子的缘由吧。
如何连接上服务中心,目前我们暂且没法分析源头。那么暂且把这藏于 Native 之下的这部分过程略过,因为通过其他资料我们可以判定我们猜想的正确性。
3.6、数据如何互相推送
绕了一大圈我们重新回到WindowManagerService
这个类,我们在早前一直认为它是服务,那么此刻我们深入源码看看它是否真的是服务。
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
}
public interface IWindowManager extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements android.view.IWindowManager{
private static final java.lang.String DESCRIPTOR = "android.view.IWindowManager";
// 构造时就将其附加到接口。
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
// 将IBinder对象转换为android.view.IWindowManager接口,如果需要,生成代理。
public static android.view.IWindowManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
// 尝试检索此Binder对象的接口的本地实现。
// 如果返回null,则需要实例化一个代理类,以通过transact()方法调用。
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof android.view.IWindowManager))) {
return ((android.view.IWindowManager) iin);
}
// 查不到构建代理对象,访问远程对象
return new android.view.IWindowManager.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{
// 省略 代码
}
}
}
1、首先WindowManagerService继承自IWindowManager.Stub。
2、而IWindowManager.Stub继承自android.os.Binder并实现了android.view.IWindowManager。
3、IWindowManager.Stub提供了asInterface方法,用于返回Binder对象。** 如果本地已有 Binder 对象则复用,若没有则调用 mRemote 的 transact()方法获取到 Binder 对象。(此处单独在下面分析)**
4、拿到 Binder 对象后,可用于两端之间的通讯。
3.6.1、获取到 Binder 对象
// Binder.java
private IInterface mOwner;
private String mDescriptor;
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
attachInterface()
方法用于将Binder
对象与descriptor
绑定,所以查询descriptor
可以获得Binder
对象。
而我们看到在Stub
的构造器中就默认将Stub
对象与descriptor
绑定,所以只要初始化了Stub
对象则默认都是使用的Stub
作为 Binder
。
如果认真的思索到此,一定会存在疑惑:构造器中已经默认attachInterface()
,那为什么还要多此一举检查是否存在Binder
对象呢?
public static android.view.IWindowManager asInterface(android.os.IBinder obj) {
}
我们发现上面的asInterface
对象是静态方法,所以它可能在IWindowManager.Stub
未构造前就传入 Binder,且该 Binder 一定不是IWindowManager.Stub
对象,具体是什么我们在下面分析!
而传入之后发现Stub
并没有持有 Binder 对象
,于是就去以传入的Binder
对象为基础创建了android.view.IWindowManager.Stub.Proxy(obj);
对象。
private static class Proxy implements android.view.IWindowManager {
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 android.view.IWindowSession openSession(android.view.IWindowSessionCallback callback, com.android.internal.view.IInputMethodClient client, com.android.internal.view.IInputContext inputContext) throws android.os.RemoteException {
// 省略大量代码
}
}
观察到Proxy
对象的asBinder()
返回的是mRemote
本身。另一个让人注意的方法是openSession ()
返回的类型是android.view.IWindowSession
,而IWindowSession
类继承自IInterface
。
这个结构与IWindowManager
是不是惊人的相似?
3.6.2、WindowManagerService到底是不是服务?
见下面代码sWindowManagerService
是通过ServiceManager
拿到的Binder
对象。 所以严格意义说sWindowManagerService
并不是微服务架构中的服务,而是用于连接真正服务的黏合剂(或者可以理解为 Binder Server)。
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
sWindowManagerService = getWindowManagerService();
ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
} catch (RemoteException e) {
Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
}
}
return sWindowManagerService;
}
}
IWindowSession、IWindow,这两个数据结构都是标准的aidl接口,用于进程之间的同步通信。 IWindowSession负责ViewRootImpl到WMS的单向请求,IWindow则用于WMS回调ViewRootImpl。
参考资料:Android窗口管理](http://www.cppblog.com/fwxjj/archive/2013/01/14/197252.html)