系统启动流程分析之SystemServer.createSystemContext函数流程分析

410 阅读3分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。

SystemServer.createSystemContext函数流程分析

SystemServer在启动过程中,在其run函数中,会调用createSystemContext函数来初始化系统上下文Context,从这个函数来看,其中部分代码较为复杂,因此,今天我们单独来看下这个函数具体做了什么动作

createSystemContext();

private void createSystemContext() {
    // 初始化ActivityThread对象
    ActivityThread activityThread = ActivityThread.systemMain();
    // 获取系统上下文Context
    mSystemContext = activityThread.getSystemContext();
    // 设置系统默认主题
    mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
    // 设置系统SystemUI默认主题
    final Context systemUiContext = activityThread.getSystemUiContext();
    systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
}

初始化ActivityThread对象

ActivityThread.systemMain
public static ActivityThread systemMain() {
    // The system process on low-memory devices do not get to use hardware
    // accelerated drawing, since this can add too much overhead to the
    // process.
    // 低内存的设备不允许使用硬件加速来绘制界面,因为硬件加速功能对于进程有很多额外的开销
    if (!ActivityManager.isHighEndGfx()) {
        ThreadedRenderer.disable(true);
    } else {
        ThreadedRenderer.enableForegroundTrimming();
    }
    // 直接new一个ActivityThread,然后调用其attach函数
    // 注意attach函数的两个参数分别为true和0
    ActivityThread thread = new ActivityThread();
    thread.attach(true, 0);
    return thread;
}

初始化一个ActivityThread对象,并且调用其attach函数

ActivityThread() {
    // 单例模式创建ResourcesManager对象
    mResourcesManager = ResourcesManager.getInstance();
}

// 接下来调用其attach函数
private void attach(boolean system, long startSeq) {
    // 设置ActivityThread.sCurrentActivityThread为当前ActivityThread对象
    sCurrentActivityThread = this;
    // 设置ActivityThread.mSystemThread = true
    mSystemThread = system;
    if (!system) {
        // ...... 第一个参数为true,这边分支无法进入,省略
    } else {
        // Don't set application object here -- if the system crashes,
        // we can't display an alert, we just want to die die die.
        // 设置DDMS进程名称
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());
        try {
            // 初始化一个Instrumentation对象,并调用其basicInit函数
            mInstrumentation = new Instrumentation();
            // 将当前的ActivityThread对象设置给Instrumentation的mThread参数
            mInstrumentation.basicInit(this);
            // 创建一个ContextImpl对象
            // 传递system ContextImpl对象的LoadedApk对象
            // getSystemContext()函数中会创建和返回一个单例的ContextImpl对象,这个对象的mPackageInfo对象为初始化的一个LoadedApk对象
            // ContextImpl.createAppContext函数初始化一个ContextImpl对象
            // 这块的代码其实个人有点不太理解,因为getSystemContext函数应用单例模式,返回一个ContextImpl作为system context,然后返回其LoadedApk对象
            // 而ContextImpl.createAppContext函数初始化ContextImpl对象后,直接使用其mPackageInfo参数,
            // 根据代码分析,此处返回的依旧是上述初始化的LoadedApk对象,那么此处为何需要多此一举呢?直接使用system context的LoadedApk对象不就好了么?
            ContextImpl context = ContextImpl.createAppContext(this, getSystemContext().mPackageInfo);
            // 初始Application,下属两条语句的主要工作是:
            // 初始化了一个Application对象,然后调用其attach函数,最后调用其onCreate函数,
            // 同时设定LoadedApk.mApplication为当前的Application对象,
            // 并且将 Application对象添加到mActivityThread.mAllApplications中
            mInitialApplication = context.mPackageInfo.makeApplication(true, null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }

    // 4. 配置ViewRootImpl的配置变化回调函数类
    ViewRootImpl.ConfigChangedCallback configChangedCallback
            = (Configuration globalConfig) -> {
        synchronized (mResourcesManager) {
            // ...... 无效代码,省略
            // We need to apply this change to the resources immediately, because upon returning
            // the view hierarchy will be informed about it.
            if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                    null /* compat */,
                    mInitialApplication.getResources().getDisplayAdjustments())) {
                updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                        mResourcesManager.getConfiguration().getLocales());

                // This actually changed the resources! Tell everyone about it.
                if (mPendingConfiguration == null
                        || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
                    mPendingConfiguration = globalConfig;
                    sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                }
            }
        }
    };
    ViewRootImpl.addConfigCallback(configChangedCallback);
}

如上的代码注释中已经将这个函数的主要功能均已经描述,此处不再重复赘述

获取系统上下文Context

// 获取系统上下文Context
// 在此前的的ActivityThread.systemMain函数中,
// ActivityThread.attach函数其实已经调用过此处的ContextImpl.createSystemContext函数,
// 而该函数又是单例的,因此此处会直接返回ActivityThread.mSystemContext对象
mSystemContext = activityThread.getSystemContext();
// 设置系统默认主题
mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
// 设置系统SystemUI默认主题
// 同system context一样,此处的ActivityThread.getSystemUiContext函数,也是使用了单例模式
// 初始化一个参数名为mSystemUiContext的ContextImpl对象
final Context systemUiContext = activityThread.getSystemUiContext();
systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);

总结

在SystemServer.createSystemContext函数中,主要是做了如下的几个操作

  1. 调用ActivityThread.systemMain函数,

    在这个函数中初始化一个ActivityThread对象,

    并且设置ActivityThread.sCurrentActivityThread为当前ActivityThread对象,

    且设置ActivityThread.mSystemThread = true,同时调用Activity.attach函数

    同时设置初始化ActivityThread.mInstrumentation

    初始化ActivityThread.mInitialApplication为Application对象,并调用其attach函数和onCreate函数,同时设置LoadedApk.mApplication为该Application对象,并将这个Application对象添加到mActivityThread.mAllApplications中

  2. 通过ActivityThread的getSystemContext和getSystemUiContext函数,初始化两个ContextImpl对象,分别标识System和SystemUi的上下文,并且设置他们的默认主题

SystemServer.createSystemContext函数调用时序图

图片.png