理解 Context.getSystemService 原理

本人只是Android小菜一个,写技术文章只是为了总结本身最近学习到的知识,历来不敢为人师,若是里面有不正确的地方请你们尽情指出,谢谢!java

本文基于原生 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系统为程序开发者提供了各类各样的系统服务,以知足在不一样场景下的需求,例如: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实例,而后就能够“肆意”使用这个服务来完成本身想要的功能了。bash

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

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

2. 理解 Context.getSystemService 原理

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

2.1 LayoutInflater 获取过程

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

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

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

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<Class<?>, String> SYSTEM_SERVICE_NAMES =
            new HashMap<Class<?>, String>();
    
    // 保存系统服务的“描述名”和“获取类”的键值对,即 key=“服务描述名”,value=“服务获取类”。
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
            
    // 缓存类服务数量,用以提供服务在缓存中的索引。
    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<ActivityManager>() {
        @Override
        // 具体的建立方式
        public ActivityManager createService(ContextImpl ctx) {
            return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
        }});

    // 注册 ConnectivityManager 服务 - 静态应用类服务
    registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
            new StaticApplicationContextServiceFetcher<ConnectivityManager>() {
        @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<InputManager>() {
        @Override
        // 具体建立方式
        public InputManager createService() {
            return InputManager.getInstance();
        }});


    // 注册 LayoutInflater 服务
    registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
            new CachedServiceFetcher<LayoutInflater>() {
        @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 <T> void registerService(String serviceName, Class<T> serviceClass, ServiceFetcher<T> 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的总体流程和实现原理,并对系统服务的分类和具体建立方法进行了简要说明,但愿能对你们在系统服务方面有必定的帮忙。

相关文章
相关标签/搜索