The relevant content of the article has been authorized to “Guo Lin” public account published

preface

This article looks at the source flow for context creation. Reading the article requires a certain understanding of the start-up process of the four components. I will briefly introduce important knowledge points and give links to relevant articles in the relevant part.

In the last article Android comprehensive analysis of the Context mechanism (a) : Context cognition explained the Context of the relevant implementation classes. After the previous discussion, the reader has a certain understanding of context in mind. But there is always something missing: when was the activity created, and how was its contextImpl assigned? The Application? Why is the ContextProvider context Application and Broadcast context Activity? How was contextImpl created? To solve these puzzles, you must read the source code. The benefits of reading the source code is very much, my story above, are based on my understanding after reading the source code, and the “one thousand audience has one thousand Hamlet”, read the source code for the whole mechanism can be formed own thinking and understanding, at the same time can make you to really implement the context that knowledge to the code, enhance their confidence for knowledge. When others disagree with you, you can pat your chest and say: I read the source code, this place is such. Are you confident and cocky?

However, reading source code is not the more the better, but to grasp the overall process after reading the key source code, do not go deep into the source code heap unable to extricate themselves. For example, IF I feel that the Activity contextImpl is assigned during the creation of the activity, I will look for the source of the activity launch process and only look at the context. While improving efficiency, we can also get to the point of our study. The following source code reading we give the overall process, and then focus on understanding the key code, other source code readers can download their own source to track reading.

This is the second part of the Context series, which is divided into three parts. The first part is about the context family and related implementation classes. Part 2: The creation process of different contexts, including Application, Activity, and Service. Part 3: The final part, which covers the context origins of the remaining two major components and understanding context from a higher perspective.

Readers can go to the home page to select the sections they are interested in, or to read the entire systematic learning context.

Application

Application An application-level context, which is created when the Application is created, is the first context to be created and the last context to be destroyed. Tracing the creation of an Application therefore starts with the Application startup process. The source code flow for application startup is as follows (simplified version) :

The application starts with the main method of the ActivityThread. The main method starts the Looper and Handler of the thread, and AMS sends a message to the main thread to control the application startup process. So we can target the last method in the diagram: handleBindApplication, where the Application is most likely to be created:

ActivityThread.class (api29)

private void handleBindApplication(AppBindData data) {
. // Create the LoadedApk object
 data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); . Application app; . try {  / / create the Application  app = data.info.makeApplication(data.restrictedBackupMode, null); . }  try { . // Call Application's onCreate method  mInstrumentation.callApplicationOnCreate(app);  } .} Copy the code

AppBindData, the parameter of handleBindApplication, is the startup information given by AMS to the application, which contains the “permission credentials” — ApplicationInfo and so on. LoadedApk uses these objects to create access to system resources, and then uses LoadApk to create ContextImpl and Application.

Here we only focus on creating the logic, and the context initiator’s source code as well as in front of the AMS, how to deal with here do not speak, readers are interested can read ContextProvider start a process, this article of that is just the start process of ContextProvider for tracking, rounding the source code.

So let’s look at how the Application is created:

LoadeApk.class(api29)
public Application makeApplication(boolean forceDefaultAppClass.        Instrumentation instrumentation) {
    // Return if application already exists
    if(mApplication ! =null) {
 return mApplication;  } . Application app = null;  String appClass = mApplicationInfo.className; . try {  java.lang.ClassLoader cl = getClassLoader(); . / / create ContextImpl  ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);  // Use the class loader to load the Application class we specified in AndroidMenifest  app = mActivityThread.mInstrumentation.newApplication(  cl, appClass, appContext);  // Reference the Application to comtextImpl so that contextImpl can easily access the Application  appContext.setOuterContext(app);  } . mActivityThread.mAllApplications.add(app);  / / set the app to mApplication, when we call context. GetApplicationContext is access to the object  mApplication = app;   if(instrumentation ! =null) {  try {  // Call Application's onCreate method  instrumentation.callApplicationOnCreate(app);  } . } . return app; } Copy the code

The logic of the code is not complicated, first check whether the mApplication in the LoadedApk object exists, otherwise create ContextImpl, then use the classloader and ContextImpl to create the Application. Finally, we assign the Application object to LoadedApk’s mApplication and call the onCreate method of Application. Let’s take a look at how contextImpl is created:

ContextImpl.class(api29)
static ContextImpl createAppContext(ActivityThread mainThread.LoadedApk packageInfo.        String opPackageName) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null.null.null.0. null, opPackageName);  context.setResources(packageInfo.getResources());  return context; } Copy the code

ContextImpl = ActivityThread; LoadedApk = ActivityThread; Let’s go back to the Application creation process. We can guess that the logic in newApplication must be to create the Application using reflection and assign contextImpl to the Application. The reason is that everyone’s custom Application class is different, and reflection is used to create the object, and the mBase property in the Application is a reference to ContextImpl. See the source code:

Instrumentation.class(api29)
public Application newApplication(ClassLoader cl.String className.Context context)
        throws InstantiationException.IllegalAccessException.        ClassNotFoundException {
    Application app = getFactory(context.getPackageName())
 .instantiateApplication(cl, className);  app.attach(context);  return app; }  Application.class(api29) final void attach(Context context) {  attachBaseContext(context);  mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; }  ContextWrapper.class(api29) Context mBase; protected void attachBaseContext(Context base) {  if(mBase ! =null) {  throw new IllegalStateException("Base context already set");  }  mBase = base; } Copy the code

The Application object is created and ContextImpl is assigned to the Application using the Attach method of the Application. The Attach method of the Application then calls ContextWrapper’s attachBaseContext method, since the Application also inherits from ContextWrapper. Thus, the ContextImpl is assigned to the Application’s mBase property.

To go back to the previous logic, we need to call the onCreate method after the Application is created:

Instrumentation.class(api29)
public void callApplicationOnCreate(Application app) {
    app.onCreate();
}
Copy the code

Simple and crude, straight back. At this point, the process of creating the Application and creating the context is complete. However, it is important to note that global initialization needs to be done in onCreate, not in the constructor of the Application. From the code we can see that ContextImpl is assigned after the Application is created.

Activity

The context of the Activity is also created during the Activity creation process, which involves the Activity launch process. There are three processes involved: the application requests AMS, AMS processes the request, and the application responds to the Activity to create a transaction:

Again, we will focus on the Activity creation process, which other readers will learn from the Activity launch process article. As with Application, the creation of an Activity is controlled by AMS, which sends messages to the Application process to perform specific startup logic. Finally, the handleLaunchActivity method is executed:

ActivityThread.class(api29)
public Activity handleLaunchActivity(ActivityClientRecord r.        PendingTransactionActions pendingActions.Intent customIntent) {
.    final Activity a = performLaunchActivity(r, customIntent);
. return a; } Copy the code

The final is the middle of this code, enter the source code:

ActivityThread.class(api29)
private Activity performLaunchActivity(ActivityClientRecord r.Intent customIntent) {
. // Create ContextImpl for the Activity
    ContextImpl appContext = createBaseContextForActivity(r);
 Activity activity = null;  try {  // Create an activity instance using class loading  java.lang.ClassLoader cl = appContext.getClassLoader();  activity = mInstrumentation.newActivity(  cl, component.getClassName(), r.intent); . }  try {  / / create the Application  Application app = r.packageInfo.makeApplication(false, mInstrumentation); . if(activity ! =null) { . // Set the activity to the context so that the context can also access the activity  appContext.setOuterContext(activity);  // Call the Attach method of the activity to set the contextImpl to the activity  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, r.configCallback,  r.assistToken);   int theme = r.activityInfo.getThemeResource();  if(theme ! =0) {  // Set the theme  activity.setTheme(theme);  } . // Call back the onCreate method  if (r.isPersistable()) {  mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);  } else {  mInstrumentation.callActivityOnCreate(activity, r.state);  } . } . } . return activity; } Copy the code

The logic of the code is not very complicated. First create the ContextImpl for the Activity, use the class load to create the instance of the Activity, and then create the Application from LoadedApk. If the Application is already created, the created object is returned. Then set the activity to the context so that the context can access the activity as well. Using the Activity context causes memory leaks. Is it possible to use the Activity contextImpl object? The answer is no, because ContextImpl also holds a reference to the Activity, requiring special care. It then calls the Attach method of the activity to set the contextImpl to the activity. We won’t go too far into setting the theme and calling the onCreate method, but will focus on attaching:

Activity.class(api29)
final void attach(Context context,...).{
    attachBaseContext(context);
.}
Copy the code

There’s a lot of code left out, except for the key sentence: attachBaseContext. Familiar? Call ContextWrapper to assign the mBase property, same as Application.

Service

Again focusing on the key code flow, let’s look at the Service startup flowchart:

The creation of a Service is also controlled by AMS. Similarly, when we see the creation of a Service, we end up calling the handleCreateService method:

private void handleCreateService(CreateServiceData data) {
.    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
 try {  java.lang.ClassLoader cl = packageInfo.getClassLoader();  service = packageInfo.getAppFactory()  .instantiateService(cl, data.info.name, data.intent);  } . try { . ContextImpl context = ContextImpl.createAppContext(this, packageInfo);  context.setOuterContext(service);   Application app = packageInfo.makeApplication(false, mInstrumentation);  service.attach(context, this, data.info.name, data.token, app,  ActivityManager.getService());  service.onCreate();  mServices.put(data.token, service); . } .} Copy the code

ContextImpl = mBase; contextImpl = mBase; contextImpl = mBase; The process is similar to the one above, so we won’t go into details here. If you are interested, you can read the source code, or you can read the details of the Android Service startup and binding process (based on api29).

The last

This article explains the startup process of the three context implementation classes, and I believe that there is a more thorough understanding of context through reading the source code. The four components also include broadcasting and content providers, which are covered in the next section due to space limitations.

Full text here, the original is not easy, feel help can like collection comments forward. I have no talent, any ideas welcome to comment area exchange correction. If need to reprint please comment section or private communication.

And welcome to my blog: Portal