从getSystemService() 看基于容器的单例模式

        android的后台运行在很多service,它们在系统启动时被SystemServer开启,比如管理打开的窗口程序的WindowManager,用于管理系统运行的Activity的ActivityManager,取得xml里定义的view的LayoutInflater ,状态栏的NotificationManager,位置服务LocationManager 等等。这些系统核心服务是不会反复创建的,它们以单例形式存在,减少资源消耗。本文基于Android12的源码,分析系统服务是如何实现以单例形式存在的。

        应用获取系统服务的接口是ContextImpl.getSystemService()。调用形式通常是:

ActivityManager manager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);

        而context的实现类是 ContextImpl ,那就从ContextImpl.java 看起吧:

@Override
public Object getSystemService(String name) {
    // ……Check incorrect Context usage.
    return SystemServiceRegistry.getSystemService(this, name);
}

        可以看到ContextImpl 里的调用非常简单,只是调用了 SystemServiceRegistry 的一个方法。 SystemServiceRegistry 是用于缓存、注册、获取系统服务的,系统服务的单例实现就是依靠这个类里面的缓存机制。接下来从getSystemService() 开始研究  SystemServiceRegistry 的缓存机制:

@SystemApi
public final class SystemServiceRegistry {
    private static final String TAG = "SystemServiceRegistry";
    private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS 
                            = new ArrayMap<String, ServiceFetcher<?>>();
    private static int sServiceCacheSize;

    public static Object getSystemService(ContextImpl ctx, String name) {
        ……
        final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        final Object ret = fetcher.getService(ctx);
        ……
        return ret;
    }

    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }
}

         SystemServiceRegistry .getSystemService()的主要工作就是从自己的map里面,根据service的名称,取出了一个   ServiceFetcher ,并使用相应的context调用这个 ServiceFetcher ​​​​​​.getService()。这里出现了一个非常重要的对象,  ServiceFetcher ,它以service的名称为键,被存储在  SystemServiceRegistry 的map键值对 SYSTEM_SERVICE_NAMES  里。   ServiceFetcher 是一个接口,实现类的对象只能在静态初始化期间创建,——也就是 SystemServiceRegistry .java 的静态初始化过程中创建:

/**
* 用context静态注册一个系统Service(只会在静态初始化过程中调用)
*/
private static <T> void registerService(@NonNull String serviceName,@NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
}

static {
    //注册一系列的Service,有一百来个,其中就比如:LayoutInflator,ActivityManager
     registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
        new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
               
            }
        }
    );
    registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
        new CachedServiceFetcher<ActivityManager>() {
            @Override
            public ActivityManager createService(ContextImpl ctx) {
                return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
            }
        }
    );
}

          SystemServiceRegistry 有一系列的静态语句块, 分析这些静态语句块,会看到   ServiceFetcher 的实现类是  CachedServiceFetcher ,在虚拟机第一次加载的时候,这些  ServiceFetcher 时会被注册,静态语句块保证了这些  CachedServiceFetcher 实例全局唯—。 CachedServiceFetcher 是怎么实现的呢,看看CachedServiceFetcher.java:

/**
 * Override this class when the system service constructor needs a
 * ContextImpl and should be cached and retained by that context.
 */
static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
    private final int mCacheIndex;

    CachedServiceFetcher() {
        //CachedServiceFetcher是 SystemServiceRegistry的内部类,而且只允许静态实例化,
        //而SystemServiceRegistry注册serviceFetcher的过程是线程安全的,所以在这里可以直接访问sServiceCacheSize。
        mCacheIndex = sServiceCacheSize++;
    }

    @Override
    public final T getService(ContextImpl ctx) {
        final Object[] cache = ctx.mServiceCache;
        T ret = null;
        for (; ; ) {
            synchronized (cache) {
                // cache 中已经存在service 则直接返回
                T service = (T) cache[mCacheIndex];
                if (service != null) {
                    ret = service;
                    break; // exit the for (;;)
                }
                ……
            }
            try {
                //不存在则创建并返回
                service = createService(ctx);
            } catch (ServiceNotFoundException e) {
                onServiceNotFound(e);
            } finally {
                synchronized (cache) {
                    cache[mCacheIndex] = service;
                }
                ret = service;
                ……
            }
        return ret;
    }

    public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;

}

 CachedServiceFetcher 中比较重要的一个成员变量是 int  mCacheIndex ,它在构造方法中赋值,也就是在  SystemServiceRegistry 的静态代码块被调用的时候被赋值,由于 CachedServiceFetcher 是  SystemServiceRegistry 的内部类,而java 类中的静态域的初始化和静态代码块的执行只在类加载的时候执行且只执行一次。仅执行一次,所以对 mCacheIndex 的操作一定是线程安全的,所以 mCacheIndex 可以直接访问  SystemServiceRegistry 的service计数器 sServiceCacheSize 。这个 mCacheIndex 会用于从  SystemServiceRegistry 的缓存mServiceCache 里获取对应的Service。

另外有两个重要的方法,一个是final的getService(),getService()的实现表明系统Service的创建是一种懒加载,只有当getService 发生的时候才会去创建,不会造成资源浪费。另一个是createService() ,具体由子类实现,子类会在这个方法里创建和返回他们的Service,比如
 return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());或者
 return new PhoneLayoutInflater(ctx.getOuterContext());。

由此我们可以看出,系统Service所使用的单例模式是基于容器的单例模式,在类加载的时候,采用静态代码块把多种单例类型注入到一个统一的管理类(静态内部类   ServiceFetcher )中,使用静态域(map SYSTEM_SERVICE_NAMES )来存储唯一一个实例,既保证了线程安全又保证了懒加载。

总结

1. ContextImpl使用SystemServiceRegistry 缓存、注册、获取系统服务的。SystemServiceRegistry 有一系列的静态语句块, 静态语句块在第—次加载该类时执行,只执行—次。在这里将各种  ServiceFetcher 注入到map中管理

2. 系统service的创建是懒加载的,只有在发生调用时会被创建。

3.  这种静态注册的方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口(context.getService())进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。

猜你喜欢

转载自blog.csdn.net/qq_33298609/article/details/116746469