定制Android系统开发之四——系统服务实现的分析

在上一篇博文中,我给出了实现系统服务的步骤,这篇博文则将分析一下,为什么这样的实现方式能够实现客户端/服务器模式。

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的内容,这里不做讨论。

至此,完成了系统服务的客户端/服务器模式的分析。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值