当前位置: 代码迷 >> Android >> Service与Android系统设计(九)
  详细解决方案

Service与Android系统设计(九)

热度:90   发布时间:2016-05-01 13:05:43.0
Service与Android系统设计(9)

特别声明:本系列文章LiAnLab.org著作权所有,转载请注明出处。作者系LiAnLab.org资深Android技术顾问吴赫老师。本系列文章交流与讨论:@宋宝华Barry

3.5   System Service的驱动形式 --- ServiceManager

对于ServiceManager的使用,我们在应用程序编程时也会经常使用到,比如我们需要使用Sensor时,我们一般会做如下的调用:

       mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

mSensorManager.registerListener(this, mAccelerometer,SensorManager.SENSOR_DELAY_UI);

       @Override

       public void onSensorChanged(SensorEvent event) {

           if(event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)

                return;

           ...

       }

这样的编程模式,API说明会告诉我们,每次系统里加速度计Sensor发生状态变化时,就会触发onSensorChanged()回调方法被执行来处理Sensor的变动信息。这里就很好地说明了在系统范围内使用Service的另一种模式,就是通过getSystemService(),取回一个System Service的引用实例,然后便可以调用Service实现的方法,比如我们例子里的mSensorManager.registerListener()方法。

我们可以继承跟踪代码的实现,getSystemService()也并没有什么神奇的,它本质上只是创建一个Service列表的Cache而已,把ContextImpl.java与getSystemService()相关的实现抽出来,于是我们可以得到:

class ContextImpl extends Context {

   ...

    static class ServiceFetcher {             4

       int mContextCacheIndex = -1;  

       public Object getService(ContextImpl ctx) {      5

           ArrayList<Object> cache = ctx.mServiceCache;

           Object service;

           synchronized (cache) {

                if (cache.size() == 0) {      

                    for (int i =0; i <sNextPerContextServiceCacheIndex; i++) {

                        cache.add(null);

                    }

                } else {

                    service =cache.get(mContextCacheIndex);

                    if (service != null) {

                        return service;

                    }

                }

                service = createService(ctx);

                cache.set(mContextCacheIndex,service);

                return service;

           }

       }       

       public Object createService(ContextImpl ctx) {     6

           throw new RuntimeException("Notimplemented");

       }

    }

   

    private staticfinalHashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP  =

    new HashMap<String,ServiceFetcher>(); 2

   

    private staticintsNextPerContextServiceCacheIndex =0;

    private staticvoidregisterService(String serviceName, ServiceFetcher fetcher) {           3

       if(!(fetcher instanceof StaticServiceFetcher)) {

           fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;

       }

       SYSTEM_SERVICE_MAP.put(serviceName, fetcher);

    }

   

    static {

       registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {   7

           public Object getService(ContextImpl ctx) {

               returnAccessibilityManager.getInstance(ctx);

           }});

       registerService(ACTIVITY_SERVICE, new ServiceFetcher() {    8

           public Object createService(ContextImpl ctx) {

                return newActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());

}});

       registerService(ALARM_SERVICE, new StaticServiceFetcher() {   9

           public Object createStaticService() {

                IBinder b = ServiceManager.getService(ALARM_SERVICE);

                IAlarmManager service =IAlarmManager.Stub.asInterface(b);

                return new AlarmManager(service);

           }});

       ...

    }

   

   @Override

    public ObjectgetSystemService(String name) {  1

       ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);

       return fetcher == null ? null : fetcher.getService(this);

    }

   ...

}}

1 getSystemService()的实现。所有通过继承Context类来创建自己的执行片段,都会调用getSystemService()来取得SystemService的引用。在这一方法里,就是通过SYSTEM_SERVICE_MAP来取得Service所对应的Proxy对象。

2 SYSTEM_SERVICE_MAP,也只不过是通过String标识出来的ServiceFetcher对象而已,为了加速查找,使用了HashMap模板。

3 在Context对象里,会通过registerService()方法,将ServiceFetcher对象填充到SYSTEM_SERVICE_MAP里。

4 ServiceFetcher类。这只是Context对象内,为了更好地组织Service而提供的一种中间类型,Service本身通过ServiceFetcher引用,于是可以灵活地替换其getService()或是createService()方法。

5 标准的getService()实现。在正常情况下,getService()只是从Cache中查找是否已经创建好所需要的Service对象,如果有则直接返回这一对象,如果没有,则创建所需要的Service对象,再返回。

6 标准的createService()实现。跟抽象类的实现类似,如果该ServiceFetcher上承载的Service没有覆盖createService()方法,则基本上可以认定是出错了,此抛出异常。所以ServiceFetcher在注册时,要么需要覆盖getService()方法,否则必须要覆盖更底层的createService()方法。

7 覆盖getService()方法。因为上层只会通过getService()方法来往下进行访问,于是覆盖了getService()方法之后,则不需要再提供createService()了。这时我们就可以理解ServiceFetcher类的作用了,在系统实现上,Service有可能会通过getService()返回其实例,比如在SingleTon模式下构建的Service。我们不需要基于Service重构,而只需要在使用它的时候通过覆盖getService()来进行灵活地重构,比如这里的AccessibilityManager.getInstance()。

8 覆盖createService()方法。这是更普遍的做法,每一个System Service,都会通过registerService()将createService()构造方法注册到Context环境里,这样当应用程序调用getSystemService()时,在内部实际上会通过createService()来创建一个与Service对应的Proxy对象。我们前面分析过framework的构成,这样的Proxy对象会是XXXManager的形式,于是我们实际上在createService()里会创建ActivityManager之类的对象。

9 覆盖createService()的另一种方法。对于System Service而言,虽然都在系统运行过程中一直存在,但有的会很忙,像Media、Audio、Graphic等,只要有Proxy,便可以响应其调用请求,有一部分则可能长期驻留后台,只是偶尔响应一下请求,比如像我们例子里看到AlarmManager。对于响应度不高的SystemService,一般都会在一个叫servicemanager的守护进程的监管之下,所以我们这里会使用Stub.asInterface()接口方法申请对象,从而保证这一Service不被调用时则可以进入休眠。

在这个整体的执行流程里,比较绕,而且深入代码分析时,我们也会看到在实现时的不一致,风格并非很严谨。但通过中间插入的这层ServiceFetcher,可以让应用程序(或是某种需要使用getSystemService()方法的系统组件)很快找到合适的ServiceProxy端的初始化方法,快速建立起跟RemoteService的通信。

除了getSystemService()方法与bindService()不同以外,在这时我们看不到两者的任何区别。当然,我们在bindService()里也会使用到onServiceConnected()回调方法异步地返回一个IBinder引用,但这也只是出于Service的生命周期考虑的结果。bindService()只是通过Intent找到合适的Service,而具体远程Service的Binder引用,则是通过onServiceConnected()。所以本质上getSystemService()与bindService()只是形式上的区别,本质上是一回事,成功调用之后便可以进行一样的RPC操作请求了。

我们可以注意到getService()与bindService()的一个重要区别,bindService()与unbindService()成对,而getService()只是单独出现。于是,bindService()这种调用机制上的Service,总是在Bounded生命周期里才能对外提供服务,可以做到按需启动,不再需要时便会在合适的时间点被关闭。而getService()所操作的Service则没有什么生命周期,永远在系统里运行并提供服务,这里也需要有种实体可以管理这些Service,当这些Service无人使用时,承载该Service的进程便会进入休眠中,这便是ServiceManager的Stub端所完成的功能。

ServiceManager在Java和Native环境里各有其实现,但在Java端实际上只有Proxy端,而Native环境里实现的servicemanager才具有完整的Proxy与Stub实现。

我们可以先来看ServiceManager.java的实现:

public finalclass ServiceManager {

    private staticfinal String TAG ="ServiceManager";

    private static IServiceManagersServiceManager;

    private static IServiceManagergetIServiceManager() {

       if(sServiceManager != null) {

           return sServiceManager;

       }

       sServiceManager =ServiceManagerNative.asInterface(BinderInternal.getContextObject()); 2

       return sServiceManager;

    }

    public static IBindergetService(String name) {

       try {

           IBinder service = sCache.get(name);

            if (service != null) {

                return service;

           } else {

                returngetIServiceManager().getService(name); 1

           }

       } catch (RemoteException e) {

           Log.e(TAG, "error in getService", e);

       }

       return null;

    }

1 每次通过ServiceManager的getService()方法取得一个SystemService的引用,实际上只是通过getIServiceManager()取回一个Proxy对象,然后再调用这个Proxy对象的getService()方法。

2 getIServiceManager(),实际上则是通过IServiceManager接口,访问到一个ServiceManagerNative对象。

代码如此简洁,于是我们可以跟踪ServiceManagerNative的实现。从ServiceManagerNative类的实现上,我们也可以看到基于Binder收发两端的实现,但实际上接收端没有意义,也不会被执行到。代码如下:

package android.os;

import java.util.ArrayList;

 

public abstractclass ServiceManagerNativeextends Binder implements IServiceManager   1

{

    static public IServiceManagerasInterface(IBinder obj)

    {

       if(obj == null) {

           return null;

       }

       IServiceManager in =

           (IServiceManager)obj.queryLocalInterface(descriptor);

       if(in != null) {

           return in;

       }

       

       return new ServiceManagerProxy(obj);   2

    }

   

    publicServiceManagerNative()

    {

       attachInterface(this, descriptor);

    }

   

    public boolean onTransact(int code, Parcel data,Parcel reply,int flags)

    {

          ...

    }

 

    public IBinderasBinder()

    {

       return this;

    }

}

 

class ServiceManagerProxy implements IServiceManager {

    publicServiceManagerProxy(IBinder remote) {

       mRemote = remote;

    }

   

    public IBinderasBinder() {

       return mRemote;

    }

   

    public IBindergetService(String name) throws RemoteException {  3

       Parcel data = Parcel.obtain();

       Parcel reply = Parcel.obtain();

       data.writeInterfaceToken(IServiceManager.descriptor);

       data.writeString(name);

       mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

       IBinder binder = reply.readStrongBinder();

       reply.recycle();

       data.recycle();

       return binder;

    }

 

    public IBindercheckService(String name)throws RemoteException {

       …

       return binder;

    }

 

    public void addService(Stringname, IBinder service,boolean allowIsolated)

           throws RemoteException {

       …

    }

   

    public String[]listServices() throws RemoteException {

       ArrayList<String> services = new ArrayList<String>();

       int n = 0;

       while (true) {

}

       return array;

    }

 

    public voidsetPermissionController(IPermissionController controller)

           throws RemoteException {

         …

    }

 

    private IBindermRemote;

}

1 从ServiceManagerNative,可以看到,它也是一个抽象类,继承Binder,实现IServiceManager接口。于是它必然会实现asInterface()、asBinder()等Binder所需要的接口方法。但因为它本质上只是起到Proxy作用,作为一个抽象类,它并不可能被实例化,除非有一个非抽象类继承它并实现它所缺少的方法。这种实现在代码层面上没有意义,我们从后面的分析servicemanager的Native实现时也可以看得出来,于是我们虽然看到了onTransact()实现,但实际上它不起作用。

2 这是整个ServiceManagerNative类实现的最有意义的一行。虽然这一行与其他基于IBinder实现的远程类没什么不同,但这一行提供了Proxy接口,这个Proxy接口,则是其他System Service所需要的访问接口。在ServiceManagerNative类的asInterface()方法里,我们会创建并返回一个Proxy对象ServiceManagerPoxy。

3 ServiceManagerProxy对象里实现就没什么特殊之处了。跟会通过Binder访问到Remote Service的其他远程方法一样,会将本地需要调用的方法,将方法名与参数打包,将得到的命令通过Binder发送出去,然后再等着远程执行的返回。

此时,如果系统里有某种实现,在标签同是“android.os.IServiceManager”的Binder通信管道上监听,并响应getService()等方法的调用请求,这时整个基于ServiceManager的模型便完美了。我们可以继续使用ActivityManagerService实现时同样的技巧,继承ServiceManagerNative并且实现一个onTransact()所需要的响应方法,但这样的方式性能不够好,不利于频繁调用。

Java语言环境本身只是一种虚拟机环境,Java虚拟机在实现上强调的是对底层的封装,并不会提供针对操作系统的某种功能,如果我们想实现对底层的访问,则必须使用JNI来访问。比如访问Binder,如果把这样的机制通过指令或是IO拓展的方式直接嵌入到Java语言里,则会引发Android系统与Java语言的更大分裂。于是Binder本身是通过JNI拓展到Java语言里的,这样同时还达到一个高效的目的,虽然Java语言里可以访问到Binder的相应操作接口,但在底层实际上是通过C++实现的更高效的版本。既然Binder已经是C++实现,再通过JNI引入到Java环境里,我们的ServiceManager的Stub实现就没有必要到Java环境里再重复一次了,可以直接在底层将IServiceManager接口所需要的远程方法实现即可。这种方式更符合Java语法习惯、Native实现可以得到更高效ServiceManager,另外还提供了进一步实现NativeSerivce的可能性。既然底层是C++实现的,于是可以将Service的逻辑用C++写出来,再通过Binder直接暴露到应用程序层即可。

  相关解决方案