安卓开发学习之获取系统上下文

背景

在安卓系统启动到初始化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()这两个方法的实现


ActivtyThread#systemMain()方法

    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

扫描二维码关注公众号,回复: 1979349 查看本文章
    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<String> 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<String> 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()的实现


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;
    }

结语

就是这样

猜你喜欢

转载自blog.csdn.net/qq_37475168/article/details/80909102
今日推荐