本人只是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 複製代碼
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
知道這些就夠了嗎?固然不是,做爲一個「有理想有抱負」的程序員,在知道一項技術的基本用法以後,接下來要作的就是了解其背後的原理和實現方式,爭取作到「知其然更知其因此然」。markdown
本文將經過分析系統服務類LayoutInflater
實例的具體獲取過程來說解Context.getSystemService()
的實現原理,雖然其自己的邏輯並不複雜,仍但願能對感興趣但沒有時間查看源碼的同窗有所幫助。多線程
Android
系統框架中提供的系統服務多種多樣,要學習和理解其實現原理,必需要以一個具體的系統服務爲切入點,在這裏選擇LayoutInflater
服務爲入口,經過對其實例獲取過程的逐步分析來揭開Context.getSystemService()
的神祕面紗。併發
前面已經給出獲取LayoutInflater
服務實例的示例代碼,以下:app
// 在 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_SERVICE
和SEARCH_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()
獲取到的,這個方法纔是須要分析的核心。
前面已經分析到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)
根據服務描述名獲取系統服務實例的全過程,也對其中的實現方式和原理有了較深刻的理解。
本文以LayoutInflater
服務爲切入點,逐步分析其實例的獲取過程,講解Context.getSystemService
的總體流程和實現原理,並對系統服務的分類和具體建立方法進行了簡要說明,但願能對你們在系統服務方面有必定的幫忙。