理解 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的總體流程和實現原理,並對系統服務的分類和具體建立方法進行了簡要說明,但願能對你們在系統服務方面有必定的幫忙。

相關文章
相關標籤/搜索