追踪 getSystemService
写过 Android 的同学都应该调用过这个函数 getSystemService(...),比如:
// 获取电话服务
TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
// 获取网络连接的服务
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
// 获取窗口服务
WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
getSystemService(serviceName) 用于获取系统服务,今天我们就从源码的角度来分析一下 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;
}
构造函数和 attachBaseContext(...) 可以初始化 mBase。
但无论是 ContextWrapper 的子类 Service,还是 ContextThemeWrapper (Activity 的父类),它们的构造函数都没有给 mBase 赋值:
// android.view.ContextThemeWrapper
public ContextThemeWrapper() {
super(null);
}
// android.app.Service
public Service() {
super(null);
}
看来一定是从 attachBaseContext(...) 来初始化 mBase 的了。
在 Service.java 和 Activity.java 中,我们分别找到了 �attachBaseContext(...) 的调用处:
// 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(...) 的参数 context 来自 attach() 函数。
要了解 attach()函数是何时被调用的,就必须了解 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) {
// 创建 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;
...
// 创建 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 ...
}
}
// 创建 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。
接下来就应该到 ContextImpl 中查看 getSystemService(...) 的实现了:
// android.app.ContextImpl
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
继续查看 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 中去获取系统服务,我们只要找到这个 HashMap 的数据来源即可:
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
...
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
原来就是 registerService(...) 是用来初始化 HashMap 的函数,很快我们就能在文件中定位到调用 registerService() 函数的静态方法块:
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(...) 分析结束。
我们来总结一下:
1、Context 的实现类为 android.app.ContextImpl;
2、系统服务缓存在一个 android.app.SystemServiceRegistry 的一个 HashMap 中;
全文完。