前言
最近在看android源码中Window的内容,在看到WindowManagerImpl创建对象时发现了SystemServiceRegistry,这个类主要是用来缓存、注册、获取系统服务的。因为对它的缓存机制比较感兴趣,所以就研究下它的源码并记录下来,以便以后回顾迭代。
1. SystemServiceRegistry刚被导入内存时的分析
先来看一段源码:
package android.app;
final class SystemServiceRegistry {
//用来保存所有Service的名字
private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
new HashMap<Class<?>, String>();
//用来保存所有的ServiceFetcher,后面会拿出ServiceFetcher源码来说
//现在只要知道它是从缓存中拿Service,缓存中没有就创建Service就可以了
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
//记录缓存的大小
private static int sServiceCacheSize;
//注意构造方法是private的
private SystemServiceRegistry() { }
static{
//注册服务代码
registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
new CachedServiceFetcher<AccessibilityManager>() {
@Override
public AccessibilityManager createService(ContextImpl ctx) {
return AccessibilityManager.getInstance(ctx);
}});
//注册服务代码
registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
new CachedServiceFetcher<CaptioningManager>() {
@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<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx);
}});
...
}
...
//registerService的声明
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> 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> {
T getService(ContextImpl ctx);
}
static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
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<T> implements ServiceFetcher<T> {
...
public abstract T createService(ContextImpl ctx);
}
该方法是抽象的,那该方法的具体实现在哪儿呢?其实在上述的static代码中new CachedServiceFetcher对象时在后面的大括号中已经实现了createService方法。比如静态代码块中注册窗口服务时是这样的:
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@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实例,并保证以后需要时返回缓存中的该实例。