寫過 Android 的同學(xué)都應(yīng)該調(diào)用過這個函數(shù) getSystemService(...)好乐,比如:
// 獲取電話服務(wù)
TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
// 獲取網(wǎng)絡(luò)連接的服務(wù)
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
// 獲取窗口服務(wù)
WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
getSystemService(serviceName) 用于獲取系統(tǒng)服務(wù)瘾蛋,今天我們就從源碼的角度來分析一下 getSystemService 背后的邏輯是怎樣的搁拙。
按住 Ctrl + 鼠標左鍵掺炭,立即就能定位到 getSystemService 來自 ContextWrapper
// android.content.ContextWrapper
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
那么 mBase 是什么辫诅?它在哪里初始化的呢?
// android.content.ContextWrapper
Context mBase;
...
public ContextWrapper(Context base) {
mBase = base;
}
...
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
構(gòu)造函數(shù)和 attachBaseContext(...) 可以初始化 mBase涧狮。
但無論是 ContextWrapper 的子類 Service炕矮,還是 ContextThemeWrapper (Activity 的父類),它們的構(gòu)造函數(shù)都沒有給 mBase 賦值:
// android.view.ContextThemeWrapper
public ContextThemeWrapper() {
super(null);
}
// android.app.Service
public Service() {
super(null);
}
看來一定是從 attachBaseContext(...) 來初始化 mBase 的了勋篓。
在 Service.java 和 Activity.java 中吧享,我們分別找到了 ?attachBaseContext(...) 的調(diào)用處:
// android.app.Activity
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
...
}
// android.app.Service
public final void attach(Context context, ActivityThread thread, String className, IBinder token, Application application, Object activityManager) {
attachBaseContext(context);
...
}
原來 attachBaseContext(...) 的參數(shù) context 來自 attach() 函數(shù)。
要了解 attach()函數(shù)是何時被調(diào)用的譬嚣,就必須了解 Framework 初始化 Service 和 Activity 的流程钢颂,通過查看 Android FrameWork 源碼,我們定位到這里:
// android.app.ActivitThread
// --- activity ---
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
// 創(chuàng)建 context
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
// attach(...)
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
...
}
...
}
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
int displayId = Display.DEFAULT_DISPLAY;
...
// 創(chuàng)建 context
ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;
...
}
// --- service ----
private void handleCreateService(CreateServiceData data) {
LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw ...
}
}
// 創(chuàng)建 context
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
// attach(...)
service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault());
service.onCreate();
...
}
到此拜银,mBase 找到了殊鞭,原來是 ContextImpl。
接下來就應(yīng)該到 ContextImpl 中查看 getSystemService(...) 的實現(xiàn)了:
// android.app.ContextImpl
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
繼續(xù)查看 SystemServiceRegistry
// android.app.SystemServiceRegistry
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS = new HashMap<String, ServiceFetcher<?>>();
可以看到尼桶,getSystemServer(...) 最終會到 SYSTEM_SERVICE_FETCHERS 這個 HashMap 中去獲取系統(tǒng)服務(wù)操灿,我們只要找到這個 HashMap 的數(shù)據(jù)來源即可:
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
...
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
原來就是 registerService(...) 是用來初始化 HashMap 的函數(shù),很快我們就能在文件中定位到調(diào)用 registerService() 函數(shù)的靜態(tài)方法塊:
static{
...
registerService(Context.WINDOW_SERVICE, WindowManager.class,
new CachedServiceFetcher<WindowManager>() {
@Override
public WindowManager createService(ContextImpl ctx) {
return new WindowManagerImpl(ctx.getDisplay());
}});
...
registerService(Context.BLUETOOTH_SERVICE, BluetoothManager.class,
new CachedServiceFetcher<BluetoothManager>() {
@Override
public BluetoothManager createService(ContextImpl ctx) {
return new BluetoothManager(ctx);
}});
}
到此泵督,getSystemService(...) 分析結(jié)束趾盐。
我們來總結(jié)一下:
1、Context 的實現(xiàn)類為 android.app.ContextImpl小腊;
2救鲤、系統(tǒng)服務(wù)緩存在一個 android.app.SystemServiceRegistry 的一個 HashMap 中;
全文完秩冈。