在安卓系统启动到初始化SystemServer进程的时候,会获取系统的上下文,在SystemServer创建过程中的相关调用如下
private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
final Context systemUiContext = activityThread.getSystemUiContext();
systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}
获取系统上下文相关操作是在ActivtyThread这个类里进行的,我们就从这个方法进入ActivityThread类,重点看ActivtyThread.systemMain()和activityThread.getSystemUiContext()这两个方法的实现
public static ActivityThread systemMain() {
// 是否采用硬件加速
if (!ActivityManager.isHighEndGfx()) {
ThreadedRenderer.disable(true);
} else {
ThreadedRenderer.enableForegroundTrimming();
}
ActivityThread thread = new ActivityThread(); // 实例化一个ActivityThread对象
thread.attach(true); // 调用attach()方法,进行一些初始化操作
return thread;
}
看一下attach()方法,进行了哪些操作
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
....
} else { // 传入的system参数是true
// 给ddm设置应用名和uid
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
// 创建上下文对象
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate(); // 默认是空实现
} catch (Exception e) {
.. // 异常
}
}
// 系统日志
DropBox.setReporter(new DropBoxReporter());
ViewRootImpl.ConfigChangedCallback configChangedCallback
= (Configuration globalConfig) -> {
synchronized (mResourcesManager) {
// 设置ViewRootImpl的回调,以便及时修改配置信息
if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
null /* compat */)) {
updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
mResourcesManager.getConfiguration().getLocales());
// 修改配置信息
if (mPendingConfiguration == null
|| mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
mPendingConfiguration = globalConfig;
sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
}
}
}
};
ViewRootImpl.addConfigCallback(configChangedCallback);
}
抛去日志、配置信息回调等部分,这个方法的核心就是try-cation里的那几行代码:
mInstrumentation = new Instrumentation(); // 实例化Instrumentation对象
// 创建上下文对象
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate(); // 默认是空实现
在进入ContextImpl.createAppContext()方法之前,调用了getSystemContext()方法,代码如下
public ContextImpl getSystemContext() {
synchronized (this) {
if (mSystemContext == null) {
mSystemContext = ContextImpl.createSystemContext(this);
}
return mSystemContext;
}
}
单例模式,如果之前没有mSystemContext单例,就调用ContextImpl.createSystemContext()方法,代码如下
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread); // 实例化packageInfo对象,类型是LoadedApk
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null);
context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
return context;
}
系统上下文对象的创建就如上所示,同时还创建了一个LoadedApk对象,做为packgeInfo,保存成ContextImpl的属性。LoadedApk的构造方法代码如下
LoadedApk(ActivityThread activityThread) {
mActivityThread = activityThread;
mApplicationInfo = new ApplicationInfo();
mApplicationInfo.packageName = "android";
mPackageName = "android"; // 包名是"android"
mAppDir = null;
mResDir = null;
mSplitAppDirs = null;
mSplitResDirs = null;
mOverlayDirs = null;
mSharedLibraries = null;
mDataDir = null;
mDataDirFile = null;
mDeviceProtectedDataDirFile = null;
mCredentialProtectedDataDirFile = null;
mLibDir = null;
mBaseClassLoader = null;
mSecurityViolation = false;
mIncludeCode = true;
mRegisterPackage = false;
mClassLoader = ClassLoader.getSystemClassLoader();
mResources = Resources.getSystem();
}
我们掉过头来,再看ContextImpl.createAppContext()方法的实现
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null);
context.setResources(packageInfo.getResources()); // 和系统上下文相比,少了一步更新配置
return context;
}
没什么好说的,只是createAppContext()创建的是应用的上下文,用来创建Application对象,而前面的createSystemContext创建的是系统上下文,用来创建LoadedApk对象,保存应用的包信息
回到ActivityThread.attach()方法,我们再看看LoadedApk.makeApplication()是如何创建Application对象的,这个LoadedApk,就是方才createSystemContext时new出来的保存应用的包信息的packageInfo
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) { // 传进来的参数:前者是true,后者是null
if (mApplication != null) { // 创建过了就返回
return mApplication;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application"; // 限定Application.className类名是"android.app.Application"
}
try {
java.lang.ClassLoader cl = getClassLoader(); // 获取ClassLoader
if (!mPackageName.equals("android")) { // mPackageName早在createSystemContext()实例化LoadedApk时就在LoadedApk的构造方法中被赋值成了"android"
..
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); // 创建Application的context
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext); // 正式创建Application对象
appContext.setOuterContext(app); // 给ApplicationContext绑定Application
} catch (Exception e) {
..
}
mActivityThread.mAllApplications.add(app); // 保存Application到数组中
mApplication = app; // 更新mApplication
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app); // 调用Application.onCreate(),但默认是空实现
} catch (Exception e) {
..
}
}
// Rewrite the R 'constants' for all library apks.
SparseArray packageIdentifiers = getAssets().getAssignedPackageIdentifiers(); // 获取包签名
final int N = packageIdentifiers.size();
for (int i = 0; i < N; i++) {
final int id = packageIdentifiers.keyAt(i);
if (id == 0x01 || id == 0x7f) { // 掐头去尾
continue;
}
rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id); // 通过反射调用每个包下R类的onResourceLoaded()方法,以更新R资源
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return app;
}
重点方法有两个:getClassLoader()和mActivityThread.mInstrumtation.newApplication(),先看前者:
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader == null) {
createOrUpdateClassLoaderLocked(null /*addedPaths*/);
}
return mClassLoader;
}
}
又是单例,如果mClassLoader不存在,直接调用createOrUpdateLoaderLocked()方法
private void createOrUpdateClassLoaderLocked(List addedPaths) {
if (mPackageName.equals("android")) {
// mPackageName在构造方法时被赋值成了"android"
if (mClassLoader != null) {
// mClassLoader不是null,直接返回
return;
}
if (mBaseClassLoader != null) { // 在构造方法里,mBaseClassLoader被赋值成了null
mClassLoader = mBaseClassLoader;
} else {
mClassLoader = ClassLoader.getSystemClassLoader(); // 获取系统的ClassLoader
}
return;
}
..
}
我们是从SystemServer获取系统上下文来的,所以得到的mClassLoader是通过ClassLoader.getSystemClassLoader()获取到的,这个方法的代码如下
public static ClassLoader getSystemClassLoader() {
return SystemClassLoader.loader;
}
SystemClassLoader.loader在定义时就被赋值了
static private class SystemClassLoader {
public static ClassLoader loader = ClassLoader.createSystemClassLoader();
}
是通过createSystemClassLoader()方法获取的
private static ClassLoader createSystemClassLoader() {
String classPath = System.getProperty("java.class.path", "."); // 获取java.class.path属性
String librarySearchPath = System.getProperty("java.library.path", ""); // 获取java.library.path属性
..
return new PathClassLoader(classPath, librarySearchPath, BootClassLoader.getInstance());
}
BootClassLoader.getInstance()就仅仅是获取BootClassLoader的单例,然后做为参数调用PathClassLoader的构造方法,所以外界获取到的SystemClassLoader是一个PathClassLoader对象。
回到LoadedApk.makeApplication()方法,再看看mActivityThread.mInstrumtation.newApplication()的实现
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
传进来的className在LoadedApk.makeApplication()里被赋值成了"android.app.Application",所以cl.loadClass(className)显然是通过反射获取了Application.class,然后进入newApplication()方法,代码如下
static public Application newApplication(Class> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance(); // clazz是Application.class
app.attach(context); // context是Application的上下文,Application.attach()就是保存了一下context和packageInfo
return app;
}
好,到这儿,LoadedApk.makeApplication()就执行完了,通过反射获取了一个Application对象,保存一下包信息,返回。
这样,SystemServer.createSystemContext()方法第一步,也是最主要的一步ActivityThread.systemMain()就执行完了,而后它是通过执行我们已经看过的activityThread.getSystemContext()方法获取系统上下文对象,并设置默认主题,而后调用activityThread.getSystemUiContext()获取系统UI的上下文,并设置默认主题。
接下来,我们就看一下activityThread.getSystemUiContext()的实现
代码如下
public ContextImpl getSystemUiContext() {
synchronized (this) {
if (mSystemUiContext == null) {
mSystemUiContext = ContextImpl.createSystemUiContext(getSystemContext());
}
return mSystemUiContext;
}
}
和获取SystemContext类似,都是单例模式,看一下ContextImpl是如何实现createSystemUiContext()的
static ContextImpl createSystemUiContext(ContextImpl systemContext) {
final LoadedApk packageInfo = systemContext.mPackageInfo;
ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null,
null, null, 0, null);
context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null,
packageInfo.getCompatibilityInfo())); // 和获取系统context相比,这里的资源标志位设置成了default_display,同时也不用更新配置
return context;
}
会发现,ContextImpl里几个createXXXContext()方法比较类似,我全部贴出来看个概览
static ContextImpl createSystemContext(ActivityThread mainThread) { // 获取系统上下文
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null);
context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
return context;
}
// 获取系统UI上下文
static ContextImpl createSystemUiContext(ContextImpl systemContext) {
final LoadedApk packageInfo = systemContext.mPackageInfo;
ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null,
null, null, 0, null);
context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null,
packageInfo.getCompatibilityInfo()));
return context;
}
// 获取应用上下文
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null);
context.setResources(packageInfo.getResources());
return context;
}
// 获取activity上下文
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
String[] splitDirs = packageInfo.getSplitResDirs();
ClassLoader classLoader = packageInfo.getClassLoader();
if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
try {
classLoader = packageInfo.getSplitClassLoader(activityInfo.splitName);
splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
} catch (NameNotFoundException e) {
// Nothing above us can handle a NameNotFoundException, better crash.
throw new RuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
activityToken, null, 0, classLoader);
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
final ResourcesManager resourcesManager = ResourcesManager.getInstance();
// Create the base resources for which all configuration contexts for this Activity
// will be rebased upon.
context.setResources(resourcesManager.createBaseActivityResources(activityToken,
packageInfo.getResDir(),
splitDirs,
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
classLoader));
context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
context.getResources());
return context;
}
就是这样