【Android】 context.getSystemService()浅析

同事在进行code review的时候问到我context中的getSystemService方法在哪实现的,他看到了一个ClipBoardManager来进行剪切板存储数据的工具方法中用到了context.getSystemService(),而此处我使用的是Application级别的Context进行调用的,可IDE跳转时发现当前类中的getSystemService()方法居然是抽象的,Context类就是一个抽象类,没有具体的实现,可在进行调用的时候却一切正常,同事好奇该方法具体实现在哪实现的,于是我俩一起看源码和查资料后发现有几个值得注意的地方:

  • 系统service获取和分享的问题,源码中提示到:

Note:  System services obtained via this API may be closely associated with the Context in which they are obtained from.  In general, do not share the service objects between various different contexts (Activities, Applications, Services, Providers, etc.)

大意: 获取的系统service可能和他们的context有紧密联系,一般来说不要在不同的context之间分享服务对象,如Activity、Application、Service、Provider

明显同样的方法调用的具体实现不同,从同样拥有getSystemService的Activity的实现可以看到,虽然最终调用还是从LayoutInflater的context获取

/*
 * Activity中的getSystemService()
 */
@Override
public Object getSystemService(@ServiceName @NonNull String name) {
    if (getBaseContext() == null) {
        throw new IllegalStateException(
                "System services not available to Activities before onCreate()");
    }

    if (WINDOW_SERVICE.equals(name)) {
        return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
        ensureSearchManager();
        return mSearchManager;
    }
  	// 以上的判断仅仅是为了检查是否为WindowManager获取窗口的服务
    return super.getSystemService(name);
}

通过super.getSystemService(name)跳转到ContextThemeWrapper这个Context.java类的代理类中,然而也并非是真正的具体实现,但是在此我们可以得知LayoutInflater实际上也是获取的是Application级别的全局context,因为该context也是该类中的mBase获取的😄:

@Override
public Context getApplicationContext() {
    return mBase.getApplicationContext();
}
/*
 * ContextThemeWrapper中的getSystemService()
 */
@Override public Object getSystemService(String name) {
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
        if (mInflater == null) {
            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
        }
        return mInflater;
    }
    return getBaseContext().getSystemService(name);
}

最后又追溯到了Context.java中的getSystemService(),什么情况呢,具体实现在哪??一番折腾后,找到了对应的Context实现类:ContextImpl.java

@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}

@Override
public String getSystemServiceName(Class<?> serviceClass) {
    return SystemServiceRegistry.getSystemServiceName(serviceClass);
}

终于SystemServiceRegistry这个类中有了getSystemService的具体实现,调用的方法其实是getService(),这里三个方法很重要:

/**
 * Creates an array which is used to cache per-Context service instances.
 */
public static Object[] createServiceCache() {
    return new Object[sServiceCacheSize];
}

/**
 * Gets a system service from a given context.
 */
public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}

/**
 * Gets the name of the system-level service that is represented by the specified class.
 */
public static String getSystemServiceName(Class<?> serviceClass) {
    return SYSTEM_SERVICE_NAMES.get(serviceClass);
}

/**
 * Statically registers a system service with the context.
 * This method must be called during static initialization only.
 */
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);
}

可以看出三个方法对service进行了创建、获取和注册。而SystemServiceRegistry这个类负责创建、启动和管理所有的服务,当需要用到哪个服务的时候,调用到getService方法然后进行名字的索引来找到需要的服务,里面的关键元素:

  • serviceFetcher
  • IBinder,没错,实际上刚开始初始化的时候就是通过匿名内部类生成对应名字的服务,然后因为这些都是binder

在启动APP时进行了必备的service注册,关于注册的服务就不列举了太多了,结构大致如此:

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);
        }});

    registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
            new CachedServiceFetcher<AccountManager>() {
        @Override
        public AccountManager createService(ContextImpl ctx) {
            IBinder b = ServiceManager.getService(Context.ACCOUNT_SERVICE);
            IAccountManager service = IAccountManager.Stub.asInterface(b);
            return new AccountManager(ctx, service);
        }});
  
     // 代码省略。。。。
}

感兴趣的朋友可以自己看看,进行注册时候是通过HashMap的方式将服务的名字进行了索引存放。

上部分的代码中,可以看到有serviceFetcher相关的匿名内部类,每个服务对应了不同的实现,因此方法也是抽象的,下面是三个对应的静态抽象内部类和一个接口:

/**
 * Base interface for classes that fetch services.
 * These objects must only be created during static initialization.
 */
static abstract interface ServiceFetcher<T> {
    T getService(ContextImpl ctx);
}

/**
 * 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;

    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);
}

/**
 * Override this class when the system service does not need a ContextImpl
 * and should be cached and retained process-wide.
 */
static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
    private T mCachedInstance;

    @Override
    public final T getService(ContextImpl unused) {
        synchronized (StaticServiceFetcher.this) {
            if (mCachedInstance == null) {
                mCachedInstance = createService();
            }
            return mCachedInstance;
        }
    }

    public abstract T createService();
}

/**
 * Like StaticServiceFetcher, creates only one instance of the service per process, but when
 * creating the service for the first time, passes it the outer context of the creating
 * component.
 *
 * TODO: Is this safe in the case where multiple applications share the same process?
 * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
 * case where multiple application components each have their own ConnectivityManager object.
 */
static abstract class StaticOuterContextServiceFetcher<T> implements ServiceFetcher<T> {
    private T mCachedInstance;

    @Override
    public final T getService(ContextImpl ctx) {
        synchronized (StaticOuterContextServiceFetcher.this) {
            if (mCachedInstance == null) {
                mCachedInstance = createService(ctx.getOuterContext());
            }
            return mCachedInstance;
        }
    }

    public abstract T createService(Context applicationContext);
}

我俩整个过程花了15分钟就了解了getSystemService的具体调用和实现的方式,还是源码来得快,在进阶Android开发过程中,阅读系统和三方类库的源码能够帮我们事半功倍的效果。

posted @ 2016-09-02 01:03  Codios  阅读(13150)  评论(0编辑  收藏  举报