android笔记之SystemServiceRegistry

前言

    最近在看android源码中Window的内容,在看到WindowManagerImpl创建对象时发现了SystemServiceRegistry,这个类主要是用来缓存、注册、获取系统服务的。因为对它的缓存机制比较感兴趣,所以就研究下它的源码并记录下来,以便以后回顾迭代。

1. SystemServiceRegistry刚被导入内存时的分析

    先来看一段源码:

package android.app;
final class SystemServiceRegistry {

    //用来保存所有Service的名字
    private static final HashMap, String> SYSTEM_SERVICE_NAMES =
            new HashMap, String>();
    //用来保存所有的ServiceFetcher,后面会拿出ServiceFetcher源码来说
    //现在只要知道它是从缓存中拿Service,缓存中没有就创建Service就可以了
    private static final HashMap> SYSTEM_SERVICE_FETCHERS =
            new HashMap>();
    //记录缓存的大小
    private static int sServiceCacheSize;
    
    //注意构造方法是private的
    private SystemServiceRegistry() { }
    
    static{
        
        //注册服务代码
        registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
                new CachedServiceFetcher() {
            @Override
            public AccessibilityManager createService(ContextImpl ctx) {
                return AccessibilityManager.getInstance(ctx);
            }});
        
        //注册服务代码
        registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
                new CachedServiceFetcher() {
            @Override
            public CaptioningManager createService(ContextImpl ctx) {
                return new CaptioningManager(ctx);
            }});
        ...//大量类似的注册服务代码
    }
}

    在SystemServiceRegistry类刚被导入内存时,这些静态字段就会被初始化、静态字段就会被执行。SYSTEM_SERVICE_NAMES、SYSTEM_SERVICE_FETCHERS这两个字段不仅是静态的,还是final的,这说明这俩字段被初始化之后,对象就不能更改了但可以增删元素(因为是HashMap)。这两个字段,分别用来存储Service名字和获取Service实例的Fetcher对象的。

    SystemServiceRegistry的构造方法是私有的,说明它不能在类外创建对象,看一下该构造方法在类内的调用,发现也没有调用,这说明SystemServiceRegistry是不允许创建对象的。再看一下该类的其它方法和字段,发现都是静态的,这就可以确定SystemServiceRegistry类是被当做Util来使用的,并且不允许创建该类的实例。

    static代码块中大量调用了registerService方法,那就结合registerService方法的调用和声明来看一下:

...
static{
    ...
    //registerService的调用
    registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
    ...
}

...
//registerService的声明
private static  void registerService(String serviceName, Class serviceClass,
            ServiceFetcher serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
...

    先看一下registerService方法声明的参数:

参数 含义
serviceName service的名字,比如Context.WINDOW_SERVICE
serviceClass 该Service对象的Class类,比如WindowManager.class
serviceFetcher ServiceFetcher对象

    registerService方法内的逻辑很简单,就是以serviceClass为key将serviceName存储到SYSTEM_SERVICE_NAMES这个HashMap中,以serviceName为key将ServiceFetcher对象对象存储到SYSTEM_SERVICE_FETCHERS这个HaspMap中。

    下面看一下,ServiceFetcher的声明及其实现类CachedServiceFetcher。如上述代码所示,registerService方法被调用时传入的第三个参数即为CachedServiceFetcher的对象。

package android.app;
final class SystemServiceRegistry {
    ...
    private static int sServiceCacheSize;
    ...
    static abstract interface ServiceFetcher {
        T getService(ContextImpl ctx);
    }
    static abstract class CachedServiceFetcher implements ServiceFetcher {
        private final int mCacheIndex;

        public CachedServiceFetcher() {
            mCacheIndex = sServiceCacheSize++;
        }

        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            synchronized (cache) {
                // Fetch or create the service.
                Object service = cache[mCacheIndex];
                if (service == null) {
                    service = createService(ctx);
                    cache[mCacheIndex] = service;
                }
                return (T)service;
            }
        }

        public abstract T createService(ContextImpl ctx);
    }
    ...
}

    从代码结构来看,ServiceFetcher为SystemServiceRegistry类的静态内部接口,定义了getService方法;CachedServiceFetcher为SystemServiceRegistry类的抽象静态内部类,实现ServiceFetcher接口并实现其定义方法getService方法。

    另外,CachedServiceFetcher的构造方法被调用时会将此时SystemServiceRegistry类中静态成员变量sServiceCacheSize的值赋给其final的成员变量mCacheIndex,然后sServiceCacheSize加1。结合上述static代码块中大量调用registerService方法时大量new CachedServiceFetcher对象作为第三个参数可知,SystemServiceRegistry类中静态成员变量sServiceCacheSize其实就是用来记录static代码块中注册了多少个服务的。同时还保证了每一个注册的服务都有一个唯一的下标mCacheIndex(与其他注册服务的下标不同)记录在ServiceFetcher对象内。

说一个小知识点:类的成员final非静态变量如果未初始化,那其实是可以在该类的构造方法初始化的。比如说,这里的mCacheIndex。

    SystemServiceRegistry类被导入内存时,能执行到的差不多就是如上所说了:静态成员变量的初始化,静态代码块以及静态代码块中执行到的registerService方法和给registerService传递参数时执行到的CachedServiceFetcher类的构造方法。

    SystemServiceRegistry类一般只会导入内存一次,然后就留在内存里了。这样就保证了static代码块只会执行一次,注册各个服务也只各执行一次,获取服务的ServiceFetcher对象也是一个服务对应一个。

2. 使用SystemServiceRegistry提供的方法创建缓存并获取服务

    通过上述对registerService方法功能的分析可知,SystemServiceRegistry存储下来的只是service名字和获取该service的ServiceFetcher对象,并没有直接存储该Service实现类的对象。那SystemServiceRegistry的缓存是在什么时候创建的?Service实现类的对象又是什么创建并存入到缓存的呢?

    1. 创建缓存

    SystemServiceRegistry类的方法并不多,public修饰可被外界调用的也只有3个而已:createServiceCache、getSystemService、getSystemServiceName。根据方法名就很快找到了创建缓存的方法createServiceCache,下面具体看一下这个方法的声明:

public static Object[] createServiceCache() {
    return new Object[sServiceCacheSize];
}

    超级简单的一个方法,就创建了一个Object数组而已。上面已经解释了sServiceCacheSize的作用是记录注册的所有服务的个数,而此处使用sServiceCacheSize来作为缓存数组的长度。

    关于创建缓存还有一点要说的,查看createServiceCache方法被调用的地方,发现它只在初始化ContextImpl的一个成员变量时被调用了,其它地方没调用:

package android.app;
class ContextImpl extends Context {
    ...
    final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
    ...
}

    从这里就可以看出,SystemServiceRegistry类中的缓存对象并没有设置到SystemServiceRegistry类中,而是存储到了另一个类ContextImpl的成员变量上了。这个跟ThreadLocal中的静态内部类ThreadLocalMap的实例对象并没有设置在ThreadLocal类中,而是设置在了Thread类的成员变量上多多少少有些相似。

    2. 获取Service实例

    上面说了,SystemServiceRegistry中可被外界调用的public方法很少,只有3个。上面说了用来创建缓存数组的createServiceCache方法,下面说一下用来获取Service实例的getSystemService方法:

public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}

    也是超级简单的一个方法,从SystemServiceRegistry的静态且final的hashmap(SYSTEM_SERVICE_FETCHERS)中取出ServiceFetcher对象(ServiceFetcher对象在SystemServiceRegistry类被导入内存执行static代码块时已被初始化),然后调用其getService方法来获取Service实例。下面来看一下ServiceFetcher的实现类CachedServiceFetcher中的getService方法(CachedServiceFetcher类上面已经贴过,这里只贴出其方法getService):

@Override
@SuppressWarnings("unchecked")
public final T getService(ContextImpl ctx) {
    //从ContextImpl对象中获得缓存数组
    final Object[] cache = ctx.mServiceCache;
    //某个线程正在获取Service,其他获取Service线程在这里阻塞
    synchronized (cache) {
        //一个下标对应一个Service,从缓存数组中获取该下标下的Service
        Object service = cache[mCacheIndex];
        //如果缓存数组中还没有Service就要去创建,创建好后保存到缓存数组的相应下标下
        if (service == null) {
            service = createService(ctx);
            cache[mCacheIndex] = service;
        }
        //返回该服务
        return (T)service;
    }
}

public abstract T createService(ContextImpl ctx);

    这个getService的逻辑基本就是缓存数组中获取不到该服务就先去创建该服务,创建好后将该服务存储到缓存数组中并返回该服务。下面看一下CachedServiceFetcher类中的createService方法:

static abstract class CachedServiceFetcher implements ServiceFetcher {
    ...
    public abstract T createService(ContextImpl ctx);
}

    该方法是抽象的,那该方法的具体实现在哪儿呢?其实在上述的static代码中new CachedServiceFetcher对象时在后面的大括号中已经实现了createService方法。比如静态代码块中注册窗口服务时是这样的:

registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher() {
    @Override
    public WindowManager createService(ContextImpl ctx) {
        return new WindowManagerImpl(ctx);
    }});

    到此已经通过获取了Service实例。

总结

    这里作一个总结,以便对SystemServiceRegistry有一个整体的印象:

  • SystemServiceRegistry类中ServiceFetcher对象是复用的,不同的ContextImpl对象获取相同的Service实例使用的同一个ServiceFetcher对象;
  • 对Service缓存的数组是记录在ContextImpl中的,不同的ContextImpl对象缓存数组不同。
  • Service缓存数组初始大小即为要注册的所有服务的个数,但数组每个位置上的Service实例均为空。只有在调用SystemServiceRegistry的getSystemService方法时发现没这个Service实例才会去创建这个Service实例,并存储到缓存数组中,保证再次调用getSystemService方法时返回缓存数组中的该实例;
  • SystemServiceRegistry这种缓存机制的好处在于,不同ContextImpl对象使用不同的缓存数组,但不同的缓存数组获取相同的Service实例可以复用同一个ServiceFetcher对象;只在需要获取Service实例时才会去创建该Service实例,并保证以后需要时返回缓存中的该实例。

你可能感兴趣的:(android笔记之SystemServiceRegistry)