理解 Context.getSystemService 原理

本人只是Android小菜一个,写技术文章只是为了总结自己最近学习到的知识,从来不敢为人师,如果里面有不正确的地方请大家尽情指出,谢谢!

本文基于原生 Android 9.0 源码来解析 Context.getSystemService 原理:

frameworks/base/core/java/android/app/Activity.java
frameworks/base/core/java/android/view/ContextThemeWrapper.java
frameworks/base/core/java/android/view/LayoutInflater.java
frameworks/base/core/java/android/content/Context.java
frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/SystemServiceRegistry.java
复制代码

1. 概述

Android系统为程序开发者提供了各种各样的系统服务,以满足在不同场景下的需求,例如:

  • LayoutInflater:把layout布局文件渲染成view控件对象;
  • DownloadManager:发起下载任务,从特定文件来源中下载文件;
  • CameraManager:调用系统摄像组件进行拍照录像等功能。

这里只列举了几个常用的系统服务,实际上现在Android框架中存在的系统服务要远远多于这些,基本涵盖了所有的系统服务类型,同时Android框架为了帮助程序开发者更便捷地获取和使用这些服务,提供了一个统一的接口Context.getSystemService(),通过这个接口,开发者可以很方便快捷地获取想要的系统服务。

通过获取LayoutInflater系统服务实例的过程来简单了解下getSystemService()的基本使用方法,示例代码如下:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 1. 通过 getSystemService 系统接口获取 LayoutInflater 服务实例
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        // 2. 使用获取到的 LayoutInflater 服务来把布局文件渲染成控件对象
        View view = inflater.inflate(R.layout.view_merge, null);
    }
}
复制代码

简直太简单了! 只通过一行代码就获取到了LayoutInflater实例,然后就可以“肆意”使用这个服务来完成自己想要的功能了。

知道这些就够了吗?当然不是,作为一个“有理想有抱负”的程序员,在知道一项技术的基本用法之后,接下来要做的就是了解其背后的原理和实现方式,争取做到“知其然更知其所以然”。

本文将通过分析系统服务类LayoutInflater实例的具体获取过程来讲解Context.getSystemService()的实现原理,虽然其本身的逻辑并不复杂,仍希望能对感兴趣但没有时间查看源码的同学有所帮助。

2. 理解 Context.getSystemService 原理

Android系统框架中提供的系统服务多种多样,要学习和理解其实现原理,必须要以一个具体的系统服务为切入点,在这里选择LayoutInflater服务为入口,通过对其实例获取过程的逐步分析来揭开Context.getSystemService()的神秘面纱。

2.1 LayoutInflater 获取过程

前面已经给出获取LayoutInflater服务实例的示例代码,如下:

// 在 Activity 中调用 getSystemService 获取 LayoutInflater 服务对象。
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
复制代码

这里通过Activity.getSystemService()获取LayoutInflater服务实例,直接看这块代码:

public Object getSystemService(@ServiceName @NonNull String name) {
    // 检查 context 是否存在,只有在 Activity 调用了 onCreate 才存在。
    if (getBaseContext() == null) {
        throw new IllegalStateException(
                "System services not available to Activities before onCreate()");
    }

    // 针对 WINDOW_SERVICE 和 SEARCH_SERVICE 可用直接返回相关服务实例。
    if (WINDOW_SERVICE.equals(name)) {
        return mWindowManager;
    } else if (SEARCH_SERVICE.equals(name)) {
        ensureSearchManager();
        return mSearchManager;
    }
    // 返回其他类型的系统服务,LayoutInflater 会走到这里。
    return super.getSystemService(name);
}
复制代码

Activity中返回了WINDOW_SERVICESEARCH_SERVICE两种特殊类型的系统服务,其他类型的服务则继续调用super.getSystemService()获取,这里的super指的是ContextThemeWrapper,转到这里继续分析:

@Override
public Object getSystemService(String name) {
    // 在获取 LayoutInflater 实例时传入的名字就是 LAYOUT_INFLATER_SERVICE,此时会走到这里。
    if (LAYOUT_INFLATER_SERVICE.equals(name)) {
        if (mInflater == null) {
            mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
        }
        return mInflater;
    }
    // 其他类型的系统服务继续调用 getSystemService 来获取服务实例。
    return getBaseContext().getSystemService(name);
}
复制代码

ContextThemeWrapper.getSystemService也没有真正返回服务实例,而是继续调用LayoutInflater.from():

/**
 * Obtains the LayoutInflater from the given context.
 */
public static LayoutInflater from(Context context) {
    // 调用 Context.getSystemService 获取 LayoutInflater 实例。
    LayoutInflater LayoutInflater =
            (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    // 获取失败则抛出异常。
    if (LayoutInflater == null) {
        throw new AssertionError("LayoutInflater not found.");
    }
    return LayoutInflater;
}
复制代码

转了一圈,LayoutInflater的实例对象原来是通过其内部静态方法from()调用Context.getSystemService()获取到的,这个方法才是需要分析的核心。

2.2 解析 Context.getSystemService 原理

前面已经分析到LayoutInflater实例是通过Context.getSystemService获取的,马上来看看这个获取过程:

 public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
复制代码

Context并没有提供具体的实现,而是仅仅提供了一个抽象的getSystemService()接口,其具体实现应该在Context的实现类中。我们知道在Android系统中Context的实现类是ContextImpl,继续来看ContextImpl.getSystemService():

/**
 * Common implementation of Context API, which provides the base
 * context object for Activity and other application components.
 */
class ContextImpl extends Context {
    // 省略无关代码
    
    // The system service cache for the system services that are cached per-ContextImpl.
    // 有些系统服务是需要进行缓存的,这样针对同一个 ContextImpl 实例就只需要创建服务一次。
    // 在创建之后把服务实例缓存起来,以后同一个 ContextImpl 实例获取服务时只需要从缓存查找即可。
    final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();

    // 服务状态 - 还没有初始化
    static final int STATE_UNINITIALIZED = 0;
    // 服务状态 - 正在初始化
    static final int STATE_INITIALIZING = 1;
    // 服务状态 - 初始化阶段完成且找到了服务
    static final int STATE_READY = 2;
    // 服务状态 - 初始化阶段完成但没有找到服务
    static final int STATE_NOT_FOUND = 3;

    /**
     * Initialization state for each service. Any of {@link #STATE_UNINITIALIZED},
     * {@link #STATE_INITIALIZING} or {@link #STATE_READY},
     */
    @ServiceInitializationState
    // 保存每个服务的初始化状态
    final int[] mServiceInitializationStateArray = new int[mServiceCache.length];
    
    // 省略无关代码
    
    @Override
    public Object getSystemService(String name) {
        // 调用 SystemServieRegistry 获取系统服务
        return SystemServiceRegistry.getSystemService(this, name);
    }
    // 省略无关代码
复制代码

分析到这里,终于看到了和系统服务直接相关的变量和方法了,最终调用SystemServiceRegistry来创建系统服务实例,那这个SystemServiceRegistry又是如何完成系统服务的创建并返回的呢?

/**
 * Manages all of the system services that can be returned by {@link Context#getSystemService}.
 * Used by {@link ContextImpl}.
 */
final class SystemServiceRegistry {
    private static final String TAG = "SystemServiceRegistry";

    // Service registry information.
    // This information is never changed once static initialization has completed.
    // 保存系统“服务实现类”和“服务描述名”的键值对,即 key=“服务实现类”,value=“服务描述名”。
    private static final HashMap, String> SYSTEM_SERVICE_NAMES =
            new HashMap, String>();
    
    // 保存系统服务的“描述名”和“获取类”的键值对,即 key=“服务描述名”,value=“服务获取类”。
    private static final HashMap> SYSTEM_SERVICE_FETCHERS =
            new HashMap>();
            
    // 缓存类服务数量,用以提供服务在缓存中的索引。
    private static int sServiceCacheSize;

    // Not instantiable.
    private SystemServiceRegistry() { }
    
    /**
     * 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;
    }
复制代码

SystemServiceRegistry.getSystemService()内部要先通过“服务描述名”查找到“服务获取类”,这里之所以把 ServiceFetcher称为“获取类”,是因为它不仅负责返回对应的系统服务还要在必要的时候创建服务对象,可见ServiceFetcher类在系统服务机制中的重要作用:

/**
 * Base interface for classes that fetch services.
 * These objects must only be created during static initialization.
 */
static abstract interface ServiceFetcher<T> {
    // ServiceFetcher 接口中只提供了一个返回服务的接口。
    T getService(ContextImpl ctx);
}
复制代码

ServiceFetcher是一个接口类,实际在Android系统中有三个不同的实现类,用于创建不同类型的系统服务。

  • 缓存类系统服务: 在创建的时候需要ContextImpl参数,并且会把创建的系统服务缓存起来,这样以后同一个ContextImpl再次获取该类系统服务时不再创建直接返回缓存中的服务对象即可,LayoutInflater属于这类服务。
/**
 * 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() {
        // 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++;
    }

    @Override
    @SuppressWarnings("unchecked")
    public final T getService(ContextImpl ctx) {
        // SystemServiceRegistry 里的服务缓存
        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];
                // 查询服务缓存时有两种情况可以直接返回:
                // 1. service != null 表示该类服务已经被创建并保存在服务缓存里,直接返回服务实例即可;
                // 2. service == null && gets[mCacheIndex] == ContextImpl.STATE_NOT_FOUND
                // 表示该类服务已经尝试创建了,但是并没有成功,这里也不再尝试创建了,直接返回 null 即可。
                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) {
                    // 缓存中没有找到服务实例,但是其状态是 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;
                    // 更新服务状态为 STATE_INITIALIZING,表示接下来开始创建该系统服务。
                    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.
                    // 尝试创建服务,并在创建成功后更新服务状态为 STATE_READY.
                    service = createService(ctx);
                    newState = ContextImpl.STATE_READY;

                } catch (ServiceNotFoundException e) {
                    // 如果没有找到服务,服务状态仍然为 STATE_NOT_FOUND 并且服务实例是 null.
                    onServiceNotFound(e);
                } finally {
                    synchronized (cache) {
                        // 把服务实例和服务状态保存到缓存中去,有两种可能:
                        // 1. 服务创建成功时,把创建的服务实例和状态 STATE_READY 分别缓存起来;
                        // 2. 服务创建失败时,把 null 和状态 STATE_NOT_FOUND 分别缓存起来。
                        // 在后续查询缓存的过程中,只要是这两种情况就直接返回不再进行创建。
                        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;
                    }
                }
            }
        }
    }
    // 创建服务,需要具体的子类去实现,在创建过程中需要传递 ContextImpl 参数。
    public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
}
复制代码
  • 静态类系统服务:在创建的时候不需要ContextImpl参数,是一个单例对象,可以跨进程使用,InputManager就属于这一类型的系统服务。
/**
 * 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 ctx) {
        // 使用单例模式创建服务对象,保证只存在一个服务对象。
        synchronized (StaticServiceFetcher.this) {
            if (mCachedInstance == null) {
                try {
                    mCachedInstance = createService();
                } catch (ServiceNotFoundException e) {
                    onServiceNotFound(e);
                }
            }
            return mCachedInstance;
        }
    }
    // 创建服务,需要具体的子类去实现,在创建过程中不需要 ContextImpl 参数。
    public abstract T createService() throws ServiceNotFoundException;
}
复制代码
  • 静态应用类系统服务:在创建的时候使用Application Context,每个进程只有一个服务实例,目前在整个Android系统中只有ConnectivityManager属于这类服务。
/**
 * Like StaticServiceFetcher, creates only one instance of the service per application, but when
 * creating the service for the first time, passes it the application context of the creating
 * application.
 *
 * 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 StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {
    // 单例服务对象
    private T mCachedInstance;

    @Override
    public final T getService(ContextImpl ctx) {
        synchronized (StaticApplicationContextServiceFetcher.this) {
            if (mCachedInstance == null) {
                // 获取对应进程的 context 信息
                Context appContext = ctx.getApplicationContext();
                // 创建单例服务对象并返回
                try {
                    mCachedInstance = createService(appContext != null ? appContext : ctx);
                } catch (ServiceNotFoundException e) {
                    onServiceNotFound(e);
                }
            }
            return mCachedInstance;
        }
    }
    // 创建服务,需要具体的子类去实现,需要传递 Application Context 参数。
    public abstract T createService(Context applicationContext) throws ServiceNotFoundException;
}
复制代码

在了解Android框架中对系统服务的不同分类后,再回到之前的问题:SystemServiceRegistry.getSystemService()是如何返回具体服务实例的呢?

/**
 * 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;
}
复制代码

可以看到在获取服务实例过程中是根据传入的name信息去找到对应的ServiceFetcher对象,再由ServiceFetcher中的getService返回具体服务,getService针对不同类型的服务有不同的返回方式,这点在前面已经讲到。

现在剩下的疑问就是SYSTEM_SERVICE_FETCHERS里面的ServiceFetcher是什么时候被添加进去的呢?如果你曾经看过SystemServiceRegistry的代码就会很容易发现这点,在其内部有一大段静态代码块,所有的ServiceFetcher都是在这里注册的:

static {
    // 省略其他代码
    
    // 注册 ActivityManager 服务 - 缓存类服务
    registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
            new CachedServiceFetcher() {
        @Override
        // 具体的创建方式
        public ActivityManager createService(ContextImpl ctx) {
            return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
        }});

    // 注册 ConnectivityManager 服务 - 静态应用类服务
    registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
            new StaticApplicationContextServiceFetcher() {
        @Override
        // 具体创建方式
        public ConnectivityManager createService(Context context) throws ServiceNotFoundException {
            IBinder b = ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
            IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
            return new ConnectivityManager(context, service);
        }});

    // 注册 InputManager 服务 - 静态类服务
    registerService(Context.INPUT_SERVICE, InputManager.class,
            new StaticServiceFetcher() {
        @Override
        // 具体创建方式
        public InputManager createService() {
            return InputManager.getInstance();
        }});


    // 注册 LayoutInflater 服务
    registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
            new CachedServiceFetcher() {
        @Override
        // 具体创建方式,返回的是 PhoneLayoutInflater 实例,它是 LayoutInflater 的实现类。
        public LayoutInflater createService(ContextImpl ctx) {
            return new PhoneLayoutInflater(ctx.getOuterContext());
        }});
}

/**
 * Statically registers a system service with the context.
 * This method must be called during static initialization only.
 */
private static  void registerService(String serviceName, Class serviceClass,
        ServiceFetcher serviceFetcher) {
    // 把“服务实现类”和“服务描述名”键值对存入 SYSTEM_SERVICE_NAMES 表。
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    // 把“服务描述名”和“服务获取类”键值对存入 SYSTEM_SERVICE_FETCHER 表,
    // 后续就可以直接通过“服务描述名”来找到“服务获取类”了,进而获取具体的服务实例,getSystemService 就是如此。
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
复制代码

SystemServiceRegistry类被加载的时候,其静态代码块就会通过registerService把所有的系统服务都进行注册,并把“服务实现类”-“服务描述名”键值对和“服务描述名”-“服务获取类”键值对分别保存,这样后续通过getSystemService(name)查询具体服务实例时,就可以直接通过“服务描述名”找到“服务获取类”,进而获取到服务实例。

实际上这段静态代码非常长,里面注册了所有的系统服务,这里只针对每一种服务类型显示了一个具体服务的注册过程,同时也显示了一直关心的LayoutInflater实例的注册方式,其返回的是PhoneLayoutInflater实现类。

自此,终于看到Context.getSystemService(name)根据服务描述名获取系统服务实例的全过程,也对其中的实现方式和原理有了较深入的理解。

3. 总结

本文以LayoutInflater服务为切入点,逐步分析其实例的获取过程,讲解Context.getSystemService的整体流程和实现原理,并对系统服务的分类和具体创建方法进行了简要说明,希望能对大家在系统服务方面有一定的帮忙。

你可能感兴趣的:(理解 Context.getSystemService 原理)