About the author
Guo Xiaoxing, programmer and guitarist, is mainly engaged in the infrastructure of Android platform. Welcome to exchange technical questions. You can go to my Github to raise an issue or send an email to [email protected] to communicate with me.
For the first time in this series, see the introduction and the table of contents for more articles.
The article directories
- The relationship between a Context and four components
- 1.1 Activity creation process
- 1.2 Service Creation Process
- 1.3 Static Broadcast Creation Process
- 1.4 Content Provider Creation Process
- 1.5 Application Creation process
- Context Creation process
- 2.1 Process of creating an Activity Context
- 2.2 Service Context Creation Process
- 2.3 Static Broadcast Context Creation Process
- 2.4 Content Provider Context Creation Process
- 2.5 Application Context Creation Process
- Context binding process
- 3.1 Binding process between Activity and Context
- 3.2 Binding process between Service and Context
- 3.3 Binding process of Static Broadcast to Context
- 3.4 Binding Process of Content Provider to Context
- 3.5 Binding process between Application and Context
Context is a god class in Android. You can start four components, get resources, get classloaders and other important functions through Context. Activity, Service, and Application are derived from Context. Broadcast Receivers are also closely related to Content providers and Context.
The Context class diagram is as follows:
ContextImpl, ContextWrapper, ContextImpl, ContextImpl, ContextImpl, ContextImpl, ContextWrapper, ContextImpl, ContextImpl, ContextImpl, ContextImpl Activities, services, and applications all directly or indirectly inherit ContextWrapper.
We know that Context represents the Context of the application. All four components are closely related to the Context. When you create a component, you create the Context at the same time and bind the two.
The relationship between a Context and four components
1.1 Activity creation process
public final class ActivityThread {
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
ActivityInfo aInfo = r.activityInfo;
// 1. Obtain the LoadedApk object.
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. Create Activity objects.
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. Create an Application object.
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
/ /... log
if(activity ! =null) {
// 4. Create ContextImpl object.
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. Execute the Activity's onCreate() callback.
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); }}returnactivity; }}Copy the code
The Activity creation process is as follows:
- Get the LoadedApk object.
- Create an Activity object.
- Create the Application object.
- Create the ContextImpl object.
- Execute the Activity’s onCreate() callback method.
1.2 Service Creation Process
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. Obtain the LoadedApk object.
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
// 2. Create Service objects.
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. Create ContextImpl object.
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
// 4. Create Application object.
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
// 5. Execute the onCreate() callback of Service.
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0.0);
} catch (RemoteException e) {
throwe.rethrowFromSystemServer(); }}catch (Exception e) {
if(! mInstrumentation.onException(service, e)) {throw new RuntimeException(
"Unable to create service " + data.info.name
+ ":"+ e.toString(), e); }}}}Copy the code
The process for creating a Service is as follows:
- Get the LoadedApk object.
- Create a Service object.
- Create the ContextImpl object.
- Create the Application object.
- Execute the onCreate() callback of the Service.
1.3 Static Broadcast Creation Process
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. Obtain the LoadedApk object.
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
IActivityManager mgr = ActivityManagerNative.getDefault();
BroadcastReceiver receiver;
try {
2. Create the BroadcastReceiver object.
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. Create an Application object.
Application app = packageInfo.makeApplication(false, mInstrumentation);
/ /... log
// 4. Get the ContextImpl object.
ContextImpl context = (ContextImpl)app.getBaseContext();
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
// 5. Call back onReceive().
receiver.onReceive(context.getReceiverRestrictedContext(),
data.intent);
} catch (Exception e) {
/ /... log
} finally {
sCurrentBroadcastIntent.set(null);
}
if(receiver.getPendingResult() ! =null) { data.finish(); }}}Copy the code
The static broadcast creation process is as follows:
- Get the LoadedApk object.
- Create the BroadcastReceiver object.
- Create the Application object.
- Gets the ContextImpl object.
- Call back the onReceive() method.
1.4 Content Provider Creation Process
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. Create ContextImpl object.
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
// Ignore}}if (c == null) {
/ /... log
return null;
}
try {
// 2. Create Content Provider objects.
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. Bind ContextImpl object to 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; }}returnretHolder; }}Copy the code
- Create the ContextImpl object.
- Create a Content Provider object.
- Bind the ContextImpl object to the Content Provider.
ContextImpl object and Application object are all created by LoadedApk makeApplication() method. However, the methods used to create the ContextImpl object vary, so let’s take a look.
1.5 Application Creation process
It can be found from the above content that the way of Application creation and acquisition is different for the four components. Specifically speaking:
- Activity: Created from the makeApplication() method of LoadedApk.
- Service: Created by LoadedApk’s makeApplication() method.
- Static broadcast: Points to Application via the first argument of its callback method onReceive().
- ContentProvider: Cannot get the Application, so the Application may not be initialized at this time.
LoadedApk’s makeApplication() method looks like this:
public final class LoadedApk {
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
// The Application object is created only once. If the Application object already exists, it is not created any more
// LoadedApk object, a LoadedApk object corresponds to an Application object.
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. Create a ClassLoader object to load the Application.
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. Create ContextImpl object.
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// 3. Create an Application object.
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
// 4. Set Application object to 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. Add the Application object to the Application list of ActivityThread.
mActivityThread.mAllApplications.add(app);
mApplication = app;
if(instrumentation ! =null) {
try {
// 6. Execute the Application callback 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);
returnapp; }}Copy the code
The Application creation process is as follows:
- Create a ClassLoader object that loads the Application.
- Create the ContextImpl object.
- Create the Application object.
- Set the Application object to ContextImpl.
- Add the Application object to the Application list of the ActivityThread.
- Execute Application’s callback method onCreate().
👉 Note: Application is created only once. If an Application object already exists, it is not created any more. One APK corresponds to one LoadedApk, and one LoadedApk corresponds to one Application object.
Application objects are built using the newApplication() method of Instrumentation.
public class Instrumentation {
static public Application newApplication(Class
clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
returnapp; }}Copy the code
Again, notice the ContextImpl setOuterContext() method, which sets the external Context, but the object is set differently in different scenarios. Specifically:
- MakeApplication () : Outer Context sets Application.
- CreateBaseContextForActivity () : the Outer Context is the Activity.
- HandleCreateService () : Outer Context sets Service.
- BroadcastReceiver/Provider: Outer Context ContextImpl setting is the default.
Context Creation process
As mentioned earlier, each of the four components gets the ContextImpl object differently, specifically:
- Activity: ContextImpl createActivityContext() method.
- Service: ContextImpl createAppContext() method.
- Static broadcast: ContextImpl’s getBaseContext() method.
- Content Provider: ContextImpl createPackageContext() method.
Let’s take a look at each.
2.1 Process of creating an Activity Context
The Activity of the Context is created through createBaseContextForActivity () method to finish, as shown below:
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. Create ContextImpl object.
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
// 2. Set Outer Context.
appContext.setOuterContext(activity);
// 3. Set Base Context.
Context baseContext = appContext;
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// ... debug code
returnbaseContext; }}Copy the code
- Create the ContextImpl object.
- Set Outer Context.
- Set the Base Context.
ContextImpl: ContextImpl: ActivityThread, LoadedApk, activityToke, displayId, Configuration, etc. ContextImpl now has all the information for an application, as shown below:
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); }}Copy the code
2.2 Service Context Creation Process
Create the Service Context. This method is used to create the ContextImpl object when creating the Service.
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); }}Copy the code
You can see that the Activity Context is constructed with more activityToken and overrideConfiguration objects than the Service Context.
2.3 Static Broadcast Context Creation Process
class ContextWraper extends Context {
public Context getBaseContext(a) {
returnmBase; }}Copy the code
This mBase also points to the ContextImpl object, which is passed in when the ContextWraper object is constructed. The ContextImpl object is actually the ContextImpl object for the Activity or Service, as we’ll see below.
2.4 Content Provider Context Creation Process
Create a Content Provider Context.
class ContextImpl extends Context {
@Override
public Context createPackageContext(String packageName, int flags)
throws NameNotFoundException {
returncreatePackageContextAsUser(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. Obtain the LoadedApk object.
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if(pi ! =null) {
// 2. Construct ContextImpl object.
ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
user, flags, mDisplay, null, Display.INVALID_DISPLAY);
if(c.mResources ! =null) {
returnc; }}// Should be a better exception.
throw new PackageManager.NameNotFoundException(
"Application package " + packageName + " not found"); }}Copy the code
When the Content Provider Context is built, it passes a UserHandle object that describes the user information of the current device.
2.5 Application Context Creation Process
Create the 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); }}Copy the code
Both Application Context and Service Context are created by calling createAppContext().
Can be found, in addition to static radio direct call getBaseContext () to obtain ContextImpl objects, the other is through ContextImpl ContextImpl constructor to construct the object, as shown below:
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. Create a default application directory /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; }}Copy important member variables such as mMainThread, mActivityToken, mPackageInfo, and mResourcesManager.
mMainThread = mainThread;
mActivityToken = activityToken;
mFlags = flags;
if (user == null) {
user = Process.myUserHandle();
}
mUser = user;
mPackageInfo = packageInfo;
mResourcesManager = ResourcesManager.getInstance();
final intdisplayId = (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. Build the Resouces object.
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. Create Display objects.
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; }}// create a ContentResolver object.
mContentResolver = new ApplicationContentResolver(this, mainThread, user); }}Copy the code
Let’s first look at the constructor’s arguments, as follows:
- ContextImpl Container: container Context, usually set to null.
- ActivityThread mainThread: indicates the mainThread ActivityThread.
- LoadedApk packageInfo: parsed APK object.
- IBinder activityToken: The Activity Token is used to communicate with ActivityManagerService.
- UserHandle user: indicates the user information. The value is usually null.
- Int flags: indicates the Context flag bit.
- Display Display: displays information about the screen.
- Configuration overrideConfiguration: Application Configuration information.
- Int createDisplayWithId: Display Id.
The construction flow of the ContextImpl object is as follows:
- Create the default application directory /data/data/packageName.
- Copy mMainThread, mActivityToken, mPackageInfo, mResourcesManager and other important member variables.
- Build the Resouces object.
- Create the Display object.
Once you understand the Context creation process, let’s look at how it binds to the component.
Context binding process
3.1 Binding process between Activity and 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);
// ...}}Copy the code
The attachBaseContext() method of ContextWrapper is called to assign the ContextImpl object to the ContextWrapper member variable mBase.
3.2 Binding process between Service and 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; }}Copy the code
The attachBaseContext() method of ContextWrapper is called to assign the ContextImpl object to the ContextWrapper member variable mBase.
3.3 Binding process of Static Broadcast to Context
Static radio and binding of the Context and other components, is it your onReceive () method, through ContextImpl object getReceiverRestrictedContext () to get to their Context, in passing to the caller, as shown below:
receiver.onReceive(context.getReceiverRestrictedContext(),
data.intent);
Copy the code
The above method calls ContextImpl getReceiverRestrictedContext () method to construct a ReceiverRestrictedContext object, ReceiverRestrictedContext is ContextImpl inner classes, inheritance in ContextWrapper, defines some of the registered broadcast operation.
class ContextImpl extends Context {
final Context getReceiverRestrictedContext(a) {
if(mReceiverRestrictedContext ! =null) {
return mReceiverRestrictedContext;
}
return mReceiverRestrictedContext = newReceiverRestrictedContext(getOuterContext()); }}Copy the code
3.4 Binding Process of Content Provider to 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. Assign the created ContextImpl to the Content Provider member variable 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. Execute the Content Provider callback onCreate().
ContentProvider.this.onCreate(); }}}Copy the code
The binding of the ContentProvider to the Context assigns the created ContextImpl to the ContentProvider member variable mContent.
3.5 Binding process between Application and Context
Application also has a procedure for binding to the ContextImpl object, as follows:
public class Application extends ContextWrapper implements ComponentCallbacks2 {
/* package */ final void attach(Context context) { attachBaseContext(context); mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; }}Copy the code
The binding is also done by calling ContextWrapper’s attachBaseContext() method to assign the ContextImpl object to the ContextWrapper member variable mBase.