• 笔记:Context


    Context 是上下文对象,是 Android 常用类 Activity、Service 和 Application 都间接继承 Context ,Context 是一个抽象类,内部定义了很多方法和静态常量,具体实现类是 ContextImpl
    在这里插入图片描述
    ContextImpl 和 ContextWrapper 继承子 Context ,ContextWrapper 内部包含了一个 Context 类型的对象 mBase对象,这个对象指向 ContextImpl ,ContextWrapper 是装饰类,它对 ContextImpl 进行了包装,ContextThemeWrapper、Service、Application 都继承自 ContextWrapper 都可以通过 mBase 来使用 Context 的方法,同时它们也是装饰了,ContextThemeWrapper 中包含了和主题相关的方法

    Application Context 创建过程

    Android 应用程序启动的最后一步,也是应用程序的入口是 RuntimeInit.java 类通过反射调用其静态 main 方法并创建 ActivityThread 对象
    位置:\frameworks\base\core\java\android\app\ActivityThread.java

    	public static void main(String[] args) {
            ......
    
            Looper.prepareMainLooper();	// 创建一个消息循环
    
            ......
            ActivityThread thread = new ActivityThread(); 	// 创建 ActivityThread 对象
            thread.attach(false, startSeq);					// 并调用attach方法
    
            ......
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    
    	private void attach(boolean system, long startSeq) {
            sCurrentActivityThread = this;
            mSystemThread = system;
            if (!system) {
                ......
                final IActivityManager mgr = ActivityManager.getService();
                try {
                    mgr.attachApplication(mAppThread, startSeq);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
                ......
            } else {
               ......
                try {
                    mInstrumentation = new Instrumentation();
                    mInstrumentation.basicInit(this);
                    ContextImpl context = ContextImpl.createAppContext(
                            this, getSystemContext().mPackageInfo);
                    mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                    mInitialApplication.onCreate();
                } catch (Exception e) {
                    throw new RuntimeException(
                            "Unable to instantiate Application():" + e.toString(), e);
                }
            }
    		.......
        }
    

    system 表示是否是系统进程,这个只有在 Framework 进程启动时才会调用到,直接调用了 attachApplication 方法,通过 Binder进程间通讯的方式,向 AMS 发送了一个消息
    位置:\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

    	@Override
        public final void attachApplication(IApplicationThread thread, long startSeq) {
            if (thread == null) {
                throw new SecurityException("Invalid application interface");
            }
            synchronized (this) {
                int callingPid = Binder.getCallingPid();
                final int callingUid = Binder.getCallingUid();
                final long origId = Binder.clearCallingIdentity();
                attachApplicationLocked(thread, callingPid, callingUid, startSeq);  // 调用 attachApplicationLocked 方法
                Binder.restoreCallingIdentity(origId);
            }
        }
    
    	@GuardedBy("this")
        private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
                int pid, int callingUid, long startSeq) {
    
            ......
                if (app.isolatedEntryPoint != null) {
                    // This is an isolated process which should just call an entry point instead of
                    // being bound to an application.
                    thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
                } else if (app.instr != null) {
                    thread.bindApplication(processName, appInfo, providers,
                            app.instr.mClass,
                            profilerInfo, app.instr.mArguments,
                            app.instr.mWatcher,
                            app.instr.mUiAutomationConnection, testMode,
                            mBinderTransactionTrackingEnabled, enableTrackAllocation,
                            isRestrictedBackupMode || !normalMode, app.persistent,
                            new Configuration(getGlobalConfiguration()), app.compat,
                            getCommonServicesLocked(app.isolated),
                            mCoreSettingsObserver.getCoreSettingsLocked(),
                            buildSerial, isAutofillCompatEnabled);
                } else {
                    thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                            null, null, null, testMode,
                            mBinderTransactionTrackingEnabled, enableTrackAllocation,
                            isRestrictedBackupMode || !normalMode, app.persistent,
                            new Configuration(getGlobalConfiguration()), app.compat,
                            getCommonServicesLocked(app.isolated),
                            mCoreSettingsObserver.getCoreSettingsLocked(),
                            buildSerial, isAutofillCompatEnabled);
                }
            ......
            return true;
        }
    

    可以看到这里面又调用了 IApplicationThread.bindApplication 方法,IApplicationThread 是 ActivityThread 中 ApplicationThread binder 对象的客户端
    位置:\frameworks\base\core\java\android\app\ActivityThread.java

    	private class ApplicationThread extends IApplicationThread.Stub {
    		......
    		public final void bindApplication(String processName, ApplicationInfo appInfo,
                    List<ProviderInfo> providers, ComponentName instrumentationName,
                    ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                    IInstrumentationWatcher instrumentationWatcher,
                    IUiAutomationConnection instrumentationUiConnection, int debugMode,
                    boolean enableBinderTracking, boolean trackAllocation,
                    boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                    CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                    String buildSerial, boolean autofillCompatibilityEnabled) {
    
                if (services != null) {
                    if (false) {
                        // Test code to make sure the app could see the passed-in services.
                        for (Object oname : services.keySet()) {
                            if (services.get(oname) == null) {
                                continue; // AM just passed in a null service.
                            }
                            String name = (String) oname;
    
                            // See b/79378449 about the following exemption.
                            switch (name) {
                                case "package":
                                case Context.WINDOW_SERVICE:
                                    continue;
                            }
    
                            if (ServiceManager.getService(name) == null) {
                                Log.wtf(TAG, "Service " + name + " should be accessible by this app");
                            }
                        }
                    }
    
                    // Setup the service cache in the ServiceManager
                    ServiceManager.initServiceCache(services);
                }
    
                setCoreSettings(coreSettings);
    
                AppBindData data = new AppBindData();
                data.processName = processName;
                data.appInfo = appInfo;
                data.providers = providers;
                data.instrumentationName = instrumentationName;
                data.instrumentationArgs = instrumentationArgs;
                data.instrumentationWatcher = instrumentationWatcher;
                data.instrumentationUiAutomationConnection = instrumentationUiConnection;
                data.debugMode = debugMode;
                data.enableBinderTracking = enableBinderTracking;
                data.trackAllocation = trackAllocation;
                data.restrictedBackupMode = isRestrictedBackupMode;
                data.persistent = persistent;
                data.config = config;
                data.compatInfo = compatInfo;
                data.initProfilerInfo = profilerInfo;
                data.buildSerial = buildSerial;
                data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
                sendMessage(H.BIND_APPLICATION, data);
            }
            ......
    	}
    

    最后调用了ActivityThread.sendMessage(),sendMessage 发送了一个 Handler 的异步消息,最后被 handleMessage 方法处理
    在这里插入图片描述

    private void handleBindApplication(AppBindData data) {
            ......
            data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
            ......
            final InstrumentationInfo ii;
            // 创建 Instrumentation
            if (data.instrumntationName != null) {
                try {
                    ii = new ApplicationPackageManager(null, getPackageManager())
                            .getInstrumentationInfo(data.instrumentationName, 0);
                } catch (PackageManager.NameNotFoundException e) {
                    throw new RuntimeException(
                            "Unable to find instrumentation info for: " + data.instrumentationName);
                }
    
                // Warn of potential ABI mismatches.
                if (!Objects.equals(data.appInfo.primaryCpuAbi, ii.primaryCpuAbi)
                        || !Objects.equals(data.appInfo.secondaryCpuAbi, ii.secondaryCpuAbi)) {
                    Slog.w(TAG, "Package uses different ABI(s) than its instrumentation: "
                            + "package[" + data.appInfo.packageName + "]: "
                            + data.appInfo.primaryCpuAbi + ", " + data.appInfo.secondaryCpuAbi
                            + " instrumentation[" + ii.packageName + "]: "
                            + ii.primaryCpuAbi + ", " + ii.secondaryCpuAbi);
                }
    
                mInstrumentationPackageName = ii.packageName;
                mInstrumentationAppDir = ii.sourceDir;
                mInstrumentationSplitAppDirs = ii.splitSourceDirs;
                mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);
                mInstrumentedAppDir = data.info.getAppDir();
                mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
                mInstrumentedLibDir = data.info.getLibDir();
            } else {
                ii = null;
            }
    
            .......
            
            try {
                
                app = data.info.makeApplication(data.restrictedBackupMode, null); // 创建 Application 对象
    
                // Propagate autofill compat state
                app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
    
                mInitialApplication = app;
    
                .......
                try {
                    mInstrumentation.onCreate(data.instrumentationArgs);
                }
                catch (Exception e) {
                    throw new RuntimeException(
                        "Exception thrown in onCreate() of "
                        + data.instrumentationName + ": " + e.toString(), e);
                }
                try {
                    mInstrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if (!mInstrumentation.onException(app, e)) {
                        throw new RuntimeException(
                          "Unable to create application " + app.getClass().getName()
                          + ": " + e.toString(), e);
                    }
                }
            } finally {
                if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
                        || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
                    StrictMode.setThreadPolicy(savedPolicy);
                }
            }
    		......
        }
    

    handleBindApplication 方法首先通过反射创建了 Instrumentation 对象,并执行了 init 方法初始化,然后调用 LoadedApk 类的 makeApplication 方法来创建一个 Application 对象,在 LoadedApk 类中会把创建的 Application 对象保存在 mApplication 变量中,并返回这个变量赋值给 ActivityThread 类中的 mInitialApplication 变量
    位置:\frameworks\base\core\java\android\app\LoadedApk.java

    	public Application makeApplication(boolean forceDefaultAppClass,
                Instrumentation instrumentation) {
            // 检查是否已经创建
            if (mApplication != null) {
                return mApplication;
            }
    
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
    
            Application app = null;
    		// 设置 Application 的类名
            String appClass = mApplicationInfo.className;
            if (forceDefaultAppClass || (appClass == null)) {
                appClass = "android.app.Application";
            }
    
            try {
            	// 创建 Application 及其 Context
                java.lang.ClassLoader cl = getClassLoader();
                if (!mPackageName.equals("android")) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                            "initializeJavaContextClassLoader");
                    initializeJavaContextClassLoader();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
                // 1.创建Context
                ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
                // 2.创建 Application
                app = mActivityThread.mInstrumentation.newApplication(
                        cl, appClass, appContext);
                // 3.将两个对象关联起来
                appContext.setOuterContext(app);
            } catch (Exception e) {
                if (!mActivityThread.mInstrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                        "Unable to instantiate application " + appClass
                        + ": " + e.toString(), e);
                }
            }
            // 4.保存创建的Application
            mActivityThread.mAllApplications.add(app);
            mApplication = app;
    
            if (instrumentation != null) {
                try {
                	// 调用 Application 中的 onCreate() 方法
                    instrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if (!instrumentation.onException(app, e)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                            + ": " + e.toString(), e);
                    }
                }
            }
    
            .......
            return app;
        }
    

    1.首先调用 ContextImpl.createAppContext 静态方法创建 ContextImpl 实例

    2.调用 newApplication 方法并传入 ContextImpl 实例和之前设置的 appClass,来创建该类名对应的一个 Application实例,在 newApplication 方法内部,创建完 Application 实例后,会调用其 attach 方法并传入 ContextImpl 实例,在 attach 方法中又会调用其父类 ContextWrapper(装饰类) 中的 attachBaseContext() 方法,将 ContextImpl 对象设置给内部实例变量 mBase, 这样 Application 内部就持有了Context的实现类ContextImpl实例
    位置:\frameworks\base\core\java\android\app\Instrumentation.java

    	static public Application newApplication(Class<?> clazz, Context context)
                throws InstantiationException, IllegalAccessException, 
                ClassNotFoundException {
            Application app = (Application)clazz.newInstance(); // 创建 Application 类,相当于 new 关键字
            app.attach(context);	// 调用 Application 的 attach 方法
            return app;
        }
    

    位置:\frameworks\base\core\java\android\app\Application.java

        /* package */ final void attach(Context context) {
            attachBaseContext(context); // 直接调用 attachBaseContext 方法,attachBaseContext 方法是在其父类 ContextWrapper 实现的
            mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
        }
    

    位置:\frameworks\base\core\java\android\content\ContextWrapper.java

        protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base; // 将 ContextImpl 对象设置给内部实例变量 mBase
        }
    

    3.最后调用 ContextImpl 的实例方法 setOuterContext,传入这个 Application 实例,这样 ContextImpl 实例也会持有 Context 的包装类 ContextWrapper 实例

    4.创建完一个 Application 对象后,将其保存在 mApplication 实例变量中,由于一个应用程序进程中的 LoadedApk 对象也是一个单例,因此一个进程中只能创建一个 Application 对象。

    Application 得到 Context

    都知道得到 Application 的 Context 是通过 getApplicationContext() 方法获得到的,这个方法是在 Application 的父类 ContextWrapper 中实现的
    在这里插入图片描述

    Activity 创建 Context

    从上面得知,创建 Application 对象是通过 ActivityManagerService 中的 attachApplicationLocked 方法中的 thread.bindApplication 方法去创建并绑定到 AMS 中,在 thread.bindApplication 之后会调用 mStackSupervisor.attachApplicationLocked(app) 方法去启动应用的 Activity,详细见这篇文章:https://blog.csdn.net/weixin_44128558/article/details/132140588 之后经过层层调用会调用到 ActivityThread 中的 performLaunchActivity 方法
    位置:\frameworks\base\core\java\android\app\ActivityThread.java

    	/**  Core implementation of activity launch. */
        private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ......
            
            ContextImpl appContext = createBaseContextForActivity(r); //1.创建 Context
            Activity activity = null;
            try {
                java.lang.ClassLoader cl = appContext.getClassLoader();
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);  // 2.创建一个新的Activity
                StrictMode.incrementExpectedActivityCount(activity.getClass());
                r.intent.setExtrasClassLoader(cl);
                r.intent.prepareToEnterProcess();
                if (r.state != null) {
                    r.state.setClassLoader(cl);
                }
            } 
            
            ......
            
            try {
                ......
    
                if (activity != null) {
                    ......
                    appContext.setOuterContext(activity); //3.将Activity 和 Context 关联起来
                    activity.attach(appContext, this, getInstrumentation(), r.token,	//4.调用attach 将 ContextImpl 对象设置给内部实例变量 mBase
                            r.ident, app, r.intent, r.activityInfo, title, r.parent,
                            r.embeddedID, r.lastNonConfigurationInstances, config,
                            r.referrer, r.voiceInteractor, window, r.configCallback);
    
                    ......
                    if (r.isPersistable()) { // 调用 activity 的 OnCreate 方法
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); 
                    } else {
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
                    ......
                    r.activity = activity;	//5.保存创建的Activity
                }
                ......
            } 
            .......
    
            return activity;
        }
    
    	private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
            ......
    
            ContextImpl appContext = ContextImpl.createActivityContext(
                    this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
    
            ......
            return appContext;
        }
    

    可见,与 Application 创建 Context 流程类似
    1.直接调用 createBaseContextForActivity 方法返回一个 ContextImpl 对象

    	private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
            ......
            ContextImpl appContext = ContextImpl.createActivityContext(
                    this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
    
            ......
            return appContext;
        }
    

    createBaseContextForActivity 方法里调用 ContextImpl.createActivityContext 静态方法创建 ContextImpl 实例并返回
    位置:\frameworks\base\core\java\android\app\ContextImpl.java

    static ContextImpl createActivityContext(ActivityThread mainThread,
                LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
                Configuration overrideConfiguration) {
            ......
            
            ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                    activityToken, null, 0, classLoader);
            
            ......
    
            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;
        }
    

    这里真正创建了 Context

    2. 调用 newActivity 方法并传入 ContextImpl 实例,实际调用的是 AppComponentFactory 的 instantiateActivity() 方法,该方法通过反射方式创建 Activity
    位置:frameworks\base\core\java\android\app\Instrumentation.java

    	public Activity newActivity(ClassLoader cl, String className,
                Intent intent)
                throws InstantiationException, IllegalAccessException,
                ClassNotFoundException {
            String pkg = intent != null && intent.getComponent() != null
                    ? intent.getComponent().getPackageName() : null;
            return getFactory(pkg).instantiateActivity(cl, className, intent);
        }
    

    位置:frameworks\base\core\java\android\app\AppComponentFactory.java

    	public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
                @Nullable Intent intent)
                throws InstantiationException, IllegalAccessException, ClassNotFoundException {
            return (Activity) cl.loadClass(className).newInstance();
        }
    

    3. 与 Application 相同,调用 ContextImpl 的实例方法 setOuterContext,传入这个 Activity 实例,这样 ContextImpl 实例也会持有 Context 的包装类 ContextWrapper 实例

    4. 再调用 Activity 的 attach ,也 Application 类似,该方法中会调用其父类 ContextWrapper 中的 attachBaseContext 方法,将 ContextImpl 对象设置给内部实例变量 mBase
    位置:\frameworks\base\core\java\android\app\Activity.java

    	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,
                Window window, ActivityConfigCallback activityConfigCallback) {
            attachBaseContext(context); // 将 ContextImpl 对象设置给内部实例变量 mBase
    
            mFragments.attachHost(null /*parent*/);
    
            mWindow = new PhoneWindow(this, window, activityConfigCallback);  //创建 PhoneWindow 应用程序的窗口
            mWindow.setWindowControllerCallback(this);
            mWindow.setCallback(this);				// 设置回调接口,有关屏幕事件回调
            mWindow.setOnWindowDismissedCallback(this);
            mWindow.getLayoutInflater().setPrivateFactory(this);
            if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
                mWindow.setSoftInputMode(info.softInputMode);
            }
            if (info.uiOptions != 0) {
                mWindow.setUiOptions(info.uiOptions);
            }
            mUiThread = Thread.currentThread();		//创建刷新ui的线程
    
           ......
    
            mWindow.setWindowManager(
                    (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                    mToken, mComponent.flattenToString(),
                    (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
            if (mParent != null) {
                mWindow.setContainer(mParent.getWindow());
            }
            mWindowManager = mWindow.getWindowManager(); // 得到 WindowManager 并赋给 mWindowManager 成员变量,这样 Activity 可以通过 getWindowManager 方法来获得 WindowManager
            mCurrentConfig = config;
    
            mWindow.setColorMode(info.colorMode);
    
            setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
            enableAutofillCompatibilityIfNeeded();
        }
    
    	@Override
        protected void attachBaseContext(Context newBase) {
            super.attachBaseContext(newBase);
            if (newBase != null) {
                newBase.setAutofillClient(this);
            }
        }
    
    

    首先调用 attachBaseContext 方法,attachBaseContext 方法中又直接调用其父类 (ContextThemeWrapper) 的 attachBaseContext 方法
    在这里插入图片描述
    ContextThemeWrapper 又会调用其父类 (ContextThemeWrapper) 的 attachBaseContext 方法,将 ContextImpl 对象设置给内部实例变量 mBase (与上面 Application 相同)

    之后会创建 PhoneWindow ,PhoneWindow 会接受很多事件,比如点击,菜单弹出,屏幕焦点变化等,这些都会转发给与 PhoneWindow 关联的 Activity,通过 Window.Callback 回调接口实现,当前的 Activity 通过 Window 的 setCallback 方法 传递给 PhoneWindow

    5.创建完一个 Activity 对象后,将其保存在 mApplication 实例变量中

    Service 创建 Context

    Service 的 Context创建过程与 Activity 的 Context 创建过程类似,是在 Service 的启动过程中被创建,Service 是通过 ActiviytThread 的内部类 ApplicationThread 调用 scheduleCreateService 方法来启动
    在这里插入图片描述
    与 Activity 类似,最后将创建的 ContextImpl 一路传递到 Context

  • 相关阅读:
    幻兽帕鲁(Palworld 1.4.1)私有服务器搭建(docker版)
    Docker基本使用
    QCI利用量子计算为飞行汽车提供优化飞行路径和改进设计的功能
    [声明]这篇书评不是我们的反串炒作
    简单来说,无人机单片机是如何控制电机的?
    值传递和引用传递详解
    神经网络照片解读下载,神经网络识别图像原理
    渐变圆角边框css
    【Java03】Java中数组在内存中的机制
    ES 11 新特性
  • 原文地址:https://blog.csdn.net/weixin_44128558/article/details/136196459