赞
踩
前言
为什么我需要搞清楚getSystemService的原理?
在分析源码时错误的把GSS以为是基于binder实现的,但发现打印的日志内容与我所设想的不一样,按理来说audioService调用Binder.getCallingPid()时应该返回获取到的audioManager的pid,因为是从audioManager通过binder调用到的audioService的。但实际打印确实上层应用的,然后看到AudioManager的constructor有Context参数,后面才发现自己望文生义了,GSS返回的是实例类对象,不是一个独立进程的binder。
先给个结论。对于缓存类的系统服务(大部分情况),会通过map根据服务名称返回实例对象,第一次获取时才真正创建对象,后面获取时都是返回缓存。真正做这工作的在SystemServiceRegistry.java中,其中处理多线程并发获取服务实例的过程很精妙。
public final T getService(ContextImpl ctx) {
final Object[] cache = ctx.mServiceCache;
final int[] gates = ctx.mServiceInitializationStateArray;
for (;;) {
boolean doInitialize = false;
synchronized (cache) {
// Return it if we already have a cached instance.
T service = (T) cache[mCacheIndex];
if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
return service;
}
// If we get here, there's no cached instance.
// Grr... if gate is STATE_READY, then this means we initialized the service
// once but someone cleared it.
// We start over from STATE_UNINITIALIZED.
if (gates[mCacheIndex] == ContextImpl.STATE_READY) {
gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED;
}
// It's possible for multiple threads to get here at the same time, so
// use the "gate" to make sure only the first thread will call createService().
// At this point, the gate must be either UNINITIALIZED or INITIALIZING.
if (gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED) {
doInitialize = true;
gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING;
}
}
if (doInitialize) {
// Only the first thread gets here.
T service = null;
@ServiceInitializationState int newState = ContextImpl.STATE_NOT_FOUND;
try {
// This thread is the first one to get here. Instantiate the service
// *without* the cache lock held.
service = createService(ctx);
newState = ContextImpl.STATE_READY;
} catch (ServiceNotFoundException e) {
onServiceNotFound(e);
} finally {
synchronized (cache) {
cache[mCacheIndex] = service;
gates[mCacheIndex] = newState;
cache.notifyAll();
}
}
return service;
}
// The other threads will wait for the first thread to call notifyAll(),
// and go back to the top and retry.
synchronized (cache) {
while (gates[mCacheIndex] < ContextImpl.STATE_READY) {
try {
cache.wait();
} catch (InterruptedException e) {
Log.w(TAG, "getService() interrupted");
Thread.currentThread().interrupt();
return null;
}
}
}
}
}
调用链为:
首先mainActivity调用到的是继承的父类Activity的GSS。
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
下一步会调用到保存的mBase,这个参数是ContextThemeWrapper构造时传递的,估计是activity时就创建好了,但具体怎么传递context、哪里地方、什么时候创建的暂时不清楚。context是一个abstract class,他的实现类是contextImpl。
return SystemServiceRegistry.getSystemService(this, name);```
ServiceFetcher就是一个接口,实现该接口需要实现getService函数
static abstract interface ServiceFetcher<T> {
T getService(ContextImpl ctx);
}
关于这个hashmap,SYSTEM_SERVICE_FETCHERS是在SystemServiceRegistry实例化是初始化的,也就是在该类的static语句块中。这一步注册很多服务。
static {
......
registerService(Context.AUDIO_SERVICE, AudioManager.class,
new CachedServiceFetcher<AudioManager>() {
@Override
public AudioManager createService(ContextImpl ctx) {
return new AudioManager(ctx);
}});
......
}
registerSerivce只是一个put元素进hashmap的封装,把服务名和一个CachedServiceFetcher的类对象扔进去。可以猜到CachedServiceFetcher实现了ServiceFetcher
CachedServiceFetcher() {
// Note this class must be instantiated only by the static initializer of the
// outer class (SystemServiceRegistry), which already does the synchronization,
// so bare access to sServiceCacheSize is okay here.
mCacheIndex = sServiceCacheSize++;
}
这是该类的构造函数,需要解释一下,所以缓存的服务实例对象是存储在context的cached数组中的,另外一个int类型数组gates是表示缓存的每一个服务实例对象的当前状态,因此mCacheIndex就是存储的这个fetcher所指服务实例对象在cached数组中的索引。注释解释了为什么不用给sServiceCacheSize加锁。
从开头的实例过程可以看出,每一个服务对象都是lazy initialized,因此可以加快activity的启动速度(我的理解),并且避免了实例化一些并不需要的服务对象,只在真正需要的时候才会实例化。
另外实例化过程还涉及到了多线程的race condition情况的处理,解决的很巧妙(对我这个菜鸟而言)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。