Connect the Activity startup process (part 1)

Prepare to start the target Activity

ActivityStack. ResumeTopActivityInnerLocked (the lower part, send Resume request)

    // /frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
    @GuardedBy("mService")
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        // .....
        //以上省略,主要是PasueActivity窗口隐藏,过渡动画等部分
        ActivityStack lastStack = mStackSupervisor.getLastStack();
        //通过缓存的ProcressRecord中的IApplicationThread来判断进程是否存在
        if (next.app != null && next.app.thread != null) {
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
                    + " stopped=" + next.stopped + " visible=" + next.visible);

            // If the previous activity is translucent, force a visibility update of
            // the next activity, so that it's added to WM's opening app list, and
            // transition animation can be set up properly.
            // For example, pressing Home button with a translucent activity in focus.
            // Launcher is already visible in this case. If we don't add it to opening
            // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a
            // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation.
            final boolean lastActivityTranslucent = lastStack != null
                    && (lastStack.inMultiWindowMode()
                    || (lastStack.mLastPausedActivity != null
                    && !lastStack.mLastPausedActivity.fullscreen));

            // The contained logic must be synchronized, since we are both changing the visibility
            // and updating the {@link Configuration}. {@link ActivityRecord#setVisibility} will
            // ultimately cause the client code to schedule a layout. Since layouts retrieve the
            // current {@link Configuration}, we must ensure that the below code updates it before
            // the layout can occur.
            synchronized(mWindowManager.getWindowManagerLock()) {
                // This activity is now becoming visible.
                if (!next.visible || next.stopped || lastActivityTranslucent) {
                    next.setVisibility(true);
                }

                // schedule launch ticks to collect information about slow apps.
                next.startLaunchTickingLocked();

                ActivityRecord lastResumedActivity =
                        lastStack == null ? null :lastStack.mResumedActivity;
                final ActivityState lastState = next.getState();

                mService.updateCpuStats();

                if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
                        + " (in existing)");

                next.setState(RESUMED, "resumeTopActivityInnerLocked");

                mService.updateLruProcessLocked(next.app, true, null);
                updateLRUListLocked(next);
                mService.updateOomAdjLocked();

                // Have the window manager re-evaluate the orientation of
                // the screen based on the new activity order.
                boolean notUpdated = true;

                if (mStackSupervisor.isFocusedStack(this)) {
                    // We have special rotation behavior when here is some active activity that
                    // requests specific orientation or Keyguard is locked. Make sure all activity
                    // visibilities are set correctly as well as the transition is updated if needed
                    // to get the correct rotation behavior. Otherwise the following call to update
                    // the orientation may cause incorrect configurations delivered to client as a
                    // result of invisible window resize.
                    // TODO: Remove this once visibilities are set correctly immediately when
                    // starting an activity.
                    notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
                            true /* markFrozenIfConfigChanged */, false /* deferResume */);
                }

                if (notUpdated) {
                    // The configuration update wasn't able to keep the existing
                    // instance of the activity, and instead started a new one.
                    // We should be all done, but let's just make sure our activity
                    // is still at the top and schedule another run if something
                    // weird happened.
                    ActivityRecord nextNext = topRunningActivityLocked();
                    if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
                            "Activity config changed during resume: " + next
                                    + ", new next: " + nextNext);
                    if (nextNext != next) {
                        // Do over!
                        mStackSupervisor.scheduleResumeTopActivities();
                    }
                    if (!next.visible || next.stopped) {
                        next.setVisibility(true);
                    }
                    next.completeResumeLocked();
                    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                    return true;
                }

                try {
                    final ClientTransaction transaction = ClientTransaction.obtain(next.app.thread,
                            next.appToken);
                    // Deliver all pending results.
                    ArrayList<ResultInfo> a = next.results;
                    if (a != null) {
                        final int N = a.size();
                        if (!next.finishing && N > 0) {
                            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                                    "Delivering results to " + next + ": " + a);
                            transaction.addCallback(ActivityResultItem.obtain(a));
                        }
                    }

                    if (next.newIntents != null) {
                        transaction.addCallback(NewIntentItem.obtain(next.newIntents,
                                false /* andPause */));
                    }

                    // Well the app will no longer be stopped.
                    // Clear app token stopped state in window manager if needed.
                    next.notifyAppResumed(next.stopped);

                    EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
                            System.identityHashCode(next), next.getTask().taskId,
                            next.shortComponentName);

                    next.sleeping = false;
                    mService.getAppWarningsLocked().onResumeActivity(next);
                    mService.showAskCompatModeDialogLocked(next);
                    next.app.pendingUiClean = true;
                    next.app.forceProcessStateUpTo(mService.mTopProcessState);
                    next.clearOptionsLocked();
                    //设置ResumeActivityItem生命周期的执行
                    transaction.setLifecycleStateRequest(
                            ResumeActivityItem.obtain(next.app.repProcState,
                                    mService.isNextTransitionForward()));
                    调度到App进程
                    mService.getLifecycleManager().scheduleTransaction(transaction);

                    if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
                            + next);
                } catch (Exception e) {
                    // Whoops, need to restart this activity!
                    if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to "
                            + lastState + ": " + next);
                    next.setState(lastState, "resumeTopActivityInnerLocked");

                    // lastResumedActivity being non-null implies there is a lastStack present.
                    if (lastResumedActivity != null) {
                        lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
                    }

                    Slog.i(TAG, "Restarting because process died: " + next);
                    if (!next.hasBeenLaunched) {
                        next.hasBeenLaunched = true;
                    } else  if (SHOW_APP_STARTING_PREVIEW && lastStack != null
                            && lastStack.isTopStackOnDisplay()) {
                        next.showStartingWindow(null /* prev */, false /* newTask */,
                                false /* taskSwitch */);
                    }
                    mStackSupervisor.startSpecificActivityLocked(next, true, false);
                    if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                    return true;
                }
            }

            // From this point on, if something goes wrong there is no way
            // to recover the activity.
            try {
                //进行resume的后续工作
                next.completeResumeLocked();
            } catch (Exception e) {
                // If any exception gets thrown, toss away this
                // activity and try the next one.
                Slog.w(TAG, "Exception thrown during resume of " + next, e);
                requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
                        "resume-exception", true);
                if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
                return true;
            }
        } else {
            // Whoops, need to restart this activity!
            if (!next.hasBeenLaunched) {
                next.hasBeenLaunched = true;
            } else {
                if (SHOW_APP_STARTING_PREVIEW) {
                    next.showStartingWindow(null /* prev */, false /* newTask */,
                            false /* taskSwich */);
                }
                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
            }
            //进程不存在或无效,执行startSpecificActivityLocked
            if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next);
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }

        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }
Copy the code

Can be seen from the above, this part is mainly to determine whether the process exists, there is direct send ResumeActivityItem request, inform the APP executive Resume operation, there is no call the startSpecificActivityLocked, has process does not exist under the situation, Continue to follow

Start a new APP process

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? / / get the target Activity process information ProcessRecord app. = mService getProcessRecordLocked (r.p rocessName, r.i show nfo. ApplicationInfo. The uid, true); getLaunchTimeTracker().setLaunchTime(r); // Check whether the target process exists if (app! = null && app.thread ! = null) { try { if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 || !" android".equals(r.info.packageName)) { // Don't add this if it is a platform component that is marked // to run in multiple processes, because this is actually // part of the framework so doesn't make sense to track as a // separate apk in the process. 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); } // If a dead object exception was thrown -- fall through to // restart the application. } mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }Copy the code

In the above method, getProcessRecordLocked obtains the process of the target App and determines whether the process exists or is valid to confirm the next step in the process. If the process exists, realStartActivityLocked is called to continue the process. If not, call startProcessLocked to start the target process

ActivityManagerService.startProcessLocked

// /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) { long startTime = SystemClock.elapsedRealtime(); ProcessRecord app; / /... Omit if (app == null) {checkTime(startTime, "startProcess: Creating new Process Record "); App = newProcessRecordLocked(info, processName, Isolated, isolatedUid); if (app == null) { Slog.w(TAG, "Failed making new process record for " + processName + "/" + info.uid + " isolated=" + isolated); return null; } app.crashHandler = crashHandler; app.isolatedEntryPoint = entryPoint; app.isolatedEntryPointArgs = entryPointArgs; checkTime(startTime, "startProcess: done creating new process record"); } else { // If this is a new package in the process, add the package to the list app.addPackage(info.packageName, info.versionCode, mProcessStats); checkTime(startTime, "startProcess: added package to existing proc"); } // If the system is not ready yet, then hold off on starting this // process until it is. mProcessesReady && ! isAllowedWhileBooting(info) && ! allowWhileBooting) { if (! mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "System not ready, putting on hold: " + app); checkTime(startTime, "startProcess: returning with proc on hold"); return app; } checkTime(startTime, "startProcess: stepping in to startProcess"); Final Boolean SUCCESS = startProcessLocked(app, hostingType, hostingNameStr, abiOverride); checkTime(startTime, "startProcess: done starting proc!" ); return success ? app : null; }Copy the code

The overloaded method of startProcessLocked will be called again, and the startProcess method will be called

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 { 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); }}Copy the code

Determine if it is webview_service, otherwise call process. start to start the Process and find process. start

Process.start

    // /frameworks/base/core/java/android/os/Process.java
    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int runtimeFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }
Copy the code

Just an indirect call to the zygoteProcess.start method, moving on

ZygoteProcess.start

// /frameworks/base/core/java/android/os/ZygoteProcess.java public final Process.ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String invokeWith, String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); throw new RuntimeException( "Starting VM process through Zygote failed", ex); }}Copy the code

Call the startViaZygote

ZygoteProcess.startViaZygote

// /frameworks/base/core/java/android/os/ZygoteProcess.java private Process.ProcessStartResult startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String invokeWith, boolean startChildZygote, String[] extraArgs) throws ZygoteStartFailedEx { ArrayList<String> argsForZygote = new ArrayList<String>(); // --runtime-args, --setuid=, --setgid=, // and --setgroups= must go first argsForZygote.add("--runtime-args"); argsForZygote.add("--setuid=" + uid); argsForZygote.add("--setgid=" + gid); argsForZygote.add("--runtime-flags=" + runtimeFlags); if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) { argsForZygote.add("--mount-external-default"); } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) { argsForZygote.add("--mount-external-read"); } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) { argsForZygote.add("--mount-external-write"); } argsForZygote.add("--target-sdk-version=" + targetSdkVersion); / /... This part of the code is omitted. The main thing is to set the startup parameter if (extraArgs! = null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } synchronized(mLock) { return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); }}Copy the code

You can see the function, will start the application process of the various parameters, and then call zygoteSendArgsAndGetResult method

ZygoteProcess.startViaZygote

    // /frameworks/base/core/java/android/os/ZygoteProcess.java
    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            // Throw early if any of the arguments are malformed. This means we can
            // avoid writing a partial response to the zygote.
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                if (args.get(i).indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
                }
            }

            /**
             * See com.android.internal.os.SystemZygoteInit.readArgumentList()
             * Presently the wire format to the zygote process is:
             * a) a count of arguments (argc, in essence)
             * b) a number of newline-separated argument strings equal to count
             *
             * After the zygote process reads these it will write the pid of
             * the child or -1 on failure, followed by boolean to
             * indicate whether a wrapper process was used.
             */
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;

            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();

            // Should there be a timeout on this?
            Process.ProcessStartResult result = new Process.ProcessStartResult();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }
Copy the code

This function sends these parameters to the Zygote process over the socket. The Zygote process incubates a new Dalvik application process and then tells ActivityManagerService the PID of the newly started process. Otherwise, this part will be further studied in the Android startup process. When an APP process is created, AMS uses attachApplication to inform the process that it has been started

The process is started.

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) { // Find the application record that is being attached... either via // the pid if we are running in multiple processes, or just pull the // next app record if we are emulating process with anonymous threads. ProcessRecord app; long startTime = SystemClock.uptimeMillis(); if (pid ! = MY_PID && pid >= 0) { synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); } } else { app = null; } / / government / / mark process is ready to start the Boolean normalMode = mProcessesReady | | isAllowedWhileBooting (app. Info); / / government / / Remove this record from the list of starting applications. MPersistentStartingProcesses. Remove (app); if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES, "Attach application locked removing on hold: " + app); mProcessesOnHold.remove(app); boolean badApp = false; boolean didSomething = false; // See if the top visible activity is waiting to run in this process... / / check if there is any activity is waiting for the process of starting the if (normalMode) {try {the if (mStackSupervisor. AttachApplicationLocked (app)) {didSomething = true; } } catch (Exception e) { Slog.wtf(TAG, "Exception thrown launching activities in " + app, e); badApp = true; }} // omit return true; }Copy the code

Here will continue to call mStackSupervisor attachApplicationLocked

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 = mactivitydisplay.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 {// Start the Activity waiting for resume 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; }Copy the code

As you can see, AMS calls realStartActivityLocked when it receives that the APP process has started, and starts the Activity that was held up waiting for the target process to start

Prepare to start the target Activity

ActivityStackSupervisor.realStartActivityLocked

// /frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { if (! allPausedActivitiesComplete()) { // While there are activities pausing we skipping starting any new activities until // pauses are complete. NOTE: that we also do this for activities that are starting in // the paused state because they will first be resumed then paused on the client side. if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE, "realStartActivityLocked: Skipping start of r=" + r + " some activities pausing..." ); return false; } final TaskRecord task = r.getTask(); final ActivityStack stack = task.getStack(); beginDeferResume(); Try {// omit try {if (app.thread == null) {throw new RemoteException(); } List<ResultInfo> results = null; List<ReferrerIntent> newIntents = null; if (andResume) { // We don't need to deliver new intents and/or set results if activity is going // to pause immediately  after launch. results = r.results; newIntents = r.newIntents; } // omit // Create activity launch transaction. Final ClientTransaction ClientTransaction = ClientTransaction.obtain(app.thread, r.appToken); / / create LaunchActivityItem and add into the mActivityCallbacks save clientTransaction. AddCallback (LaunchActivityItem. Obtain (new Intent(r.intent), System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global // and override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, mService.isNextTransitionForward(), profilerInfo)); // Set desired final state. final ActivityLifecycleItem lifecycleItem; // Set ResumeActivityItem to the expected state of the Activity if (andResume) {lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward()); } else { lifecycleItem = PauseActivityItem.obtain(); } / / set to LifecycleStateRequest clientTransaction. SetLifecycleStateRequest (lifecycleItem); / / the Schedule, / process/call to App mService getLifecycleManager () scheduleTransaction (clientTransaction); } catch (RemoteException e) {if (r.launchfailed) {// This is the second time we failed -- finish activity // and give up. Slog.e(TAG, "Second failure launching " + r.intent.getComponent().flattenToShortString() + ", giving up", e); mService.appDiedLocked(app); stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, "2nd-crash", false); return false; } // This is the first time we failed -- restart process and // retry. r.launchFailed = true; app.activities.remove(r); throw e; } } finally { endDeferResume(); } // omit return true; }Copy the code

Method creates a ClientTransaction object, adds LaunchActivityItem and ResumeActivityItem, and sends them to the APP process for processing. I’ve already done that in Pause, so I’m not going to do that and finally I’m going to do the LaunchActivityItem first, call its execute method, execute creates an ActivityClientRecord object, Then call the handleLaunchActivity method of the ActivityThread and pass in the ActivityClientRecord

OnCreate processing

ActivityThread.handleLaunchActivity

// /frameworks/base/core/java/android/app/ActivityThread.java public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { // If we are getting ready to gc after going to the background, UnscheduleGcIdler (); well // We are back active so skip it. mSomeActivitiesChanged = true; if (r.profilerInfo ! = null) { mProfiler.setProfiler(r.profilerInfo); mProfiler.startProfiling(); } // Make sure we are running with the most recent config. handleConfigurationChanged(null, null); if (localLOGV) Slog.v( TAG, "Handling launch of " + r); // Initialize before creating the activity if (! ThreadedRenderer.sRendererDisabled) { GraphicsEnvironment.earlyInitEGL(); } WindowManagerGlobal.initialize(); Final Activity A = performLaunchActivity(r, customIntent); if (a ! = null) { r.createdConfig = new Configuration(mConfiguration); reportSizeConfigurations(r); if (! r.activity.mFinished && pendingActions ! = null) { pendingActions.setOldState(r.state); pendingActions.setRestoreInstanceState(true); pendingActions.setCallOnPostCreate(true); } } else { // If there was an error, for any reason, tell the activity manager to stop us. try { ActivityManager.getService() .finishActivity(r.token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } return a; }Copy the code

Look at the implementation of performLaunchActivity

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.patinfo, Context.CONTEXT_INCLUDE_CODE); } // Get ComponentName ComponentName Component = r.i.nten.getComponent (); If (component == null) {// The intent is not set, ComponentName component = R.i.nten.resolveActivity (PackageManagerService) mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity ! = null) {// If the Activity has an alias (targetActivity attribute), Use the targetActivity build the ComponentName component = new the ComponentName (state Richard armitage ctivityInfo. PackageName, r.activityInfo.targetActivity); } / / get ContextImpl instance ContextImpl appContext = createBaseContextForActivity (r); Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); / / by reflecting instantiate the Activity Activity. = mInstrumentation newActivity (cl, component getClassName (), r.i ntent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); if (r.state ! = null) { r.state.setClassLoader(cl); } } catch (Exception e) { if (! mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to instantiate activity " + component + ": " + e.toString(), e); Try {}} / / get LoadedApk cache of Application objects (in the App process startup instantiation) Application App = r.p ackageInfo. MakeApplication (false, mInstrumentation); if (localLOGV) Slog.v(TAG, "Performing launch of " + r); if (localLOGV) Slog.v( TAG, r + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + r.packageInfo.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir()); if (activity ! = null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (r.overrideConfig ! = null) { config.updateFrom(r.overrideConfig); } if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); Window window = null; if (r.mPendingRemoveWindow ! = null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; } / / the Activity assigned to ContextImpl mOuterContex, make its holding the Activity of reference appContext. SetOuterContext (Activity); Attach (appContext, this, getInstrumentation(), r.toy, R.I.dent, app, R.I.ntent, 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; int theme = r.activityInfo.getThemeResource(); if (theme ! = 0) {// Set the theme activity.setTheme(theme); } activity.mCalled = false; Persistable if (r.isspersistable ()) { Will trigger the two parameters of onCreate lifecycle callback mInstrumentation. CallActivityOnCreate (activity, r.s Tate, r.p ersistentState); } else {/ / trigger a parameter onCreate callback mInstrumentation. CallActivityOnCreate (activity, r.s Tate); } if (! activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not  call through to super.onCreate()"); } r.activity = activity; } // Update the state in ActivityClientRecord r.setState(ON_CREATE); // Save ActivityClientRecord mActivities.put(r.token, r); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (! mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to start activity " + component + ": " + e.toString(), e); } } return activity; }Copy the code

Get ComponentName. Instantiate ContextImpl 3. 4. Trigger the onCreate lifecycle callback, The mLifecycleState member in the ActivityClientRecord is set to ON_CREATE. After the LaunchActivityItem is processed, the ResumeActivityItem, From the executeLifecycleState method of TransactionExecutor, which you may have seen during Pause, the Activity state is ON_CREATE, But the expected state stored in ResumeActivityItem is ON_RESUME, and in cycleToPath the handleStartActivity method is called first to handle the Activity start phase

OnStart processing

ActivityThread.handleStartActivity

// /frameworks/base/core/java/android/app/ActivityThread.java @Override public void handleStartActivity(ActivityClientRecord r, PendingTransactionActions pendingActions) { final Activity activity = r.activity; if (r.activity == null) { // TODO(lifecycler): What do we do in this case? return; } if (! r.stopped) { throw new IllegalStateException("Can't start activity that is not stopped."); } if (r.activity.mFinished) { // TODO(lifecycler): How can this happen? return; } // Start // In the Instrumentation call Activity onStart lifecycle callback method activity.performStart("handleStartActivity"); // Set the life cycle state to ON_START r.setState(ON_START); if (pendingActions == null) { // No more work to do. return; } // Restore instance state if (pendingActions.shouldRestoreInstanceState()) { if (r.isPersistable()) { if (r.state ! = null || r.persistentState ! = null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); } } else if (r.state ! = null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } // Call postOnCreate() if (pendingActions.shouldCallOnPostCreate()) { activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnPostCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnPostCreate(activity, r.state); } if (! activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not  call through to super.onPostCreate()"); }}}Copy the code

The above method calls the onStart lifecycle method and sets the Activity’s lifecycle state to ON_START to continue the handleResumeActivity

OnResume processing

ActivityThread.handleResumeActivity

// /frameworks/base/core/java/android/app/ActivityThread.java @Override public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged = true; // TODO pushes resumeArgs into the activity for consideration Then call the onResume lifecycle method final ActivityClientRecord r = performResumeActivity(Token, finalStateRequest, Reason); if (r == null) { // We didn't actually resume the activity, so skipping any follow-up actions. return; } // This is a DecorView, viewrotimpl, WindowManager initialization, register the window with WindowManagerService, set the view tree to see r.netidle = mNewActivities;  mNewActivities = r; if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r); // Add an idle message to the current thread looper.myQueue ().addidleHandler (new Idler()); }Copy the code

If the Activity is started for the first time, DecorView, ViewRootImpl, and WindowManager initialization are required. Register the window with WindowManagerService and make the view tree visible. The first time an Activity starts, it is visible only after onResume, not partially after onStart

Finally, an idle message Idler is added to the message queue in the current thread Looper. When there is no message processing in the message queue, its queueIdle method is called. In queueIdle, AMS’s activityIdle method is called through IActivityManager

OnStop processing

APP process by activityIdle method notice AMS target Activity of resume operation is completed, which will be based on corresponding ActivityStack token, calls its activityIdleInternalLocked method

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) { if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token); ArrayList<ActivityRecord> finishes = null; ArrayList<UserState> startingUsers = null; int NS = 0; int NF = 0; boolean booting = false; boolean activityRemoved = false; ActivityRecord r = ActivityRecord.forTokenLocked(token); // omit // get the ActivityRecord collection paused, ActivityPaused will be followed by mStopngActivityies and // Atomically retrieve all of the other things to do.final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r, true /* remove */, processPausingActivities); NS = stops ! = null ? stops.size() : 0; if ((NF = mFinishingActivities.size()) > 0) { finishes = new ArrayList<>(mFinishingActivities); / / mFinishingActivities saved already stop waiting for finish mFinishingActivities ActivityRecord collection. The clear (); } if (mStartingUsers.size() > 0) { startingUsers = new ArrayList<>(mStartingUsers); mStartingUsers.clear(); } // Stop any activities that are scheduled to do so but have been // waiting for the next one to start. for (int i = 0;  i < NS; I ++) {// Stop or finish the ActivityRecord, 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); }}} // omit return r; }Copy the code

Take a look at stopActivityLocked and get the ActivityRecord that you saved and wait to stop or finish

ActivityStack.stopActivityLocked

///frameworks/base/services/core/java/com/android/server/am/ActivityStack.java final void stopActivityLocked(ActivityRecord r) { if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + r); if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) ! = 0 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) ! = 0) { if (! r.finishing) { if (! shouldSleepActivities()) { if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r); if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, "stop-no-history", false)) { // If {@link requestFinishActivityLocked} returns {@code true}, // {@link adjustFocusedActivityStack} would have been already called. r.resumeKeyDispatchingLocked(); return; } } else { if (DEBUG_STATES) Slog.d(TAG_STATES, "Not finishing noHistory " + r + " on stop because we're just sleeping"); } } } if (r.app ! = null && r.app.thread ! = null) { adjustFocusedActivityStack(r, "stopActivity"); r.resumeKeyDispatchingLocked(); try { r.stopped = false; if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPING: " + r + " (stop requested)"); r.setState(STOPPING, "stopActivityLocked"); if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Stopping visible=" + r.visible + " for " + r); if (! r.visible) { r.setVisible(false); } EventLogTags.writeAmStopActivity( r.userId, System.identityHashCode(r), r.shortComponentName); // Transaction wrapped by StopActivityItem, Process scheduling to App mService. GetLifecycleManager () scheduleTransaction (of state Richard armitage pp thread, state Richard armitage ppToken, StopActivityItem.obtain(r.visible, r.configChangeFlags)); if (shouldSleepOrShutDownActivities()) { r.setSleeping(true); MSG = mhandler. obtainMessage(STOP_TIMEOUT_MSG, r); mHandler.sendMessageDelayed(msg, STOP_TIMEOUT); } catch (Exception e) { // Maybe just ignore exceptions here... if the process // has crashed, our death notification will clean things // up. Slog.w(TAG, "Exception thrown during pause", e); // Just in case, assume it to be stopped. r.stopped = true; if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + r); r.setState(STOPPED, "stopActivityLocked"); if (r.deferRelaunchUntilPaused) { destroyActivityLocked(r, true, "stop-except"); }}}}Copy the code

StopActivityLocked sends ClientTransaction to the corresponding APP process (the Activity that was previously paused), The StopActivityItem execute method is then called, which calls the ActivityThread handleStopActivity method

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) { final ActivityClientRecord r = mActivities.get(token); r.activity.mConfigChangeFlags |= configChanges; Final StopInfo StopInfo = new StopInfo(); // The onStop lifecycle callback method will be called, PerformStopActivityInner (r, stopInfo, show, true /* saveState */, finalStateRequest, reason); if (localLOGV) Slog.v( TAG, "Finishing stop of " + r + ": show=" + show + " win=" + r.window); updateVisibility(r, show); // Make sure any pending writes are now committed. if (! r.isPreHoneycomb()) { QueuedWork.waitToFinish(); } stopInfo.setActivity(r); stopInfo.setState(r.state); stopInfo.setPersistentState(r.persistentState); / / to save stopInfo added to pendingActions pendingActions setStopInfo (stopInfo); mSomeActivitiesChanged = true; }Copy the code

This method creates StopInfo to hold parameters related to the stop procedure, then calls the performStopActivityInner method, sets the state to ON_STOP, and calls the onSveInstanceState callback method as appropriate, After executing the StopActivityItem method, the postExecute method is executed, and within this method the reportStop method of ActivityThread is called

ActivityThread.reportStop

// /frameworks/base/core/java/android/app/ActivityThread.java @Override public void reportStop(PendingTransactionActions  pendingActions) { mH.post(pendingActions.getStopInfo()); }Copy the code

Here, take the previously saved StopInfo from pendingActions and switch to the main thread for execution. StopInfo inherits from Runnable and triggers its run method

PendingTransactionActions.StopInfo.run

// /frameworks/base/core/java/android/app/servertransaction/PendingTransactionActions.java @Override public void run() {  // Tell activity manager we have been stopped. try { if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + mActivity); // TODO(lifecycler): Home Use interface callback AMS. / / call the AMS ActivityStopped method notice AMS ActivityManager. GetService () ActivityStopped ( mActivity.token, mState, mPersistentState, mDescription); } catch (RemoteException ex) { // Dump statistics about bundle to help developers debug final LogWriter writer = new LogWriter(Log.WARN, TAG); final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); pw.println("Bundle stats:"); Bundle.dumpStats(pw, mState); pw.println("PersistableBundle stats:"); Bundle.dumpStats(pw, mPersistentState); if (ex instanceof TransactionTooLargeException && mActivity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {  Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex); return; } throw ex.rethrowFromSystemServer(); }}Copy the code

AMS’s activityStopped method finds the corresponding ActivityRecord based on the token and calls its activityStoppedLocked method

ActivityRecord.activityStoppedLocked

// /frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java final void activityStoppedLocked(Bundle  newIcicle, PersistableBundle newPersistentState, CharSequence description) { final ActivityStack stack = getStack(); if (mState ! = STOPPING) { Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this); stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this); return; } if (newPersistentState ! = null) { persistentState = newPersistentState; service.notifyTaskPersisterLocked(task, false); } if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle); if (newIcicle ! = null) { // If icicle is null, this is happening due to a timeout, so we haven't really saved // the state. icicle = newIcicle; haveState = true; launchCount = 0; updateTaskDescription(description); } if (! stopped) { if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)"); stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this); stopped = true; setState(STOPPED, "activityStoppedLocked"); mWindowContainerController.notifyAppStopped(); if (finishing) { clearOptionsLocked(); } else { if (deferRelaunchUntilPaused) { stack.destroyActivityLocked(this, true /* removeFromApp */, "stop-config"); mStackSupervisor.resumeFocusedStackTopActivityLocked(); } else { mStackSupervisor.updatePreviousProcessLocked(this); }}}}Copy the code

Here completes the stop operation, and notify the AMS, start the whole process will be over, and, of course, a variety of conditions can be analyzed, such as the destruction of, return to operation, here not analyzed one by one, mainly is to understand the process and understand the thinking, to facilitate the related problems, has a better processing method, You know your enemy and you know yourself in a hundred battles

conclusion

Finally, summarize the startup process

  1. First the APP initiates the startActivity request
  2. Through a series of calls to AMS’s startActivityAsUser method
  3. Call ActivityStartController obtainStarter, set all the launch parameters, return a ActivityStarter object, at the same time perform the execute method
  4. ActivityStarter’s startActivityMayWait method is then called to resolve the ActivityInfo corresponding to the Intent. Get the foreground Tas that started the Activity and start the Activity with startActivity and process the result
  5. StartActivityUnchecked is called in startActivity to handle the Activity startup mode. After setting the corresponding task and bringing it to the foreground, To start the corresponding Activity by calling ActivityStack. StartActivityLocked Activity to create a Task for the new open, And to save the Task in ActivityRecord then call ActivityStackSupervisor. ResumeFocusedStackTopActivityLocked, Will call to ActivityStack. ResumeTopActivityInnerLocked method
  6. ActivityStack. ResumeTopActivityInnerLocked first half through ActivityStack. StartPausingLocked to pause the current running Activity, Ultimately perform ActivityThread handlePauseActivity
  7. Call AMS’s activityPaused to notify the Activity Pause that it has finished
  8. AMS will eventually call ActivityStack.com pletePauseLocked credits to the pause ActivityRecord ActivityStackSupervisor mStoppingActivities members (ArrayLi St), used to stop and finish the stop and finish operations
  9. When an Activity on Pause after the operation, in ActivityStack. ResumeTopActivityInnerLocked bottom half, according to need to confirm whether you need to create new processes
  10. Need is initiated by AMS ActivityManagerService startProcessLocked, eventually to the Zygote hatching process, fock new processes, creating a successful call AMS attachApplication method after notification process start to finish
  11. When AMS receives that the APP process has started, it calls realStartActivityLocked to start the Activity that was held up while waiting for the target process to start
  12. Call ActivityThread performLaunchActivity, instantiation ContextImpl, through reflection instantiate the target Activity, trigger onCreate lifecycle callback, set the life cycle state to ON_CREATE
  13. Call ActivityThread handleStartActivity method, trigger the onStart lifecycle methods, and sets the Activity state of life cycle to ON_START
  14. Call ActivityThread handleResumeActivity method, trigger onResume lifecycle methods, sets the status to ON_RESUME, if the current Activity is your first time, Initialize DecorView, ViewRootImpl, and WindowManager, register Windows with WindowManagerService, and set view tree visibility
  15. APP process by activityIdle method notice AMS target Activity of resume operation is completed, the final will be called to ActivityThread handleStopActivity method, and set the status to ON_STOP trigger onStop life cycle
  16. AMS’s ActivityStopped method is called to notify AMS
  17. AMS’s activityStopped method finds the corresponding ActivityRecord based on the token and calls its activityStoppedLocked method