在上一篇博文中,我给出了实现系统服务的步骤,这篇博文则将分析一下,为什么这样的实现方式能够实现客户端/服务器模式。
RadioManagerService
首先来看一下RadioManagerService是如何创建的。
如果我没有记错的话,SystemServer是在开机的过程中由zygote通过调用Zygote.forkSystemServer函数来创建。我们看一下SystemServer的main()函数。
public static void main(String[] args) {
SystemProperties.set("persist.sys.dalvik.vm.lib",
VMRuntime.getRuntime().vmLibrary());
// 此处省略很多行
// 这个地方载入了jni库。我们后面将jni的时候还会提到。
System.loadLibrary("android_servers");
Slog.i(TAG, "Entered the Android system server!");
// Initialize native services.
nativeInit();
// This used to be its own separate thread, but now it is
// just the loop we run on the main thread.
ServerThread thr = new ServerThread();
thr.initAndLoop();
}
可见,在main函数的最后,创建了一个ServerThread的对象,并调用了它的initAndLoop()函数。上一篇博文里,我们在这个函数里面增加了下面的代码:
com.android.server.RadioManagerService radioManagerService = null;
try {
Slog.i(TAG, "radio service");
radioManagerService = new com.android.server.RadioManagerService(context);
ServiceManager.addService(Context.RADIO_MANAGER_SERVICE, radioManagerService);
} catch (Throwable e) {
reportWtf("starting radio service", e);
}
在这里,我们先创建了一个RadioManagerService对象,然后把它加入到系统的ServiceManager里面。有兴趣的朋友可以跟踪一下addService()函数,它最终将添加到jni的ServiceManagerNative里面。因为系统服务的管理不是这篇博文的内容,所以这里只是提一下。
从上面的分析可以看出,RadioManagerService是在开机过程中创建的,所以在Android运行期间,RadioManagerService将在后台一直运行,时刻准备着为客户端服务。
RadioManager
在应用中,我们是通过下面的代码获取RadioManager实例的:
RadioManager mRadioManager = (RadioManager)getSystemService(Context.RADIO_MANAGER_SERVICE);
Activity是继承于Context的,getSystemService()这个函数是在Context中定义的:
public abstract Object getSystemService(String name);
它的实现是在ContextImpl这个类中:
@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
我们可以看到,它实际上返回的是根据name从SYSTEM_SERVICE_MAP里面查到的一个fetcher,然后调用fetcher的getService来获取服务的。
这个SYSTEM_SERVICE_MAP是个什么东西呢?查看其定义:
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>();
可知这就是一个存储服务名称和ServiceFetcher对象的哈希表。
那么fetcher是个什么东西呢?
static class ServiceFetcher {
int mContextCacheIndex = -1;
/**
* Main entrypoint; only override if you don't need caching.
*/
public Object getService(ContextImpl ctx) {
ArrayList<Object> cache = ctx.mServiceCache;
Object service;
synchronized (cache) {
if (cache.size() == 0) {
// Initialize the cache vector on first access.
// At this point sNextPerContextServiceCacheIndex
// is the number of potential services that are
// cached per-Context.
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;
}
}
/**
* Override this to create a new per-Context instance of the
* service. getService() will handle locking and caching.
*/
public Object createService(ContextImpl ctx) {
throw new RuntimeException("Not implemented");
}
}
我们来细细品味一下这段代码(我在这里看了好久才看明白是怎么回事)。
ServiceFetcher有两个方法,getService()和createService()。getService()是干嘛的呢?首先,它会获取当前Context中的一个服务缓存列表(cache)。然后判断cache的大小。如果它的大小是0(第一次调用这个getService()),就会根据sNextPerContextServiceCacheIndex(这个东西的意思是系统服务的种类数。为什么表示这个意思,后面会说。)创建一个空列表,然后创建所需的服务并加入列表。如果不是0(已经调用过getService()),则根据当前ServiceFetch对象在系统服务中的index来获取这个service。如果service不为空,就返回查到的service,否则创建所需服务并加入列表。
createService()是一个空的函数。其注释说,如果这个服务是每一个上下文都重新创建的服务,就需要重载这个函数。这句话的意思是只要服务的应用场景是每个Context(应用)都保留自己的服务副本,就要重载这个函数。这正好就是我们的应用场景。所以在上一篇博文里面,我们在ContextImpl里添加了下面的代码:
registerService(RADIO_MANAGER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(RADIO_MANAGER_SERVICE);
return new android.os.RadioManager(ctx, IRadioManager.Stub.asInterface(b));
}});
在这里,我们重载了createService()方法,来创建RadioManager对象。
private static void registerService(String serviceName, ServiceFetcher fetcher) {
if (!(fetcher instanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
}
SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}
查看registerService的函数代码,它的工作就是将当前服务的名称和包含服务的fetcher加入到SYSTEM_SERVICE_MAP中。同时,我们看到了在ServiceFetcher中使用的两个量。mContextCacheIndex和sNextPerContextServiceCacheIndex。从这里可以看出来它们的含义分别是当前ServiceFetcher的index和总的服务种类的数量。
综上,getSystemService()的执行过程是:根据服务名称查询与其对应的ServiceFetcher对象,调用ServiceFetcher对象的getService()方法。如果在当前上下文中,RadioManager对象已经创建过,则返回已经创建的对象,如果尚未创建过,则创建对象、缓存对象并返回。
所以,我们在应用中调用getSystemService()方法,将会为应用创建RadioManager对象的一个副本。在创建RadioManager的时候,我们还把系统中唯一的RadioManagerService对象传给了RadioManager对象,这样就完成了客户端到服务器的映射。获取RadioManagerService的方法最终也会到ServiceManagerNative里面,有兴趣的朋友可以去ServiceManagerNative里面感受下Android的博大精深。
至于运行在用户进程的RadioManager怎么调用到运行在系统进程的RadioManagerService的,这个属于AIDL的内容,这里不做讨论。
至此,完成了系统服务的客户端/服务器模式的分析。