[Android's Four Components']--Activity's "Start-up Process"

Keywords: Android Java

Core Source (Android 9.0)

Source Path(/packages/apps/Launcher3/)
BaseDraggingActivity.java src/com/android/launcher3/BaseDraggingActivity.java
ItemClickHandler.java src/com/android/launcher3/touch/ItemClickHandler.java
Launcher.java src/com/android/launcher3/Launcher.java
Source Path(/packages/apps/Launcher3/)
Activity.java core/java/android/app/Activity.java
ActivityManager.java core/java/android/app/ActivityManager.java
ActivityThread.java core/java/android/app/ActivityThread.java
ClientTransaction.java core/java/android/app/servertransaction/ClientTransaction.java
ClientTransactionHandler.java core/java/android/app/ClientTransactionHandler.java
Instrumentation.java core/java/android/app/Instrumentation.java
LaunchActivityItem.java core/java/android/app/servertransaction/LaunchActivityItem.java
PauseActivityItem.java core/java/android/app/servertransaction/PauseActivityItem.java
Process.java core/java/android/os/Process.java
TransactionExecutor.java core/java/android/app/servertransaction/TransactionExecutor.java
ActivityManagerService.java services/core/java/com/android/server/am/ActivityManagerService.java
ActivityStack.java services/core/java/com/android/server/am/ActivityStack.java
ActivityStarter.java services/core/java/com/android/server/am/ActivityStarter.java
ActivityStartController.java services/core/java/com/android/server/am/ActivityStartController.java
ActivityStackSupervisor.java services/core/java/com/android/server/am/ActivityStackSupervisor.java
ClientLifecycleManager.java services/core/java/com/android/server/am/ClientLifecycleManager.java

I. Preface

It is our daily behavior to click on the application icon of Launcher interface and run various dazzling and powerful applications. As a system engineer, it is necessary for us to study deeply together. When we click on the APK icon until the main interface of the application is finally displayed, during this period, we start from the source code perspective to the end. What was born and what was the logic of processing?

Personally, this process is very necessary for us to understand deeply. For example, sometimes when we click on the application, we have the phenomenon of "Carton" and "black-and-white screen". Are these problems of the application itself or of the system? When you analyze this kind of problem, if you are not familiar with the start-up process of Activity, it will be hard to analyze, and may not be able to get a thorough analysis of the most fundamental reasons.

Not much nonsense. In order to analyze the source code process more conveniently and carefully, we choose Launcher interface click application as the entry point for analysis (through a specific scenario/operation is the best way to study the source code). Then we go directly to the topic. (Lions, this is also a question many interviewers like to ask.)

Launcher's onPause process

Since we are going to start a new APK in the foreground, the current activity will inevitably be switched to the background, so Launcher's onPause process is the first one involved. Activity's life cycle can be read [Android's Four Components']--Activity's "Life Cycle" One article.

2.1 ItemClickHandler.onClick

When you click on an icon of the application Launcher, the callback interface ItemClickHandler executes the startAppShortcutOrInfoActivity in the onClick() method.

// packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

public View createShortcut(ViewGroup parent, ShortcutInfo info) {
    BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext())
            .inflate(R.layout.app_icon, parent, false);
    favorite.applyFromShortcutInfo(info);
    favorite.setOnClickListener(ItemClickHandler.INSTANCE);
    favorite.setOnFocusChangeListener(mFocusHandler);
    return favorite;
}


// packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java

public class ItemClickHandler {
    public static final OnClickListener INSTANCE = ItemClickHandler::onClick;

    private static void onClick(View v) {
        ... ...
        if (tag instanceof ShortcutInfo) {
            onClickAppShortcut(v, (ShortcutInfo) tag, launcher);
        } else if (tag instanceof FolderInfo) {
            if (v instanceof FolderIcon) {
                onClickFolderIcon(v);
            }
        } else if (tag instanceof AppInfo) {
            // Execute the startAppShortcutOrInfoActivity method
            startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
        } else if (tag instanceof LauncherAppWidgetInfo) {
            if (v instanceof PendingAppWidgetHostView) {
                onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
            }
        }
    }
    ... ...
}

2.2 ItemClickHandler.startAppShortcutOrInfoActivity

// packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java

private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
    Intent intent;
    if (item instanceof PromiseAppInfo) {
        PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
        intent = promiseAppInfo.getMarketIntent(launcher);
    } else {
        intent = item.getIntent();
    }
    if (intent == null) {
        throw new IllegalArgumentException("Input must have a valid intent");
    }
    if (item instanceof ShortcutInfo) {
        ShortcutInfo si = (ShortcutInfo) item;
        if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI)
                && intent.getAction() == Intent.ACTION_VIEW) {
            intent = new Intent(intent);
            intent.setPackage(null);
        }
    }
    // Execute the startActivitySafely method
    launcher.startActivitySafely(v, intent, item);
}

2.3 Launcher.startActivitySafely

The code eventually goes to Launcher's startActivitySafely() method.

// packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
    // Calling the startActivitySafely method of the parent BaseDragging Activity
    boolean success = super.startActivitySafely(v, intent, item);
    if (success && v instanceof BubbleTextView) {
        BubbleTextView btv = (BubbleTextView) v;
        btv.setStayPressed(true);
        setOnResumeCallback(btv);
    }
    return success;    // Represents the Activity success of launching a new application
}

2.4 BaseDraggingActivity.startActivitySafely

// packages/apps/Launcher3/src/com/android/launcher3/BaseDraggingActivity.java

public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
    ... ...
    // Add a flag to indicate that you want to start the Activity in a new Task
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (v != null) {
        intent.setSourceBounds(getViewBounds(v));
    }
    try {
        boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
                                && (item instanceof ShortcutInfo)
                                && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
                                || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                                && !((ShortcutInfo) item).isPromise();
        if (isShortcut) {
            startShortcutIntentSafely(intent, optsBundle, item);
        } else if (user == null || user.equals(Process.myUserHandle())) {
            startActivity(intent, optsBundle);    // Call the Activity.startActivity method
        } else {
            LauncherAppsCompat.getInstance(this).startActivityForProfile(
                    intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
        }
        getUserEventDispatcher().logAppLaunch(v, intent);
        return true;
    } catch (ActivityNotFoundException|SecurityException e) {
        Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
        Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
    }
    return false;
}

2.5 Activity.startActivity

// framework/base/core/java/android/app/Activity.java

public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);    // options represent Launcher's animation when she starts Activity
    } else {
        startActivityForResult(intent, -1);
    }
}

2.6 Activity.startActivityForResult

// framework/base/core/java/android/app/Activity.java

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    // mParent represents the current state of Launcher Activity
    if (mParent == null) {    // Start Activity for the first time, follow this branch
        options = transferSpringboardActivityOptions(options);
        // Execute the mInstrumentation.execStartActivity() method
        Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, 
                        mMainThread.getApplicationThread(), mToken,
                        this, intent, requestCode, options);
        ... ...
    } else {
        if (options != null) {
            // Eventually, the mInstrumentation.execStartActivity() method is called
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}

mMainThread is a member variable of the Activity class. Its type is ActivityThread, which represents the main thread of the application.

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

public final class ActivityThread extends ClientTransactionHandler {
    ... ...
    final ApplicationThread mAppThread = new ApplicationThread();
    ... ...
    private class ApplicationThread extends IApplicationThread.Stub {...}
    ... ...
    public ApplicationThread getApplicationThread()
    {
        return mAppThread;
    }
    ... ...
}

mMainThread.getApplicationThread() gets the internal member variable of ApplicationThread, which is a Binder object. What's this object for? We'll talk about it later.

2.7 Instrumentation.execStartActivity

Instrumentation is a practical operation class that starts Activity in Android system. It is used to monitor the interaction between application and system.

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

public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token,
                        Activity target, Intent intent, int requestCode, Bundle options) {
    ... ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess(who);
        // The services provided by ActivityManagerService can be obtained through the ActivityManager.getService() method
        int result = ActivityManager.getService().startActivity(whoThread,
                            who.getBasePackageName(), intent, 
                            intent.resolveTypeIfNeeded(who.getContentResolver()),
                            token, target != null ? target.mEmbeddedID : null, 
                            requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}

We study the ActivityManager.getService() method:

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

public static IActivityManager getService() {
    return IActivityManagerSingleton.get();    // Get the IActivityManager singleton
}
    
private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
        };

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
          
public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

We found that the Binder communication between Activity Manager Service and Activity Manger takes the form of AIDL.

The ActivityManager.getService().startActivity method actually calls the startActivity() method of the ActivityManagerService.

If you don't know about AIDL, you can check it out [Android's Core Mechanisms']--The ubiquitous "AIDL" One article.

2.8 ActivityManagerService.startActivity

Let's look at the startActivity method of ActivityManagerService:

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
    // Move to the startActivityAsUser method
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}

2.9 ActivityManagerService.startActivityAsUser

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

// Android P has been added. The process here is totally different from before, but the final method is the same. Follow it carefully.
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
    // Continue tuning the startActivityAsUser method
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
            true /*validateIncomingUser*/);
}

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
        boolean validateIncomingUser) {
    enforceNotIsolatedCaller("startActivity");

    userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
                      Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

    // Before Android P, the ActivityStartController.startActivityMayWait method was called
    return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)            
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setMayWait(userId)      // mRequest.mayWait = true is set, which will be used later.
            .execute();
}

2.10 ActivityStartController.obtainStarter

// frameworks/base/services/core/java/com/android/server/am/ActivityStartController.java

import com.android.server.am.ActivityStarter.Factory;
private final Factory mFactory;

ActivityStarter obtainStarter(Intent intent, String reason) {
    // What did get (), setIntent(), and setReason(), respectively, are described below.
    return mFactory.obtain().setIntent(intent).setReason(reason);
}

The factory model is used here. Let's follow the specific process.

2.10.1 DefaultFactory.obtain

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

interface Factory {
    void setController(ActivityStartController controller);
    ActivityStarter obtain();
    void recycle(ActivityStarter starter);
}

// DefaultFactory implements classes
static class DefaultFactory implements Factory {
    ... ...
    @Override
    public ActivityStarter obtain() {
        ActivityStarter starter = mStarterPool.acquire();

        // The get () method eventually returns an instance of ActivityStarter
        if (starter == null) {
            starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
        }
        return starter;
    }
    ... ...
}

2.10.2 ActivityStarter.setIntent

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

ActivityStarter setIntent(Intent intent) {
    mRequest.intent = intent;        // Assignment for mRequest 
    return this;
}

2.10.3 ActivityStarter.setReason

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

ActivityStarter setReason(String reason) {
    mRequest.reason = reason;        // Assignment for mRequest
    return this;
}

The mActivityStartController.obtainStarter() method eventually obtains an ActivityStarter object containing all the startup information, then performs various assignment processing, and finally executes the execute method.

2.11 ActivityStarter.execute

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

// The setMayWait(userId) method is executed above.
ActivityStarter setMayWait(int userId) {
    mRequest.mayWait = true;
    mRequest.userId = userId;
    return this;
}
    
int execute() {
    try {
        if (mRequest.mayWait) {    // The setMayWait() method is set to true
            return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                    mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
                    mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                    mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
                    mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
                    mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
                    mRequest.inTask, mRequest.reason,
                    mRequest.allowPendingRemoteAnimationRegistryLookup,
                    mRequest.originatingPendingIntent);
        } else {
            return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                    mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
                    mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                    mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
                    mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
                    mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
                    mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                    mRequest.outActivity, mRequest.inTask, mRequest.reason,
                    mRequest.allowPendingRemoteAnimationRegistryLookup,
                    mRequest.originatingPendingIntent);
        }
    } finally {
        onExecutionComplete();
    }
}

After a round trip, we finally came to the startActivityMayWait() method!

2.12 Process Summary

2.13 ActivityStarter.startActivityMayWait

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

private int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult,
        Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
        int userId, TaskRecord inTask, String reason,
        boolean allowPendingRemoteAnimationRegistryLookup,
        PendingIntentRecord originatingPendingIntent) {
    // Refuse possible leaked file descriptors
    if (intent != null && intent.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }
    mSupervisor.getActivityMetricsLogger().notifyActivityLaunching();
    boolean componentSpecified = intent.getComponent() != null;

    final int realCallingPid = Binder.getCallingPid();
    final int realCallingUid = Binder.getCallingUid();
    ... ...
    // Analyzing Intent's Data
    ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
            0 /* matchFlags */,
                    computeResolveFilterUid(
                            callingUid, realCallingUid, mRequest.filterCallingUid));
    ... ...
    // Collect relevant information in intent
    ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);

    synchronized (mService) {
        ... ...
        // Data used to record Activity
        final ActivityRecord[] outRecord = new ActivityRecord[1];
        // Start Activity
        int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
                voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
                callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
                ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
                allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);

        Binder.restoreCallingIdentity(origId);
        ... ...
        mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
        return res;
    }
}

2.14 ActivityStarter.startActivity -01

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
        ActivityRecord[] outActivity, TaskRecord inTask, String reason,
        boolean allowPendingRemoteAnimationRegistryLookup,
        PendingIntentRecord originatingPendingIntent) {
    ... ...
    // Jump startActivity
    mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
            aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
            callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
            options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
            inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent);
    ... ...
    return getExternalResult(mLastStartActivityResult);
}

2.15 ActivityStarter.startActivity -02

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        SafeActivityOptions options,
        boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
        TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
        PendingIntentRecord originatingPendingIntent) {
    ... ...
    // Jump startActivity
    return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true /* doResume */, checkedOptions, inTask, outActivity);
}

2.16 ActivityStarter.startActivity -03

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
    int result = START_CANCELED;
    try {
        // Pause layout
        mService.mWindowManager.deferSurfaceLayout();
        // Call the startActivityUnchecked method
        result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, doResume, options, inTask, outActivity);
    } finally {
        final ActivityStack stack = mStartActivity.getStack();
        if (!ActivityManager.isStartResultSuccessful(result) && stack != null) {
            stack.finishActivityLocked(mStartActivity, RESULT_CANCELED,
                    null /* intentResultData */, "startActivity", true /* oomAdj */);
        }
        // Continue layout
        mService.mWindowManager.continueSurfaceLayout();
    }
    postStartActivityProcessing(r, result, mTargetStack);
    return result;
}

startActivity() is called three times, and finally the startActivityUnchecked() method is executed, which decides how to start an activity based on the startup flag and Activity startup mode.

2.17 ActivityStarter.startActivityUnchecked

// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity) {
            
    // Initialization of various configurations that start Activity will be reset before reconfiguration, including Activity Record, Intent, etc.
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
            voiceInteractor);

    // Calculate the starting FLAG and assign the calculated value to mLaunchFlags
    computeLaunchingTaskFlags();
    computeSourceStack();
    // Setting mLaunchFlags to Intent achieves the purpose of setting the activation mode of Activity
    mIntent.setFlags(mLaunchFlags);
    // Get whether there are reusable activities
    ActivityRecord reusedActivity = getReusableIntentActivity();
    ... ...
    // Reusable Activity is not empty
    if (reusedActivity != null) {
        ... ...
    }
    ... ...
    mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
            mOptions);
    if (mDoResume) {
        final ActivityRecord topTaskActivity =
                mStartActivity.getTask().topRunningActivityLocked();
        if (!mTargetStack.isFocusable()
                || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                && mStartActivity != topTaskActivity)) {
            ... ...
        } else {
            if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                mTargetStack.moveToFront("startActivityUnchecked");
            }
            // Call the resumeFocusedStackTopActivityLocked() method
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                    mOptions);
        }
    } else if (mStartActivity != null) {
        mSupervisor.mRecentTasks.add(mStartActivity.getTask());
    }
    ... ...
    return START_SUCCESS;
}

2.18 ActivityStackSupervisor.resumeFocusedStackTopActivityLocked

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

    if (!readyToResume()) {
        return false;
    }

    if (targetStack != null && isFocusedStack(targetStack)) {
        // Call resumeTopActivityUncheckedLocked method
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }

    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
    if (r == null || !r.isState(RESUMED)) {
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
    } else if (r.isState(RESUMED)) {
        mFocusedStack.executeAppTransition(targetOptions);
    }

    return false;
}

2.19 ActivityStack.resumeTopActivityUncheckedLocked

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    if (mStackSupervisor.inResumeTopActivity) {
        // Don't even start recursing.
        return false;
    }

    boolean result = false;
    try {
        // Protect against recursion.
        mStackSupervisor.inResumeTopActivity = true;
        result = resumeTopActivityInnerLocked(prev, options);    // Key methodologies

        final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
        if (next == null || !next.canTurnScreenOn()) {
            checkReadyForSleep();
        }
    } finally {
        mStackSupervisor.inResumeTopActivity = false;
    }

    return result;
}

2.20 ActivityStack.resumeTopActivityInnerLocked

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    if (!mService.mBooting && !mService.mBooted) {
        // Not ready yet!
        return false;
    }
    ... ...
    boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
    if (mResumedActivity != null) {
        if (DEBUG_STATES) Slog.d(TAG_STATES,
                "resumeTopActivityLocked: Pausing " + mResumedActivity);
        // startPausingLocked() method is executed first
        pausing |= startPausingLocked(userLeaving, false, next, false);
    }
    ... ...
    ActivityStack lastStack = mStackSupervisor.getLastStack();
    if (next.app != null && next.app.thread != null) {
        ... ...
        synchronized(mWindowManager.getWindowManagerLock()) {
            ... ...
            try {
                ... ...    
            } catch (Exception e) {
                ... ...
                // Execute the startSpecificActivityLocked() method
                mStackSupervisor.startSpecificActivityLocked(next, true, false);
                return true;
            }
        }

        try {
            next.completeResumeLocked();
        } catch (Exception e) {
            requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
                    "resume-exception", true);
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return true;
        }
    } else {
        ... ...
        // Execute the startSpecificActivityLocked() method
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }

    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    return true;
}

In the resumeTopActivityInnerLocked method, it is used to determine whether an Activity is in the Resume state.

If there is one, the Activity is first asked to execute the Pausing process (Launcher's onPause process in this case) and then the startSpecific ActivityLocked method is executed to start the Activity that needs to be started.

2.21 ActivityStack.startPausingLocked

Let's first analyze the startPausingLocked() source code. The startSpecificActivityLocked() startSpecificActivityLocked () is discussed in the third section.

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

// Execution of onPause method by stack top Activity
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
        ActivityRecord resuming, boolean pauseImmediately) {
    ... ...
    ActivityRecord prev = mResumedActivity;
    ... ...
    // Assign prev to mPausingActivity, which is used during Activity startup.
    // This is actually the assignment of mResumedActivity to mPausingActivity, our Launcher.
    mPausingActivity = prev;
    ... ...
    if (prev.app != null && prev.app.thread != null) {
        try {
            EventLogTags.writeAmPauseActivity(prev.userId, System.identityHashCode(prev),
                    prev.shortComponentName, "userLeaving=" + userLeaving);
            mService.updateUsageStats(prev, false);
            /*
             * Android P Client Lifecycle Manager and Client Transaction Handler are introduced here to assist.
             * Manage the Activity life cycle, which sends EXECUTE_TRANSACTION messages
             * Continue processing in ActivityThread.H.
             
             * PauseActivityItem is implemented through the scheduleTransaction method of ClientLifecycle Manager
             * Events are added to the execution plan to start the pausing process at the top of the stack.
             */
            mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken,
                    PauseActivityItem.obtain(prev.finishing, userLeaving,
                                    prev.configChangeFlags, pauseImmediately));
        } catch (Exception e) {
            // Ignore exception, if process died other code will cleanup.
            Slog.w(TAG, "Exception thrown during pause", e);
            mPausingActivity = null;
            mLastPausedActivity = null;
            mLastNoHistoryActivity = null;
        }
    } else {
        mPausingActivity = null;
        mLastPausedActivity = null;
        mLastNoHistoryActivity = null;
    }
    ... ...
}

2.22 ClientLifecycleManager.scheduleTransaction

// frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java

class ClientLifecycleManager {
    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        transaction.schedule();
        if (!(client instanceof Binder)) {
            transaction.recycle();
        }
    }
    ... ...
}

// frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java

public class ClientTransaction implements Parcelable, ObjectPoolItem {

    /** Target client. */
    private IApplicationThread mClient;
    
    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }
}

The mClient of ClientTransaction.schedule method is an IApplicationThread type. The internal class ApplicationThread of ActivityThread derives this interface class and implements the corresponding method. So jump directly to the scheduleTransaction method in Application Thread.

2.23 ActivityThread.scheduleTransaction

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

public final class ActivityThread extends ClientTransactionHandler {

    private class ApplicationThread extends IApplicationThread.Stub {
        ... ...    
        public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
            ActivityThread.this.scheduleTransaction(transaction);
        }
    }
}

2.24 Process Summary

2.25 ClientTransactionHandler.scheduleTransaction

The scheduleTransaction method is not defined in the ActivityThread class, so it calls the scheduleTransaction method of its parent ClientTransactionHandler.

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

public abstract class ClientTransactionHandler {

    abstract void sendMessage(int what, Object obj);
    
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        // sendMessage method is called, which is an abstract method.
        // Its implementation is in ActivityThread, a derived class of ClientTransactionHandler.
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
}

2.26 ActivityThread.sendMessage

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

public final class ActivityThread extends ClientTransactionHandler {

    private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);

    void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
    }

    private void sendMessage(int what, Object obj, int arg1) {
        sendMessage(what, obj, arg1, 0, false);
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2) {
        sendMessage(what, obj, arg1, arg2, false);
    }

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        // The ActivityThread.sendMessage method sends the message to Hadler, whose internal name is H.
        mH.sendMessage(msg);
    }
    
    class H extends Handler {
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case EXECUTE_TRANSACTION:
                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
                    // An instance of Handler H is called after receiving the EXECUTE_TRANSACTION message 
                    // The TransactionExecutor.execute method switches the Activity state.
                    mTransactionExecutor.execute(transaction);
                    if (isSystem()) {
                        transaction.recycle();
                    }
                    // TODO(lifecycler): Recycle locally scheduled transactions.
                    break;
            }
        }
    }
}

2.27 TransactionExecutor.execute

// frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java

public class TransactionExecutor {

    public void execute(ClientTransaction transaction) {
        final IBinder token = transaction.getActivityToken();
        log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);

        executeCallbacks(transaction);    // Important Method 1
        executeLifecycleState(transaction);    // Important Method 2
        
        mPendingActions.clear();
        log("End resolving transaction");
    }

    // Important Method 1
    public void executeCallbacks(ClientTransaction transaction) {
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        if (callbacks == null) {
            // No callbacks to execute, return early.
            return;
        }

        final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
            final ClientTransactionItem item = callbacks.get(i);
            ... ...
            item.execute(mTransactionHandler, token, mPendingActions);
            item.postExecute(mTransactionHandler, token, mPendingActions);
            ... ...
        }
    }

    // Important Method 2
    /** Transition to the final state if requested by the transaction. */
    private void executeLifecycleState(ClientTransaction transaction) {
        final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
        ... ...
        // The state before the current life cycle state is executed
        cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);

        // Execute the final transition with proper parameters.
        lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
        lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
    }
    
}

In the ActivityStack.startPausingLocked method, scheduleTransaction passes the PauseActivityItem object, so the execute method called in the executeLifecycleState method is actually the PauseActivityItem.execute method.

2.28 PauseActivityItem.execute

// frameworks/base/core/java/android/app/servertransaction/PauseActivityItem.java

public class PauseActivityItem extends ActivityLifecycleItem {

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        // Jump to the ActivityThread.handlePauseActivity method
        client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
                "PAUSE_ACTIVITY_ITEM");
    }
}

2.29 ActivityThread.handlePauseActivity

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

@Override
public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
        int configChanges, PendingTransactionActions pendingActions, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    if (r != null) {
        ... ...
        performPauseActivity(r, finished, reason, pendingActions);
        ... ...
    }
}

2.30 ActivityThread.performPauseActivity

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

final Bundle performPauseActivity(IBinder token, boolean finished, String reason,
        PendingTransactionActions pendingActions) {
    ActivityClientRecord r = mActivities.get(token);
    return r != null ? performPauseActivity(r, finished, reason, pendingActions) : null;
}

private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason,
        PendingTransactionActions pendingActions) {
    ... ...
    performPauseActivityIfNeeded(r, reason);
    ... ...
    return shouldSaveState ? r.state : null;
}

2.31 ActivityThread.performPauseActivityIfNeeded

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

private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
    if (r.paused) {
        // You are already paused silly...
        return;
    }

    try {
        r.activity.mCalled = false;
        mInstrumentation.callActivityOnPause(r.activity);    // Key methodologies
        if (!r.activity.mCalled) {
            throw new SuperNotCalledException("Activity " + safeToComponentShortString(r.intent)
                    + " did not call through to super.onPause()");
        }
    } catch (SuperNotCalledException e) {
        throw e;
    } catch (Exception e) {
        if (!mInstrumentation.onException(r.activity, e)) {
            throw new RuntimeException("Unable to pause activity "
                    + safeToComponentShortString(r.intent) + ": " + e.toString(), e);
        }
    }
    r.setState(ON_PAUSE);
}

2.32 Instrumentation.callActivityOnPause

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

public void callActivityOnPause(Activity activity) {
    activity.performPause();      // Direct invocation of Activity.performPause method
}

2.33 Activity.performPause

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

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {

    final void performPause() {
        ... ...
        onPause();
        ... ...
    }
}

Summary of 2.34 Process

So far, Launcher's onPause() process analysis is over! At the same time, we need to understand that the onPause method of Activity at the top of the stack is the first one to be executed when starting an activity.

III. Starting the Process

Launcher's onPause() process is analyzed. Next, let's look at the startSpecificActivityLocked() method for starting a new process. In this method, we will determine whether App has been started based on the existence of processes and threads.

3.1 ActivityStackSupervisor.startSpecificActivityLocked

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // Is this activity's application already running?
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

    getLaunchTimeTracker().setLaunchTime(r);

    // If the app exists and has been started
    if (app != null && app.thread != null) {
        try {
            if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                    || !"android".equals(r.info.packageName)) {
                app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
                        mService.mProcessStats);
            }
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }
    }

    // Start a new process with mService as Activity Manager Service
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

If started, the ActivityManagerService.realStartActivityLocked method is called to continue processing.

If it is not started, the ActivityManagerService.startProcessLocked method is called to create a new process process process.

3.2 ActivityManagerService.startProcessLocked -01

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        String hostingType, ComponentName hostingName, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
            hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
            null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
            null /* crashHandler */);
}

3.3 ActivityManagerService.startProcessLocked -02

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
        boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
    ... ...
    
    final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
}

3.3 ActivityManagerService.startProcessLocked -03

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private final boolean startProcessLocked(ProcessRecord app,
        String hostingType, String hostingNameStr, String abiOverride) {
    return startProcessLocked(app, hostingType, hostingNameStr,
            false /* disableHiddenApiChecks */, abiOverride);
}

3.4 ActivityManagerService.startProcessLocked -04

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private final boolean startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {

    try {
        ... ...
        return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                startTime);
    } catch (RuntimeException e) {
        forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
                false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
        return false;
    }
}

3.5 ActivityManagerService.startProcessLocked -05

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime) {
    ... ...
    final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
                    uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
                    invokeWith, startTime);
    ... ...
}

3.6 ActivityManagerService.startProcess

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private ProcessStartResult startProcess(String hostingType, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
    try {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                app.processName);
        checkTime(startTime, "startProcess: asking zygote to start proc");
        final ProcessStartResult startResult;
        if (hostingType.equals("webview_service")) {
            startResult = startWebView(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, null,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        } else {
            // Execute the Process.start method
            startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, invokeWith,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        }
        checkTime(startTime, "startProcess: returned from zygote!");
        return startResult;
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
}

At this point, we understand that the ActivityManagerService.startProcessLocked method, after several jumps, will eventually create a process for the application through the Process.start method.

The process creation process and source code analysis are not discussed here. stay [Android'Process Threads'] Chat about how "processes" are created In this article, we have made a detailed analysis!

IV. Activity process

In our process-created blog, we discussed that the source code will eventually execute to the ActivityThread.main method to initialize the main thread.

4.1 Initialize the main thread

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

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser();

    EventLogger.setReporter(new EventLoggingReporter());

    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("<pre-initialized>");

    Looper.prepareMainLooper();    // Create the main thread looper

    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    ActivityThread thread = new ActivityThread();    // Initialize ActivityThread
    thread.attach(false, startSeq);    // attach to system process

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();    // The main thread starts and enters the loop state

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

4.2 Start Activity

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

private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ... ...
        final IActivityManager mgr = ActivityManager.getService();
        try {
            // Bind an Application for this application through Activity Manager Service
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Add a garbage collector, which will be in the run method whenever the system triggers garbage collection
        // To calculate how much memory the application uses, if more than three-quarters of the total, it will attempt to free memory.
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        });
    } else {
        ... ...
    }
    ... ...
    // Adding a config callback to the root View to receive information about config changes
    ViewRootImpl.addConfigCallback(configChangedCallback);
}

4.2.1 ActivityManagerService.attachApplication

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        Binder.restoreCallingIdentity(origId);
    }
}

4.2.2 ActivityManagerService.attachApplicationLocked

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    ... ... 
    // See if the top visible activity is waiting to run in this process...
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
    ... ...
    return true;
}

4.3 ActivityStackSupervisor.attachApplicationLocked

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
        for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = display.getChildAt(stackNdx);
            if (!isFocusedStack(stack)) {
                continue;
            }
            stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
            final ActivityRecord top = stack.topRunningActivityLocked();
            final int size = mTmpActivityList.size();
            for (int i = 0; i < size; i++) {
                final ActivityRecord activity = mTmpActivityList.get(i);
                if (activity.app == null && app.uid == activity.info.applicationInfo.uid
                        && processName.equals(activity.processName)) {
                    try {
                        // Execute the realStartActivityLocked method
                        if (realStartActivityLocked(activity, app,
                                top == activity /* andResume */, true /* checkConfig */)) {
                            didSomething = true;
                        }
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception in new application when starting activity "
                                + top.intent.getComponent().flattenToShortString(), e);
                        throw e;
                    }
                }
            }
        }
    }
    if (!didSomething) {
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    }
    return didSomething;
}

4.4 ActivityStackSupervisor.realStartActivityLocked

Real Start Activity Locked is a method called to start an activity when the application process has been started.

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {

    try {
        ... ...
        try {
            ... ...
            final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                    r.appToken);
            // Add the callback of LaunchActivityItem to the ClientTransaction object
            clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                    System.identityHashCode(r), r.info,
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                    profilerInfo));

            final ActivityLifecycleItem lifecycleItem;
            // Setting the current life cycle state
            if (andResume) {
                lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
            } else {
                lifecycleItem = PauseActivityItem.obtain();
            }
            clientTransaction.setLifecycleStateRequest(lifecycleItem);

            // Call the ClientLifecycle Manager. scheduleTransaction method
            mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    ... ...
}

After calling the ClientLifecycle Manager. scheduleTransaction method, we have already analyzed how to execute it, but we will not analyze it here.

Let's look at the LaunchActivityItem.execute method after executing callback.

4.5 LaunchActivityItem.execute

// frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java

@Override
public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
            mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
            mPendingResults, mPendingNewIntents, mIsForward,
            mProfilerInfo, client);
    // Call the ActivityThread.handleLaunchActivity method
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

4.6 ActivityThread.handleLaunchActivity

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

public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, Intent customIntent) {
    ... ...
    final Activity a = performLaunchActivity(r, customIntent);
    ... ...
}

4.7 ActivityThread.performLaunchActivity

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

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }
    
    // Initialize ComponentName
    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);
    }
    
    // Initialize ContextImpl and Activeness
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.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) {
        ... ...
    }

    try {
        // Initialize Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
                config.updateFrom(r.overrideConfig);
            }
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            appContext.setOuterContext(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 (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            checkAndBlockForNetworkAccess();
            activity.mStartedActivity = false;
            // Setting the Theme of Activity
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) {
                activity.setTheme(theme);
            }

            activity.mCalled = false;
            // Call Instrumentation.callActivityOnCreate method
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            if (!activity.mCalled) {
            ... ...
            r.activity = activity;
        }
        r.setState(ON_CREATE);

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        ... ...
    }

    return activity;
}

4.8 Instrumentation.callActivityOnCreate

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

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

4.9 Activity.performCreate

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

final void performCreate(Bundle icicle, PersistableBundle persistentState) {
    ... ...
    if (persistentState != null) {
        onCreate(icicle, persistentState);
    } else {
        onCreate(icicle);
    }
    ... ...
}

At this point, when executeCallbacks() is finished, the executeLifecycleState method is started, and the cycleToPath method is executed first.

4.10 TransactionExecutor.cycleToPath

// frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java

private void cycleToPath(ActivityClientRecord r, int finish,
            boolean excludeLastState) {
    final int start = r.getLifecycleState();
    log("Cycle from: " + start + " to: " + finish + " excludeLastState:" + excludeLastState);
    final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
    performLifecycleSequence(r, path);
}

4.11 TransactionExecutor.performLifecycleSequence

// frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java

private void performLifecycleSequence(ActivityClientRecord r, IntArray path) {
        final int size = path.size();
    for (int i = 0, state; i < size; i++) {
        state = path.get(i);
        log("Transitioning to state: " + state);
        // The life cycle state is from ON_CREATE state to ON_RESUME state, with an ON_START state in the middle.
        // So the ActivityThread.handleStartActivity method is executed.
        switch (state) {
            case ON_CREATE:
                mTransactionHandler.handleLaunchActivity(r, mPendingActions,
                        null /* customIntent */);
                break;
            case ON_START:
                mTransactionHandler.handleStartActivity(r, mPendingActions);
                break;
            case ON_RESUME:
                mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
                        r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
                break;
            case ON_PAUSE:
                mTransactionHandler.handlePauseActivity(r.token, false /* finished */,
                        false /* userLeaving */, 0 /* configChanges */, mPendingActions,
                        "LIFECYCLER_PAUSE_ACTIVITY");
                break;
            case ON_STOP:
                mTransactionHandler.handleStopActivity(r.token, false /* show */,
                        0 /* configChanges */, mPendingActions, false /* finalStateRequest */,
                        "LIFECYCLER_STOP_ACTIVITY");
                break;
            case ON_DESTROY:
                mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */,
                        0 /* configChanges */, false /* getNonConfigInstance */,
                        "performLifecycleSequence. cycling to:" + path.get(size - 1));
                break;
            case ON_RESTART:
                mTransactionHandler.performRestartActivity(r.token, false /* start */);
                break;
            default:
                throw new IllegalArgumentException("Unexpected lifecycle state: " + state);
        }
    }
}

4.12 ActivityThread.handleStartActivity

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

public void handleStartActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions) {
    ... ...
    // Start
    activity.performStart("handleStartActivity");
    r.setState(ON_START);
    ... ...
}

4.13 Activity.performStart

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

final void performStart(String reason) {
    ... ...
    mInstrumentation.callActivityOnStart(this);
    ... ...
}

4.14 Instrumentation.callActivityOnStart

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

public void callActivityOnStart(Activity activity) {
    // After many jumps, the Activity.onStart method is finally called
    activity.onStart();
}

After executing cycleToPath, start executing the ResumeActivityItem.execute method.

4.15 ResumeActivityItem.execute

// frameworks/base/core/java/android/app/servertransaction/ResumeActivityItem.java

public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
    client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
            "RESUME_ACTIVITY");
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

4.16 ActivityThread.handleResumeActivity

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

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
    ... ...
    // TODO Push resumeArgs into the activity for consideration
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    if (r == null) {
        // We didn't actually resume the activity, so skipping any follow-up actions.
        return;
    }
    ... ...
    if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
    
    // The method here will be explained in the end, which involves the onStop() method.
    Looper.myQueue().addIdleHandler(new Idler());
}

4.17 ActivityThread.performResumeActivity

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

public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest,
        String reason) {
    ... ...
    try {
        r.activity.onStateNotSaved();
        r.activity.mFragments.noteStateNotSaved();
        checkAndBlockForNetworkAccess();
        if (r.pendingIntents != null) {
            deliverNewIntents(r, r.pendingIntents);
            r.pendingIntents = null;
        }
        if (r.pendingResults != null) {
            deliverResults(r, r.pendingResults, reason);
            r.pendingResults = null;
        }
        // Execute the performResume method
        r.activity.performResume(r.startsNotResumed, reason);

        r.state = null;
        r.persistentState = null;
        r.setState(ON_RESUME);
    } catch (Exception e) {
        if (!mInstrumentation.onException(r.activity, e)) {
            throw new RuntimeException("Unable to resume activity "
                    + r.intent.getComponent().toShortString() + ": " + e.toString(), e);
        }
    }
    return r;
}

4.18 Activity.performResume

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

final void performResume(boolean followedByPause, String reason) {
    performRestart(true /* start */, reason);
    ... ...
    // mResumed is set by the instrumentation
    mInstrumentation.callActivityOnResume(this);
    ... ...
}

4.19 Instrumentation.callActivityOnResume

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

public void callActivityOnResume(Activity activity) {
    activity.mResumed = true;
    // Eventually call the Activity.onResume method
    activity.onResume();
    ... ...
}

So far, Activity has been started.

5. Stack top activity onStop

When we discussed the ActivityThread.handleResumeActivity source code, the last line of code was not discussed.

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

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
        String reason) {
    ... ...
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    ... ...
    // This Handler is executed when MessageQueue is idle, after executing the onResume() method of the current Activity
    Looper.myQueue().addIdleHandler(new Idler());
}

Why discuss this line of code separately, because the onPause(), onCreate(), onStart(), onResume() of the new Activity are analyzed above, but an onStop() lifecycle of the top Activity is missing. This method is handled in this line of code.

5.1 Idler

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

private class Idler implements MessageQueue.IdleHandler {
    @Override
    public final boolean queueIdle() {
        ... ...
        if (a != null) {
            mNewActivities = null;
            IActivityManager am = ActivityManager.getService();
            ActivityClientRecord prev;
            do {
                if (a.activity != null && !a.activity.mFinished) {
                    try {
                        // Call the ActivityManagerService.activityIdle method
                        am.activityIdle(a.token, a.createdConfig, stopProfiling);
                        a.createdConfig = null;
                    } catch (RemoteException ex) {
                        throw ex.rethrowFromSystemServer();
                    }
                }
                prev = a;
                a = a.nextIdle;
                prev.nextIdle = null;
            } while (a != null);
        }
        ... ...
        return false;
    }
}

5.2 ActivityManagerService.activityIdle

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
    final long origId = Binder.clearCallingIdentity();
    synchronized (this) {
        ActivityStack stack = ActivityRecord.getStackLocked(token);
        if (stack != null) {
            // Call the ActivityStackSupervisor.activityIdleInternalLocked method
            ActivityRecord r =
                    mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
                            false /* processPausingActivities */, config);
            if (stopProfiling) {
                if ((mProfileProc == r.app) && mProfilerInfo != null) {
                    clearProfilerLocked();
                }
            }
        }
    }
    Binder.restoreCallingIdentity(origId);
}

5.3 ActivityStackSupervisor.activityIdleInternalLocked

// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
        boolean processPausingActivities, Configuration config) {

    for (int i = 0; i < NS; i++) {
        r = stops.get(i);
        final ActivityStack stack = r.getStack();
        if (stack != null) {
            if (r.finishing) {
                stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
                        "activityIdleInternalLocked");
            } else {
                stack.stopActivityLocked(r);
            }
        }
    }
    ... ...
    return r;
}

5.4 ActivityStack.stopActivityLocked

// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

final void stopActivityLocked(ActivityRecord r) {
    ... ...
    if (r.app != null && r.app.thread != null) {
        adjustFocusedActivityStack(r, "stopActivity");
        r.resumeKeyDispatchingLocked();
        try {
            ... ...
            mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
                    StopActivityItem.obtain(r.visible, r.configChangeFlags));
            if (shouldSleepOrShutDownActivities()) {
                r.setSleeping(true);
            }
            Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
            mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
        } catch (Exception e) {
            ... ...
        }
    }
}

I saw ClientLifecycle Manager. scheduleTransaction method again. I have analyzed it many times before, and I will execute the StopActivityItem.execute method. After many jumps, I finally execute the Activity.onStop method.

5.5 StopActivityItem.execute

// frameworks/base/core/java/android/app/servertransaction/StopActivityItem.java

@Override
public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
    client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions,
            true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

5.6 ActivityThread.handleStopActivity

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

@Override
public void handleStopActivity(IBinder token, boolean show, int configChanges,
        PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) {
    ... ...
    performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest,
                reason);
    ... ...
}

5.7 ActivityThread.performStopActivityInner

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

private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown,
        boolean saveState, boolean finalStateRequest, String reason) {
    if (r != null) {
        ... ...
        if (!keepShown) {
            callActivityOnStop(r, saveState, reason);
        }
    }
}

5.8 ActivityThread.callActivityOnStop

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

private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) {
    ... ...
    try {
        r.activity.performStop(false /*preserveWindow*/, reason);
    } catch (SuperNotCalledException e) {
        throw e;
    } catch (Exception e) {
        ... ...
    }
    ... ...
}

5.9 Activity.performStop

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

final void performStop(boolean preserveWindow, String reason) {
    ... ...
    if (!mStopped) {
        ... ...
        mInstrumentation.callActivityOnStop(this);
    }
}

5.10 Instrumentation.callActivityOnStop

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

public void callActivityOnStop(Activity activity) {
    activity.onStop();
}

Posted by tomsasse on Tue, 27 Aug 2019 02:29:41 -0700