Android goes deep into four components (7) Android 8.0 Root Activity Startup Process (later)

Posted by HSKrustofsky on Sat, 18 May 2019 07:02:46 +0200

Related articles
Android goes deep into four major component series
Android System Startup Series
Android application process series
Android in-depth analysis of AMS series

Preface

I wrote it a few months ago. Android goes deep into four components (1) Application startup process (previous part) and Android goes deep into four components (1) Application startup process (later) Both articles are based on Android 7.0. When I started reading the Android 8.0 source code, I found that the application (root activity) startup process had some changes according to Android 7.0, so I wrote this article. This article not only changed the process, but also added some analysis, which is an upgraded version. Due to the length of the article, Android 8.0 Activity startup process is still divided into the front and the back to explain.

1. ActivityThread starts the Activity process

Through the previous introduction, we know that the current code logic runs in the application process. Let's first look at the sequence diagram of the process in which ActivityThread starts Activity.

We then look at the scheduleLaunchActivity method of ApplicationThread, where ApplicationThread is the internal class of ActivityThread, which runs the instance ActivityThread representing the main thread after the application process is created, which manages the threads of the current application process. The scheduleLaunchActivity method of ApplicationThread is shown below.

frameworks/base/core/java/android/app/ActivityThread.java

        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
            updateProcessState(procState, false);
            ActivityClientRecord r = new ActivityClientRecord();
            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            ...
            updatePendingConfiguration(curConfig);
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

The scheduleLaunchActivity method encapsulates the parameters that start the Activity into ActivityClientRecord. The sendMessage method sends a message of type LAUNCH_ACTIVITY to Class H, and passes the ActivityClientRecord to Class H. The sendMessage method has several overloading methods. The sendMessage method is finally called as follows.
frameworks/base/core/java/android/app/ActivityThread.java

   private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

Here mH refers to H, which is the inner class of ActivityThread and inherits Handler. It is the message management class of the main thread in the application process. The code for H is shown below.

private class H extends Handler {
      public static final int LAUNCH_ACTIVITY         = 100;
      public static final int PAUSE_ACTIVITY          = 101;
...
public void handleMessage(Message msg) {
          if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
          switch (msg.what) {
              case LAUNCH_ACTIVITY: {
                  Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                  final ActivityClientRecord r = (ActivityClientRecord) msg.obj;//1
                  r.packageInfo = getPackageInfoNoCheck(
                          r.activityInfo.applicationInfo, r.compatInfo);//2
                  handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");//3
                  Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
              } break;
              case RELAUNCH_ACTIVITY: {
                  Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
                  ActivityClientRecord r = (ActivityClientRecord)msg.obj;
                  handleRelaunchActivity(r);
                  Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
              } break;
            ...
}

Look at the handling of LAUNCH_ACTIVITY in H's handleMessage method and convert the passed member variable obj of msg to ActivityClientRecord at Note 1.
At Note 2, LoadedApk-type objects are obtained through the getPackageInfoNoCheck method and assigned to the member variable packageInfo of ActivityClientRecord. To start an Activity, an application process needs to load the APK to which the Activity belongs, and Loaded Apk is used to describe the loaded APK file.
Call the handleLaunchActivity method at comment 3, as shown below.
frameworks/base/core/java/android/app/ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...
    WindowManagerGlobal.initialize();
    //Start Activity
    Activity a = performLaunchActivity(r, customIntent);//1
    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
        //Set the Activity status to Resume
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);//2
        if (!r.activity.mFinished && r.startsNotResumed) {
            performPauseActivityIfNeeded(r, reason);
            if (r.isPreHoneycomb()) {
                r.state = oldState;
            }
        }
    } else {
        try {
            //Stop Activity Startup
            ActivityManager.getService()
                .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                        Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
}

The performLaunchActivity method at Note 1 is used to start Activity, and the code at Note 2 is used to set the status of Activity to Resume. If the activity is null, AMS is notified to stop starting the activity. To see what the performLaunchActivity method does:
frameworks/base/core/java/android/app/ActivityThread.java

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //Get the ActivityInfo class
        ActivityInfo aInfo = r.activityInfo;//1
        if (r.packageInfo == null) {
        //Get the description class LoadedApk of APK file
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);//2
        }

        ComponentName component = r.intent.getComponent();//3
        ...
        //Create a context to start Activity
        ContextImpl appContext = createBaseContextForActivity(r);//4
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //Create an instance of the Activity with a class loader
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);//5
          ...
        } catch (Exception e) {
          ...
        }

        try {
            //Create Application
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);//6
            ...
            if (activity != null) {
               ...
                /**
                *7 Initialize 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);

               ...
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//8
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
               ...
            }
            r.paused = true;
            mActivities.put(r.token, r);
        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
          ...
        }

        return activity;
    }

Annotation 1 is used to get ActivityInfo, which stores the Activity and Reciver node information set by code and Android Manifes, such as the theme and launchMode of Activity. Get the description class LoadedApk of the APK file at Note 2. Note 3 gets the ComponentName class of Activity to start, and the package name and class name of the activity are stored in the ComponentName class. Note 4 is used to create the context in which Activity is to be started. Note 5 uses the class loader to create an instance of Activity based on the name of the Activity class stored in ComponentName. Note 6 is used to create the Application, and the onCreate method of the Application is called inside the makeApplication method. Note 7 calls the attach method of Activity to initialize Activity, which creates a Windows object (PhoneWindow) and associates it with Activity itself. Note 8 calls Instrumentation's callActivityOnCreate method to start Activity, as shown below.
frameworks/base/core/java/android/app/Instrumentation.java

  public void callActivityOnCreate(Activity activity, Bundle icicle,
            PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);//1
        postPerformCreate(activity);
    }

Note 1 calls Activity's performCreate method, as shown below.
frameworks/base/core/java/android/app/Activity.java

  final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        restoreHasCurrentPermissionRequest(icicle);
        onCreate(icicle, persistentState);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }

The onCreate method of Activity is invoked in the performance Create method, where the root activity is started, that is, the application is started.
So far as the root Activity startup process is concerned, let's learn about the process involved in the root Activity startup process.

2. Processes involved in root Activity startup

When the application process is not created, there are four processes involved in the process of root Activity startup: Zyget process, Launcher process, AMS process (Syetem Server process), and application process. The relationship between them is shown in the following figure.

First, the Launcher process requests AMS to create the root Activity. AMS determines whether the application process required by the root Activity exists and starts, and if it does not exist, requests the Zygote process to create the application process. When the application process is ready, AMS is notified, and AMS requests the application process to create the root Activity. For the four steps of inter-process communication in the figure above, the processes related to step 2 and step 3 adopt Socket communication, and the processes related to step 1 and step 4 adopt Binder communication.
The above figure may not be very intuitive. For a better understanding, the sequence diagrams of these four process calls are given below.

How many processes would be involved in a normal Activity startup process? The answer is two, the process AMS is in and the application process. In fact, it is easy to understand the initiation process of root activity (the onCreate process of root activity). Root activity and other life cycle states of ordinary activity, such as onStart and onResume, can also be easily grasped. These knowledge points are all by-the-way. Students who want to know these knowledge points can read the source code by themselves.

Topics: Android Java Windows socket