Android元件管理框架:Android應用上下文Context

蘇策發表於2018-02-26

關於作者

郭孝星,程式設計師,吉他手,主要從事Android平臺基礎架構方面的工作,歡迎交流技術方面的問題,可以去我的Github提issue或者發郵件至guoxiaoxingse@163.com與我交流。

第一次閱覽本系列文章,請參見導讀,更多文章請參見文章目錄

文章目錄

  • 一 Context與四大元件的關係
    • 1.1 Activity的建立流程
    • 1.2 Service的建立流程
    • 1.3 靜態廣播的建立流程
    • 1.4 Content Provider的建立流程
    • 1.5 Application的建立流程
  • 二 Context的建立流程
    • 2.1 Activity Context的建立流程
    • 2.2 Service Context的建立流程
    • 2.3 靜態廣播 Context的建立流程
    • 2.4 Content Provider Context的建立流程
    • 2.5 Application Context的建立流程
  • 三 Context的繫結流程
    • 3.1 Activity與Context的繫結流程
    • 3.2 Service與Context的繫結流程
    • 3.3 靜態廣播與Context的繫結流程
    • 3.4 Content Provider與Context的繫結流程
    • 3.5 Application與Context的繫結流程

提到Context大家並不陌生,它是Android裡的一個上帝類,啟動四大元件、獲取資源、獲取類載入器等重要功能都通過Context 來完成,Activity、Service與Application也都派生自Context,Broadcast Receiver與Content Provider與Context 也有著密切的聯絡。

Context類圖如下所示:

Android元件管理框架:Android應用上下文Context

可以發現Context是個抽象類,它的具體實現類是ContextImpl,ContextWrapper是個包裝類,內部的成員變數mBase指向的也是個ContextImpl物件,ContextImpl完成了 實際的功能,Activity、Service與Application都直接或者間接的繼承ContextWrapper。

我們知道Context表示的應用的上下文環境,四大元件都與Context有密切的關係,在建立元件的時候會同時建立Context,並將兩者進行繫結,我們來看看四大元件與 Context之間的關係。

一 Context與四大元件的關係

1.1 Activity的建立流程

public final class ActivityThread {
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
    
            ActivityInfo aInfo = r.activityInfo;
            // 1. 獲取LoadedApk物件。
            if (r.packageInfo == null) {
                r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                        Context.CONTEXT_INCLUDE_CODE);
            }
    
            ComponentName component = r.intent.getComponent();
            if (component == null) {
                component = r.intent.resolveActivity(
                    mInitialApplication.getPackageManager());
                r.intent.setComponent(component);
            }
    
            if (r.activityInfo.targetActivity != null) {
                component = new ComponentName(r.activityInfo.packageName,
                        r.activityInfo.targetActivity);
            }
    
            // 2. 建立Activity物件。
            Activity activity = null;
            try {
                java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
                StrictMode.incrementExpectedActivityCount(activity.getClass());
                r.intent.setExtrasClassLoader(cl);
                r.intent.prepareToEnterProcess();
                if (r.state != null) {
                    r.state.setClassLoader(cl);
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            try {
                // 3. 建立Application物件。
                Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    
                // ...log
                
                if (activity != null) {
                    // 4. 建立ContextImpl物件。
                    Context appContext = createBaseContextForActivity(r, activity);
                    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                    Configuration config = new Configuration(mCompatConfiguration);
                    if (r.overrideConfig != null) {
                        config.updateFrom(r.overrideConfig);
                    }
                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                            + r.activityInfo.name + " with config " + config);
                    Window window = null;
                    if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                        window = r.mPendingRemoveWindow;
                        r.mPendingRemoveWindow = null;
                        r.mPendingRemoveWindowManager = null;
                    }
                    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, window);
    
                    if (customIntent != null) {
                        activity.mIntent = customIntent;
                    }
                    r.lastNonConfigurationInstances = null;
                    activity.mStartedActivity = false;
                    int theme = r.activityInfo.getThemeResource();
                    if (theme != 0) {
                        activity.setTheme(theme);
                    }
    
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        // 5. 執行Activity的onCreate()回撥方法。
                        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onCreate()");
                    }
                    r.activity = activity;
                    r.stopped = true;
                    if (!r.activity.mFinished) {
                        activity.performStart();
                        r.stopped = false;
                    }
                    if (!r.activity.mFinished) {
                        if (r.isPersistable()) {
                            if (r.state != null || r.persistentState != null) {
                                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                        r.persistentState);
                            }
                        } else if (r.state != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                        }
                    }
                    if (!r.activity.mFinished) {
                        activity.mCalled = false;
                        if (r.isPersistable()) {
                            mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                    r.persistentState);
                        } else {
                            mInstrumentation.callActivityOnPostCreate(activity, r.state);
                        }
                        if (!activity.mCalled) {
                            throw new SuperNotCalledException(
                                "Activity " + r.intent.getComponent().toShortString() +
                                " did not call through to super.onPostCreate()");
                        }
                    }
                }
                r.paused = true;
    
                mActivities.put(r.token, r);
    
            } catch (SuperNotCalledException e) {
                throw e;
    
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to start activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            return activity;
        }
}
複製程式碼

Activity的建立流程如下所示:

  1. 獲取LoadedApk物件。
  2. 建立Activity物件。
  3. 建立Application物件。
  4. 建立ContextImpl物件。
  5. 執行Activity的onCreate()回撥方法。

1.2 Service的建立流程

public final class ActivityThread {
    
    private void handleCreateService(CreateServiceData data) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();
    
            // 1. 獲取LoadedApk物件。
            LoadedApk packageInfo = getPackageInfoNoCheck(
                    data.info.applicationInfo, data.compatInfo);
            Service service = null;
            try {
                // 2. 建立Service物件。
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                service = (Service) cl.loadClass(data.info.name).newInstance();
            } catch (Exception e) {
                if (!mInstrumentation.onException(service, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate service " + data.info.name
                        + ": " + e.toString(), e);
                }
            }
    
            try {
                if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
                // 3. 建立ContextImpl物件。
                ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                context.setOuterContext(service);
    
                // 4. 建立Application物件。
                Application app = packageInfo.makeApplication(false, mInstrumentation);
                service.attach(context, this, data.info.name, data.token, app,
                        ActivityManagerNative.getDefault());
                // 5. 執行Service的onCreate()回撥方法。
                service.onCreate();
                mServices.put(data.token, service);
                try {
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(service, e)) {
                    throw new RuntimeException(
                        "Unable to create service " + data.info.name
                        + ": " + e.toString(), e);
                }
            }
        }
}
複製程式碼

Service的建立流程如下所示:

  1. 獲取LoadedApk物件。
  2. 建立Service物件。
  3. 建立ContextImpl物件。
  4. 建立Application物件。
  5. 執行Service的onCreate()回撥方法。

1.3 靜態廣播的建立流程

public final class ActivityThread {
    
    private void handleReceiver(ReceiverData data) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();
    
            String component = data.intent.getComponent().getClassName();
            // 1. 獲取LoadedApk物件。
            LoadedApk packageInfo = getPackageInfoNoCheck(
                    data.info.applicationInfo, data.compatInfo);
    
            IActivityManager mgr = ActivityManagerNative.getDefault();
    
            BroadcastReceiver receiver;
            try {
                // 2. 建立BroadcastReceiver物件。
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                data.intent.setExtrasClassLoader(cl);
                data.intent.prepareToEnterProcess();
                data.setExtrasClassLoader(cl);
                receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
            } catch (Exception e) {
                // ...log
            }
    
            try {
                // 3. 建立Application物件。
                Application app = packageInfo.makeApplication(false, mInstrumentation);
    
                // ...log
    
                // 4. 獲取ContextImpl物件。
                ContextImpl context = (ContextImpl)app.getBaseContext();
                sCurrentBroadcastIntent.set(data.intent);
                receiver.setPendingResult(data);
                // 5. 回撥onReceive()方法。
                receiver.onReceive(context.getReceiverRestrictedContext(),
                        data.intent);
            } catch (Exception e) {
                // ...log
            } finally {
                sCurrentBroadcastIntent.set(null);
            }
    
            if (receiver.getPendingResult() != null) {
                data.finish();
            }
        }   
}
複製程式碼

靜態廣播的建立流程如下所示:

  1. 獲取LoadedApk物件。
  2. 建立BroadcastReceiver物件。
  3. 建立Application物件。
  4. 獲取ContextImpl物件。
  5. 回撥onReceive()方法。

1.4 Content Provider的建立流程

public final class ActivityThread {
    
     private IActivityManager.ContentProviderHolder installProvider(Context context,
                IActivityManager.ContentProviderHolder holder, ProviderInfo info,
                boolean noisy, boolean noReleaseNeeded, boolean stable) {
            ContentProvider localProvider = null;
            IContentProvider provider;
            if (holder == null || holder.provider == null) {
                if (DEBUG_PROVIDER || noisy) {
                    Slog.d(TAG, "Loading provider " + info.authority + ": "
                            + info.name);
                }
                Context c = null;
                ApplicationInfo ai = info.applicationInfo;
                if (context.getPackageName().equals(ai.packageName)) {
                    c = context;
                } else if (mInitialApplication != null &&
                        mInitialApplication.getPackageName().equals(ai.packageName)) {
                    c = mInitialApplication;
                } else {
                    try {
                        // 1. 建立ContextImpl物件。
                        c = context.createPackageContext(ai.packageName,
                                Context.CONTEXT_INCLUDE_CODE);
                    } catch (PackageManager.NameNotFoundException e) {
                        // Ignore
                    }
                }
                if (c == null) {
                    // ...log
                    return null;
                }
                try {
                    // 2. 建立Content Provider物件。
                    final java.lang.ClassLoader cl = c.getClassLoader();
                    localProvider = (ContentProvider)cl.
                        loadClass(info.name).newInstance();
                    provider = localProvider.getIContentProvider();
                    if (provider == null) {
                        // ...log
                        return null;
                    }
                    if (DEBUG_PROVIDER) Slog.v(
                        TAG, "Instantiating local provider " + info.name);
                    // 3. 將ContextImpl物件繫結到Content Provider。
                    localProvider.attachInfo(c, info);
                } catch (java.lang.Exception e) {
                    // ...log
                    return null;
                }
            } else {
                provider = holder.provider;
                if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
                        + info.name);
            }
    
            IActivityManager.ContentProviderHolder retHolder;
    
            synchronized (mProviderMap) {
                if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
                        + " / " + info.name);
                IBinder jBinder = provider.asBinder();
                if (localProvider != null) {
                    ComponentName cname = new ComponentName(info.packageName, info.name);
                    ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                    if (pr != null) {
                        // ...log
                        provider = pr.mProvider;
                    } else {
                        holder = new IActivityManager.ContentProviderHolder(info);
                        holder.provider = provider;
                        holder.noReleaseNeeded = true;
                        pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                        mLocalProviders.put(jBinder, pr);
                        mLocalProvidersByName.put(cname, pr);
                    }
                    retHolder = pr.mHolder;
                } else {
                    ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
                    if (prc != null) {
                        // ...log
                        if (!noReleaseNeeded) {
                            incProviderRefLocked(prc, stable);
                            try {
                                ActivityManagerNative.getDefault().removeContentProvider(
                                        holder.connection, stable);
                            } catch (RemoteException e) {
                                //do nothing content provider object is dead any way
                            }
                        }
                    } else {
                        ProviderClientRecord client = installProviderAuthoritiesLocked(
                                provider, localProvider, holder);
                        if (noReleaseNeeded) {
                            prc = new ProviderRefCount(holder, client, 1000, 1000);
                        } else {
                            prc = stable
                                    ? new ProviderRefCount(holder, client, 1, 0)
                                    : new ProviderRefCount(holder, client, 0, 1);
                        }
                        mProviderRefCountMap.put(jBinder, prc);
                    }
                    retHolder = prc.holder;
                }
            }
    
            return retHolder;
        }
}
複製程式碼
  1. 建立ContextImpl物件。
  2. 建立Content Provider物件。
  3. 將ContextImpl物件繫結到Content Provider。

通過上面的分析我們知道在四大元件建立的過程中,都需要建立ContextImpl物件與Application物件,Application物件都是通過LoadedApk的makeApplication()方法來完成的,但 是ContextImpl物件的建立方法卻各不相同,我們來看一看。

1.5 Application的建立流程

通過上述內容可以發現,對於四大元件,Application的建立和獲取方式也是不盡相同的,具體說來:

  • Activity:通過LoadedApk的makeApplication()方法建立。
  • Service:通過LoadedApk的makeApplication()方法建立。
  • 靜態廣播:通過其回撥方法onReceive()方法的第一個引數指向Application。
  • ContentProvider:無法獲取Application,因此此時Application不一定已經初始化。

LoadedApk的makeApplication()方法如下所示:

public final class LoadedApk {
    
       public Application makeApplication(boolean forceDefaultAppClass,
                Instrumentation instrumentation) {
            // Application只會建立一次,如果Application物件已經存在則不再建立,一個APK對應一個
            // LoadedApk物件,一個LoadedApk物件對應一個Application物件。
            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";
            }
    
            try {
                // 1. 建立載入Application的ClassLoader物件。
                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);
                }
                // 2. 建立ContextImpl物件。
                ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
                // 3. 建立Application物件。
                app = mActivityThread.mInstrumentation.newApplication(
                        cl, appClass, appContext);
                // 4. 將Application物件設定給ContextImpl。
                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);
                }
            }
            // 5. 將Application物件新增到ActivityThread的Application列表中。
            mActivityThread.mAllApplications.add(app);
            mApplication = app;
    
            if (instrumentation != null) {
                try {
                    // 6. 執行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);
                    }
                }
            }
    
            // Rewrite the R 'constants' for all library apks.
            SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
                    .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);
            }
    
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    
            return app;
        }
}
複製程式碼

Application的建立流程如下所示:

  1. 建立載入Application的ClassLoader物件。
  2. 建立ContextImpl物件。
  3. 建立Application物件。
  4. 將Application物件設定給ContextImpl。
  5. 將Application物件新增到ActivityThread的Application列表中。
  6. 執行Application的回撥方法onCreate()。

? 注:Application只會建立一次,如果Application物件已經存在則不再建立,一個APK對應一個LoadedApk物件,一個LoadedApk物件 對應一個Application物件。

Application物件的構建時通過Instrumentation的newApplication()方法完成的。

public class Instrumentation {
   static public Application newApplication(Class<?> clazz, Context context)
           throws InstantiationException, IllegalAccessException, 
           ClassNotFoundException {
       Application app = (Application)clazz.newInstance();
       app.attach(context);
       return app;
   } 
}
複製程式碼

這裡我們再注意一下ContextImpl的setOuterContext()方法,它用來設定外部Context,但是不同場景下設定的物件不同,具體說來:

  • makeApplication():Outer Context設定的是Application。
  • createBaseContextForActivity():Outer Context設定的是Activity。
  • handleCreateService():Outer Context設定的是Service。
  • BroadcastReceiver/Provider:Outer Context設定的是預設的ContextImpl。

二 Context的建立流程

前面說過四大元件獲取ContextImpl物件的方式是各不相同的,具體說來:

  • Activity:ContextImpl的createActivityContext()方法。
  • Service:ContextImpl的createAppContext()方法。
  • 靜態廣播:ContextImpl的getBaseContext()方法。
  • Content Provider:ContextImpl的createPackageContext()方法。

我們分別來看看。

2.1 Activity Context的建立流程

Activity Context的建立是通過createBaseContextForActivity()方法來完成,如下所示:

public final class ActivityThread {
    
     private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
            int displayId = Display.DEFAULT_DISPLAY;
            try {
                displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
    
            // 1. 建立ContextImpl物件。
            ContextImpl appContext = ContextImpl.createActivityContext(
                    this, r.packageInfo, r.token, displayId, r.overrideConfig);
            // 2. 設定Outer Context。
            appContext.setOuterContext(activity);
            // 3. 設定Base Context。
            Context baseContext = appContext;
    
            final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
            // ... debug code
            return baseContext;
        }
}
複製程式碼
  1. 建立ContextImpl物件。
  2. 設定Outer Context。
  3. 設定Base Context。

ContextImpl物件的構建其實就是將ActivityThread、LoadedApk、activityToke、displayId、Configuration等重要資訊 傳遞給ContextImpl,這樣ContextImpl就擁有了一個應用的所有資訊,具體如下所示:

class ContextImpl extends Context {
    
     static ContextImpl createActivityContext(ActivityThread mainThread,
               LoadedApk packageInfo, IBinder activityToken, int displayId,
               Configuration overrideConfiguration) {
           if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
           return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
                   null, overrideConfiguration, displayId);
       } 
}
複製程式碼

2.2 Service Context的建立流程

建立Service Context,建立Service的時候用的就是這個方法來建立ContextImpl物件。

class ContextImpl extends Context {
    
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        return new ContextImpl(null, mainThread,
                packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
    }
}
複製程式碼

可以發現Activity Context在構建的時候比Service Context多傳了activityToken和overrideConfiguration物件。

2.3 靜態廣播 Context的建立流程

class ContextWraper extends Context {
   public Context getBaseContext() {
        return mBase;
    }
}
複製程式碼

這個mBase指向的也是ContextImpl物件,它是在構造ContextWraper物件的時候傳遞進來的。這個ContextImpl物件實際上是Activity或者 Service的ContextImpl物件,下面我們會具體講。

2.4 Content Provider Context的建立流程

建立Content Provider Context。

class ContextImpl extends Context {
       @Override
       public Context createPackageContext(String packageName, int flags)
               throws NameNotFoundException {
           return createPackageContextAsUser(packageName, flags,
                   mUser != null ? mUser : Process.myUserHandle());
       }
   
       @Override
       public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
               throws NameNotFoundException {
           if (packageName.equals("system") || packageName.equals("android")) {
               return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
                       user, flags, mDisplay, null, Display.INVALID_DISPLAY);
           }
   
           // 1. 獲取LoadedApk物件。
           LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                   flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
           if (pi != null) {
               // 2. 構造ContextImpl物件。
               ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
                       user, flags, mDisplay, null, Display.INVALID_DISPLAY);
               if (c.mResources != null) {
                   return c;
               }
           }
   
           // Should be a better exception.
           throw new PackageManager.NameNotFoundException(
                   "Application package " + packageName + " not found");
       } 
}
複製程式碼

Content Provider Context在構建的時候多傳了一個UserHandle物件,該物件用來描述當前裝置的使用者資訊。

2.5 Application Context的建立流程

建立Application Context。

class ContextImpl extends Context {
    
    static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        return new ContextImpl(null, mainThread,
                packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
    }
}
複製程式碼

Application Context與Service Context的建立都是呼叫createAppContext()方法。

可以發現,除了靜態廣播直接呼叫getBaseContext()獲取ContextImpl物件以外,其他的都是通過ContextImpl的構造方法來構建ContextImpl物件,如下所示:

class ContextImpl extends Context {
    
     private ContextImpl(ContextImpl container, ActivityThread mainThread,
                LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
                Display display, Configuration overrideConfiguration, int createDisplayWithId) {
            mOuterContext = this;
    
            // 1. 建立預設的應用目錄/data/data/packageName。
            if ((flags & (Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE
                    | Context.CONTEXT_DEVICE_PROTECTED_STORAGE)) == 0) {
                final File dataDir = packageInfo.getDataDirFile();
                if (Objects.equals(dataDir, packageInfo.getCredentialProtectedDataDirFile())) {
                    flags |= Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
                } else if (Objects.equals(dataDir, packageInfo.getDeviceProtectedDataDirFile())) {
                    flags |= Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
                }
            }
    
            // 2. 複製mMainThread、mActivityToken、mPackageInfo、mResourcesManager等重要成員變數。
            mMainThread = mainThread;
            mActivityToken = activityToken;
            mFlags = flags;
    
            if (user == null) {
                user = Process.myUserHandle();
            }
            mUser = user;
    
            mPackageInfo = packageInfo;
            mResourcesManager = ResourcesManager.getInstance();
    
            final int displayId = (createDisplayWithId != Display.INVALID_DISPLAY)
                    ? createDisplayWithId
                    : (display != null) ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
    
            CompatibilityInfo compatInfo = null;
            if (container != null) {
                compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
            }
            if (compatInfo == null) {
                compatInfo = (displayId == Display.DEFAULT_DISPLAY)
                        ? packageInfo.getCompatibilityInfo()
                        : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
            }
    
            // 3. 構建Resouces物件。
            Resources resources = packageInfo.getResources(mainThread);
            if (resources != null) {
                if (displayId != Display.DEFAULT_DISPLAY
                        || overrideConfiguration != null
                        || (compatInfo != null && compatInfo.applicationScale
                                != resources.getCompatibilityInfo().applicationScale)) {
    
                    if (container != null) {
                        // This is a nested Context, so it can't be a base Activity context.
                        // Just create a regular Resources object associated with the Activity.
                        resources = mResourcesManager.getResources(
                                activityToken,
                                packageInfo.getResDir(),
                                packageInfo.getSplitResDirs(),
                                packageInfo.getOverlayDirs(),
                                packageInfo.getApplicationInfo().sharedLibraryFiles,
                                displayId,
                                overrideConfiguration,
                                compatInfo,
                                packageInfo.getClassLoader());
                    } else {
                        // This is not a nested Context, so it must be the root Activity context.
                        // All other nested Contexts will inherit the configuration set here.
                        resources = mResourcesManager.createBaseActivityResources(
                                activityToken,
                                packageInfo.getResDir(),
                                packageInfo.getSplitResDirs(),
                                packageInfo.getOverlayDirs(),
                                packageInfo.getApplicationInfo().sharedLibraryFiles,
                                displayId,
                                overrideConfiguration,
                                compatInfo,
                                packageInfo.getClassLoader());
                    }
                }
            }
            mResources = resources;
    
            // 4. 建立Display物件。
            mDisplay = (createDisplayWithId == Display.INVALID_DISPLAY) ? display
                    : mResourcesManager.getAdjustedDisplay(displayId, mResources.getDisplayAdjustments());
    
            if (container != null) {
                mBasePackageName = container.mBasePackageName;
                mOpPackageName = container.mOpPackageName;
            } else {
                mBasePackageName = packageInfo.mPackageName;
                ApplicationInfo ainfo = packageInfo.getApplicationInfo();
                if (ainfo.uid == Process.SYSTEM_UID && ainfo.uid != Process.myUid()) {
                    // Special case: system components allow themselves to be loaded in to other
                    // processes.  For purposes of app ops, we must then consider the context as
                    // belonging to the package of this process, not the system itself, otherwise
                    // the package+uid verifications in app ops will fail.
                    mOpPackageName = ActivityThread.currentPackageName();
                } else {
                    mOpPackageName = mBasePackageName;
                }
            }
    
            // 5. 建立ContentResolver物件。
            mContentResolver = new ApplicationContentResolver(this, mainThread, user);
        }
}
複製程式碼

我們首先來看看這個建構函式的引數,如下所示:

  • ContextImpl container:容器Context,一般置為null。
  • ActivityThread mainThread:主執行緒ActivityThread。
  • LoadedApk packageInfo:解析後的APK物件。
  • IBinder activityToken:Activity Token用來和ActivityManagerService通訊。
  • UserHandle user:使用者資訊,一般置為null。
  • int flags:Context標誌位。
  • Display display:Display物件,描述螢幕相關資訊。
  • Configuration overrideConfiguration:應用配置資訊。
  • int createDisplayWithId:Display Id。

ContextImpl物件的構建流程如下所示:

  1. 建立預設的應用目錄/data/data/packageName。
  2. 複製mMainThread、mActivityToken、mPackageInfo、mResourcesManager等重要成員變數。
  3. 構建Resouces物件。
  4. 建立Display物件。

理解完Context的建立流程,我們再來看看它是如何和元件進行繫結的。

三 Context的繫結流程

3.1 Activity與Context的繫結流程

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {
    
        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);
            // ...
        }
}
複製程式碼

呼叫ContextWrapper的attachBaseContext()方法將ContextImpl物件賦值給ContextWrapper的成員變數mBase.

3.2 Service與Context的繫結流程

public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
    
        public final void attach(
                Context context,
                ActivityThread thread, String className, IBinder token,
                Application application, Object activityManager) {
            attachBaseContext(context);
            mThread = thread;           // NOTE:  unused - remove?
            mClassName = className;
            mToken = token;
            mApplication = application;
            mActivityManager = (IActivityManager)activityManager;
            mStartCompatibility = getApplicationInfo().targetSdkVersion
                    < Build.VERSION_CODES.ECLAIR;
        }
}
複製程式碼

呼叫ContextWrapper的attachBaseContext()方法將ContextImpl物件賦值給ContextWrapper的成員變數mBase.

3.3 靜態廣播與Context的繫結流程

靜態廣播與Context的繫結與其他元件不同,它是在執行自己onReceive()方法時,通過ContextImpl物件的getReceiverRestrictedContext() 獲取到自己的Context,在傳遞給呼叫者,如下所示:

receiver.onReceive(context.getReceiverRestrictedContext(),
            data.intent);
複製程式碼

上述方法呼叫ContextImpl的getReceiverRestrictedContext()方法構建了一個ReceiverRestrictedContext物件,ReceiverRestrictedContext 是ContextImpl的內部類,繼承於ContextWrapper,定義了註冊廣播等的一些操作。

class ContextImpl extends Context {
      final Context getReceiverRestrictedContext() {
          if (mReceiverRestrictedContext != null) {
              return mReceiverRestrictedContext;
          }
          return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
      }  
}
複製程式碼

3.4 Content Provider與Context的繫結流程

public abstract class ContentProvider implements ComponentCallbacks2 {
    
    private void attachInfo(Context context, ProviderInfo info, boolean testing) {
        mNoPerms = testing;

        /*
         * Only allow it to be set once, so after the content service gives
         * this to us clients can't change it.
         */
        if (mContext == null) {
            // 1. 將建立的ContextImpl賦值賦值給Content Provider成員變數mContent。
            mContext = context;
            if (context != null) {
                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
                        Context.APP_OPS_SERVICE);
            }
            mMyUid = Process.myUid();
            if (info != null) {
                setReadPermission(info.readPermission);
                setWritePermission(info.writePermission);
                setPathPermissions(info.pathPermissions);
                mExported = info.exported;
                mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
                setAuthorities(info.authority);
            }
            // 2.執行Content Provider的回撥方法onCreate()。
            ContentProvider.this.onCreate();
        }
    }
}
複製程式碼

ContentProvider與Context的繫結就是將建立的ContextImpl賦值賦值給Content Provider成員變數mContent。

3.5 Application與Context的繫結流程

Application也有一個與ContextImpl物件繫結的過程,如下所示:

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
}
複製程式碼

繫結的過程也是呼叫ContextWrapper的attachBaseContext()方法將ContextImpl物件賦值給ContextWrapper的成員變數mBase.

相關文章