Startup Process Analysis


preface

This submission activity is in progress, and the prizes will be issued by Huazhang Company of China Machine Press. Thank Frank for his contribution and support. The submission activity is still going on, please pay attention

Welfare activities

The book donation activity jointly sponsored by Android Institute and China Machine Press Huazhang company is in progress. Please click the link to participate

The body of the

Writing in the front

This article is based on Android 10 version of the source code, from the Activity start method startActivity as the entry to analyze the whole process. This article covers only Framework code

Introduction to the classes involved

  • Instrumentation is responsible for invoking activities and Application lifecycles.
  • ActivityTaskManagerService be responsible for the management and scheduling Activity, etc. New in android10
  • ActivityManagerService is responsible for managing four components and processes, including life cycle and state transitions.
  • ActivityTaskManagerInternal ActivityTaskManagerService provides an abstract class, the real implementation in ActivityTaskManagerService# LocalService
  • ActivityThread manages the execution of the main thread in the application process
  • ActivityStackSupervisor is responsible for managing all Activity stacks
  • TransactionExecutor performs ClientTransaction
  • ClientLifecycleManager Management calls for the lifecycle

The flow chart is as follows

The initiating

We usually start an Activity with startActivity

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

@Override
public void startActivity(Intent intent) {
    this.startActivity(intent, null);
}

@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    if(options ! = null) { startActivityForResult(intent, -1, options); }else {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
}

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
    startActivityForResult(intent, requestCode, null);
}

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if(ar ! = null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); }if (requestCode >= 0) {
            // If this start is requesting a result, we can avoid making
            // the activity visible until the result is received.  Setting
            // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
            // activity hidden during this time, to avoid flickering.
            // This can only be done when a result is requested because
            // that guarantees we will get information back when the
            // activity is finished, no matter what happens to it.
            mStartedActivity = true;
        }
        cancelInputsAndStartExitTransition(options);
        // TODO Consider clearing/flushing other event sources and events for child windows.
    } else{/ /... }} Public void activityFromChild (@nonnull Activity child, @requiresperMission Intent Intent, int requestCode) { startActivityFromChild(child, intent, requestCode, null); } public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { options = transferSpringboardActivityOptions(options); Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, child, intent, requestCode, options);if(ar ! = null) { mMainThread.sendActivityResult( mToken, child.mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } cancelInputsAndStartExitTransition(options); }Copy the code

When an Activity is started using startActivity, it ends up calling startActivityForResult. If it is started for the first time, mParent will be null and will call Instrumentation#execStartActivity. Instrumentation#execStartActivity instrumentactivity instrumentactivity instrumentactivity

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) { IApplicationThread whoThread = (IApplicationThread) contextThread; Uri referrer = target ! = null ? target.onProvideReferrer() : null;if(referrer ! = null) { intent.putExtra(Intent.EXTRA_REFERRER, referrer); }if(mActivityMonitors ! = null) { synchronized (mSync) { final int N = mActivityMonitors.size();for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                ActivityResult result = null;
                if (am.ignoreMatchingSpecificIntents()) {
                    result = am.onStartActivity(intent);
                }
                if(result ! = null) { am.mHits++;return result;
                } else if (am.match(who, null, intent)) {
                    am.mHits++;
                    if (am.isBlocking()) {
                        return requestCode >= 0 ? am.getResult() : null;
                    }
                    break; } } } } try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); int result = ActivityTaskManager.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;
}
Copy the code

Finally, ActivityTaskManager#getService is called to get IActivityTaskManager, which is an IPC call, The server is ActivityTaskManagerService IActivityTaskManager, So ActivityTaskManager. GetService (). StartActivity final call is IActivityTaskManager server is ActivityTaskManagerService# startActivity

\frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.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) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions,
            UserHandle.getCallingUserId());
}

@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
            true /*validateIncomingUser*/);
}

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("startActivityAsUser");

    userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
    // TODO: Switch to user app stacks here.
    return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setMayWait(userId)
            .execute();
}
Copy the code

Is ActivityStartController getActivityStartController get. You get ActivityStarter with ActivityStartController#obtainStarter. ActivityStarter#execute is eventually called

frameworks\base\services\core\java\com\android\server\wm\ActivityStarter.java

int execute() {
    try {
        // TODO(b/64750076): Look into passing request directly to these methods to allow
        // for transactional diffs and preprocessing.
        if (mRequest.mayWait) {
            return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                    mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
                    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, mRequest.allowBackgroundActivityStart);
        } else {
            returnstartActivity(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, mRequest.allowBackgroundActivityStart); } } finally { onExecutionComplete(); }}Copy the code

The assignment of mRequest.mayWait is setMayWait in startActivityAsUser, where true is passed in. So startActivityMayWait

frameworks\base\services\core\java\com\android\server\wm\ActivityStarter.java

private int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, int requestRealCallingPid, int requestRealCallingUid,
        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, boolean allowBackgroundActivityStart) { ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0 /* matchFlags */, computeResolveFilterUid( callingUid, realCallingUid, mRequest.filterCallingUid)); / /... Final ActivityRecord[] outRecord = new ActivityRecord[1]; 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, allowBackgroundActivityStart); Binder.restoreCallingIdentity(origId); / /... Omit codereturn res;
    }
}

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, boolean allowBackgroundActivityStart) { mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent); int err = ActivityManager.START_SUCCESS; // Pull the optional Ephemeral Installer-only bundle out of the options early. final Bundle verificationBundle = options ! = null ? options.popAppVerificationBundle() : null; / /... Omit code mService. OnStartActivitySetDidAppSwitch (); mController.doPendingActivityLaunches(false);

    final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true/ *doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity);
    mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outActivity[0]);
    return res;
}

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity, boolean restrictedBgActivity) {
    int result = START_CANCELED;
    final ActivityStack startedActivityStack;
    try {
        mService.mWindowManager.deferSurfaceLayout();
        result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, doResume, options, inTask, outActivity, restrictedBgActivity); } finally { //... Omit code mService. MWindowManager. ContinueSurfaceLayout (); } postStartActivityProcessing(r, result, startedActivityStack);return result;
}
Copy the code

Will call startActivity startActivityMayWait, calling startActivity overloading, call postStartActivityProcessing finally. There’s an important call to startActivityUnchecked, so let’s look at the code

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity, boolean restrictedBgActivity) {
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor, restrictedBgActivity); / /... Omit code mRootActivityContainer. SendPowerHintForLaunchStartIfNeeded (false /* forceSend */, mStartActivity);

    mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
            mOptions);
    if (mDoResume) {
        final ActivityRecord topTaskActivity =
                mStartActivity.getTaskRecord().topRunningActivityLocked();
        if(! mTargetStack.isFocusable() || (topTaskActivity ! = null && topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) { mTargetStack.getDisplay().mDisplayContent.executeAppTransition(); }else {
            if(mTargetStack.isFocusable() && ! mRootActivityContainer.isTopDisplayFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked"); } mRootActivityContainer.resumeFocusedStacksTopActivities( mTargetStack, mStartActivity, mOptions); }}else if(mStartActivity ! = null) { mSupervisor.mRecentTasks.add(mStartActivity.getTaskRecord()); } mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack); mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(), preferredWindowingMode, mPreferredDisplayId, mTargetStack);return START_SUCCESS;
}
Copy the code

Through the comments we can see that would go RootActivityContainer# resumeFocusedStacksTopActivities.

frameworks\base\services\core\java\com\android\server\wm\RootActivityContainer.java

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

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

    boolean result = false;
    if(targetStack ! = null && (targetStack.isTopStackOnDisplay() || getTopDisplayFocusedStack() == targetStack)) { result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); }for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        boolean resumedOnDisplay = false;
        final ActivityDisplay display = mActivityDisplays.get(displayNdx);
        for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = display.getChildAt(stackNdx);
            final ActivityRecord topRunningActivity = stack.topRunningActivityLocked();
            if(! stack.isFocusableAndVisible() || topRunningActivity == null) {continue;
            }
            if (stack == targetStack) {
                // Simply update the result for targetStack because the targetStack had
                // already resumed in above. We don't want to resume it again, especially in // some cases, it would cause a second launch failure if app process was dead. resumedOnDisplay |= result; continue; } if (display.isTopStack(stack) && topRunningActivity.isState(RESUMED)) { // Kick off any lingering app transitions form  the MoveTaskToFront operation, // but only consider the top task and stack on that display. stack.executeAppTransition(targetOptions); } else { resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target); } } if (! resumedOnDisplay) { // In cases when there are no valid activities (e.g. device just booted or launcher // crashed) it's possible that nothing was resumed on a display. Requesting resume
            // of top activity in focused stack explicitly will make sure that at least home
            // activity is started and resumed, and no recursion occurs.
            final ActivityStack focusedStack = display.getFocusedStack();
            if(focusedStack ! = null) { focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); }}}return result;
}
Copy the code

Then call ActivityStack# resumeTopActivityUncheckedLocked

frameworks\base\services\core\java\com\android\server\wm\ActivityStack.java

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    if (mInResumeTopActivity) {
        // Don't even start recursing. return false; } boolean result = false; try { // Protect against recursion. mInResumeTopActivity = true; result = resumeTopActivityInnerLocked(prev, options); final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */); if (next == null || ! next.canTurnScreenOn()) { checkReadyForSleep(); } } finally { mInResumeTopActivity = false; } return result; } boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { //... Omit code Boolean pausing = getDisplay(). PauseBackStacks (userLeaving, next, false); if (mResumedActivity ! = null) { if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Pausing " + mResumedActivity); pausing |= startPausingLocked(userLeaving, false, next, false); } / /... Omit code if (next-.attachedToProcess ()) {try {final ClientTransaction = ClientTransaction.obtain(next.app.getThread(), next.appToken); // Deliver all pending results. ArrayList
      
        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, true /* resume */)); } // 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.mUserId, System.identityHashCode(next), next.getTaskRecord().taskId, next.shortComponentName); next.sleeping = false; mService.getAppWarningsLocked().onResumeActivity(next); next.app.setPendingUiCleanAndForceProcessStateUpTo(mService.mTopProcessState); next.clearOptionsLocked(); transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.getReportedProcState(), getDisplay().mDisplayContent.isNextTransitionForward())); mService.getLifecycleManager().scheduleTransaction(transaction); } catch (Exception e) { //... Omit code mStackSupervisor. StartSpecificActivityLocked (next, true, false); 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); } if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next); mStackSupervisor.startSpecificActivityLocked(next, true, true); } return true; } final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, boolean pauseImmediately) { //... Omit the code mservice.updatecpuStats (); if (prev.attachedToProcess()) { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev); try { EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev), prev.shortComponentName, "userLeaving=" + userLeaving); mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), 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; } / /... Omit code}
      Copy the code

OnPause call

ResumeTopActivityInnerLocked invokes startPausingLocked pause, we come to the core code

mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,prev.configChangeFlags, pauseImmediately));
Copy the code

Here is mService ActivityTaskManagerService, getLifecycleManager ClientLifecycleManager returns

frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java

ClientLifecycleManager getLifecycleManager() {
    return mLifecycleManager;
}
Copy the code

ClientLifecycleManager#scheduleTransaction what do we do

frameworks\base\services\core\java\com\android\server\wm\ClientLifecycleManager.java

void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken,
        @NonNull ActivityLifecycleItem stateRequest) throws RemoteException {
    final ClientTransaction clientTransaction = transactionWithState(client, activityToken,
            stateRequest);
    scheduleTransaction(clientTransaction);
}

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
    if(! (client instanceof Binder)) { // If client is not an instance of Binder - it's a remote call and at this point it is // safe to recycle the object. All objects used for local calls will be recycled after // the transaction is executed on client in ActivityThread. transaction.recycle(); } } private static ClientTransaction transactionWithState(@NonNull IApplicationThread client, @NonNull IBinder activityToken, @NonNull ActivityLifecycleItem stateRequest) { final ClientTransaction clientTransaction = ClientTransaction.obtain(client, activityToken); clientTransaction.setLifecycleStateRequest(stateRequest); return clientTransaction; } frameworks\base\core\java\android\app\servertransaction\ClientTransaction.java public void schedule() throws RemoteException { mClient.scheduleTransaction(this); }Copy the code

IApplicationThread# scheduleTransaction. The Server side of IApplicationThread is ActivityThread#ApplicationThread. So ApplicationThread#scheduleTransaction is eventually called.

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

@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
}
Copy the code

Instead of overwriting the parent class’s scheduleTransaction, ActivityThread will eventually call the parent class’s ClientTransactionHandler#scheduleTransaction.

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

void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
Copy the code

SendMessage is an abstract method that is implemented in ActivityThread.

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

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) {
    if (DEBUG_MESSAGES) {
        Slog.v(TAG,
                "SCHEDULE " + what + "" + mH.codeToString(what) + ":" + arg1 + "/" + obj);
    }
    Message msg = Message.obtain();
    msg.what = what;
    msg.obj = obj;
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    if (async) {
        msg.setAsynchronous(true);
    }
    mH.sendMessage(msg);
}
Copy the code

The final call is mH. SendMessage (MSG), mH is an inner class of H, an inherited Handler of ActivityThread.

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

case EXECUTE_TRANSACTION:
    final ClientTransaction transaction = (ClientTransaction) msg.obj;
    mTransactionExecutor.execute(transaction);
    if (isSystem()) {
        // Client transactions inside system process are recycled on the client side
        // instead of ClientLifecycleManager to avoid being cleared before this
        // message is handled.
        transaction.recycle();
    }
    // TODO(lifecycler): Recycle locally scheduled transactions.
    break;
Copy the code

H after receiving the message will be called mTransactionExecutor. Execute (transaction). MTransactionExecutor stands for TransactionExecutor

\frameworks\base\core\java\android\app\servertransaction\TransactionExecutor.java public void execute(ClientTransaction transaction) { //... Omit the code executeCallbacks(Transaction); executeLifecycleState(transaction); mPendingActions.clear();if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "End resolving transaction");
}

public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    if (callbacks == null || callbacks.isEmpty()) {
        // 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);
        if (DEBUG_RESOLVER) Slog.d(TAG, tId(transaction) + "Resolving callback: " + item);
        final int postExecutionState = item.getPostExecutionState();
        final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
                item.getPostExecutionState());
        if(closestPreExecutionState ! = UNDEFINED) { cycleToPath(r, closestPreExecutionState, transaction); } / /... Omit the code item.execute(mTransactionHandler, Token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); }}Copy the code

ClientTransactionItem#execute is eventually called. Let’s go back to the PauseActivityItem passed in above.

@Override
public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
    client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
            "PAUSE_ACTIVITY_ITEM");
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
Copy the code

Let’s take a look at what client actually implements

\frameworks\base\core\java\android\app\servertransaction\TransactionExecutor.java public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) { mTransactionHandler = clientTransactionHandler;  } frameworks\base\core\java\android\app\ActivityThread.java private final TransactionExecutor mTransactionExecutor = new  TransactionExecutor(this);Copy the code

So the methods in ActivityThread are called. Let’s take a look at ActivityThread#handlePauseActivity.

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

        r.activity.mConfigChangeFlags |= configChanges;
        performPauseActivity(r, finished, reason, pendingActions);

        // Make sure any pending writes are now committed.
        if (r.isPreHoneycomb()) {
            QueuedWork.waitToFinish();
        }
        mSomeActivitiesChanged = true;
    }
}

final Bundle performPauseActivity(IBinder token, boolean finished, String reason,
        PendingTransactionActions pendingActions) {
    ActivityClientRecord r = mActivities.get(token);
    returnr ! = null ? performPauseActivity(r, finished, reason, pendingActions) : null; } private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason, PendingTransactionActions pendingActions) { //... Final Boolean shouldSaveState =! r.activity.mFinished && r.isPreHoneycomb();if(shouldSaveState) { callActivityOnSaveInstanceState(r); } performPauseActivityIfNeeded(r, reason); // Notify any outstanding on paused listeners ArrayList<OnActivityPausedListener> listeners; synchronized (mOnPauseListeners) { listeners = mOnPauseListeners.remove(r.activity); } int size = (listeners ! = null ? listeners.size() : 0);for(int i = 0; i < size; i++) { listeners.get(i).onPaused(r.activity); } / /... Omit codereturnshouldSaveState ? r.state : null; } private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) { //... Omit code reportTopResumedActivityChanged (r,false /* onTop */, "pausing");

    try {
        r.activity.mCalled = false;
        mInstrumentation.callActivityOnPause(r.activity);
        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);
}
Copy the code

Instrumentation#callActivityOnPause will be called

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

public void callActivityOnPause(Activity activity) {
    activity.performPause();
}

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

final void performPause() {
    dispatchActivityPrePaused();
    mDoReportFullyDrawn = false;
    mFragments.dispatchPause();
    mCalled = false;
    onPause();
    writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause");
    mResumed = false;
    if(! mCalled && getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.GINGERBREAD) { throw new SuperNotCalledException("Activity " + mComponent.toShortString() +
                " did not call through to super.onPause()");
    }
    dispatchActivityPostPaused();
}
Copy the code

The final onPause call to the activity.

The Activity of creating

Let’s go back to ActivityStack#startPausingLocked above after executing. Invokes the mStackSupervisor. StartSpecificActivityLocked (next, true, true)

\frameworks\base\services\core\java\com\android\server\wm\ActivityStackSupervisor.java

void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
    // Is this activity's application already running? final WindowProcessController wpc = mService.getProcessController(r.processName, r.info.applicationInfo.uid); boolean knownToBeDead = false; if (wpc ! = null && wpc.hasThread()) { try { realStartActivityLocked(r, wpc, 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. knownToBeDead = true; } / /... try { // Post message to start process to avoid possible deadlock of calling into AMS with the // ATMS lock held. final Message msg = PooledLambda.obtainMessage( ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName, r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent()); mService.mH.sendMessage(msg); } finally { Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }}Copy the code

If processes and threads exist, realStartActivityLocked is called directly. If not, mservice.mh.sendMessage (MSG) is called. MH is the inner class H of the ActivityThread we mentioned above.

boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
        boolean andResume, boolean checkConfig) throws RemoteException {

        try {
            if(! proc.hasThread()) { throw new RemoteException(); } // Create activity launch transaction. final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.appToken); final DisplayContent dc = r.getDisplay().mDisplayContent; 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, proc.getReportedProcState(), r.icicle, r.persistentState, results, newIntents, dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(), r.assistToken)); // Set desired final state. final ActivityLifecycleItem lifecycleItem;if (andResume) {
                lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
            } else{ lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // Schedule transaction. mService.getLifecycleManager().scheduleTransaction(clientTransaction); / /... } catch (RemoteException e) { //... } } finally { endDeferResume(); } / /... // Perform OOM scoring after the activity state isset, so the process can be updated with // the latest state. proc.onStartActivity(mService.mTopProcessState, r.info); / /... Omit codereturn true;
}
Copy the code

We look at ClientTransaction and add the LaunchActivityItem callBack to it. . Then set the Request life cycle, and finally call mService getLifecycleManager () scheduleTransaction, it has already been said before, we will call 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, mAssistToken);
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
Copy the code

The essence is to call ActivityThread#handleLaunchActivity

@Override public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { //... Omit code handleConfigurationChanged (null, null); / /... Omit code WindowManagerGlobal. The initialize (); // Hint the GraphicsEnvironment that an activity is launching on the process. GraphicsEnvironment.hintActivityLaunch(); 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, forany reason, tell the activity manager to stop us. try { ActivityTaskManager.getService() .finishActivity(r.token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }}returna; } private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; / /... 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 { Application app = r.packageInfo.makeApplication(false, mInstrumentation); / /... Omit codeif(activity ! = null) { //... Omit code 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, r.assistToken); / /... Omit codeif (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else{ mInstrumentation.callActivityOnCreate(activity, r.state); } r.activity = activity; } r.setState(ON_CREATE); / /... } catch (SuperNotCalledException e) {throw e; } catch (Exception e) { //... }return activity;
}
Copy the code

Instrumentation#callActivityOnCreate Instrumentation#callActivityOnCreate Instrumentation#callActivityOnCreate Start the Activity. TransactionExecutor#executeCallbacks The system will execute TransactionExecutor#executeLifecycleState.

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

private void executeLifecycleState(ClientTransaction transaction) {
    final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
    if (lifecycleItem == null) {
        // No lifecycle request, return early.
        return;
    }

    final IBinder token = transaction.getActivityToken();
    final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
    if (DEBUG_RESOLVER) {
        Slog.d(TAG, tId(transaction) + "Resolving lifecycle state: "
                + lifecycleItem + " for activity: "
                + getShortActivityName(token, mTransactionHandler));
    }

    if (r == null) {
        // Ignore requests for non-existent client records for now.
        return;
    }

    // Cycle to the state right before the final requested state.
    cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);

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

private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState,
        ClientTransaction transaction) {
    final int start = r.getLifecycleState();
    if (DEBUG_RESOLVER) {
        Slog.d(TAG, tId(transaction) + "Cycle activity: "
                + getShortActivityName(r.token, mTransactionHandler)
                + " from: " + getStateName(start) + " to: " + getStateName(finish)
                + " excludeLastState: " + excludeLastState);
    }
    final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
    performLifecycleSequence(r, path, transaction);
}

private void performLifecycleSequence(ActivityClientRecord r, IntArray path,
        ClientTransaction transaction) {
    final int size = path.size();
    for (int i = 0, state; i < size; i++) {
        state = path.get(i);
        if (DEBUG_RESOLVER) {
            Slog.d(TAG, tId(transaction) + "Transitioning activity: "
                    + getShortActivityName(r.token, mTransactionHandler)
                    + " to state: " + getStateName(state));
        }
        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); }}}Copy the code

Finish by lifecycleItem. GetTargetState (), this is in setLifecycleStateRequest assignment, the code is as follows:

\frameworks\base\services\core\java\com\android\server\wm\ActivityStackSupervisor.java

final ActivityLifecycleItem lifecycleItem;
if (andResume) {
    lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
} else {
    lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
Copy the code

You can see that onCreate is called back

Creating a new process

If the process does not exist, it will go to the create process ActivityThread#handleStartActivity and ActivityThread#handleResumeActivity. In the end, onStart and onResume are called through Instrumentation. I will not repeat it here.

final Message msg = PooledLambda.obtainMessage(
        ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
        r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
Copy the code

The implementation of ActivityManagerInternal class ActivityManagerService#LocalService

@Override
public void startProcess(String processName, ApplicationInfo info,
        boolean knownToBeDead, String hostingType, ComponentName hostingName) {
    try {
        synchronized (ActivityManagerService.this) {
            startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
                    new HostingRecord(hostingType, hostingName),
                    false /* allowWhileBooting */, false /* isolated */,
                    true /* keepIfLarge */);
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
}

final ProcessRecord startProcessLocked(String processName,
    ApplicationInfo info, boolean knownToBeDead, int intentFlags,
    HostingRecord hostingRecord, boolean allowWhileBooting,
    boolean isolated, boolean keepIfLarge) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
        hostingRecord, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
        null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
        null /* crashHandler */);
}
Copy the code

The create thread is created with ProcessList#startProcessLocked

frameworks\base\services\core\java\com\android\server\am\ProcessList.java

@GuardedBy("mService") final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { //... Omit code checkSlow(startTime,"startProcess: stepping in to startProcess");
    final boolean success = startProcessLocked(app, hostingRecord, abiOverride);
    checkSlow(startTime, "startProcess: done starting proc!");
    return success ? app : null;
}

@GuardedBy("mService")
final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
        String abiOverride) {
    return startProcessLocked(app, hostingRecord,
            false/ *disableHiddenApiChecks */, false /* mountExtStorageFull */, abiOverride);
}

boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
        boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride) { //... Omit code Final String entryPoint ="android.app.ActivityThread"; / /... Omit codereturn startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
                runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                startTime);
    } catch (RuntimeException e) {
        Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e);

        // Something went very wrong while trying to start this process; one
        // common case is when the package is frozen due to an active
        // upgrade. To recover, clean up any active bookkeeping related to
        // starting this process. (We already invoked this method once when
        // the package was initially frozen through KILL_APPLICATION_MSG, so
        // it doesn't hurt to use it again.) mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); return false; } } boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { app.pendingStart = true; app.killedByAm = false; app.removed = false; app.killed = false; if (app.startSeq ! = 0) { Slog.wtf(TAG, "startProcessLocked processName:" + app.processName + " with non-zero startSeq:" + app.startSeq); } if (app.pid ! = 0) { Slog.wtf(TAG, "startProcessLocked processName:" + app.processName + " with non-zero pid:" + app.pid); } final long startSeq = app.startSeq = ++mProcStartSeqCounter; app.setStartParams(uid, hostingRecord, seInfo, startTime); app.setUsingWrapper(invokeWith ! = null || SystemProperties.get("wrap." + app.processName) ! = null); mPendingStarts.put(startSeq, app); if (mService.mConstants.FLAG_PROCESS_START_ASYNC) { if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES, "Posting procStart msg for " + app.toShortString()); mService.mProcStartHandler.post(() -> { try { final Process.ProcessStartResult startResult = startProcess(app.hostingRecord, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); synchronized (mService) { handleProcessStartedLocked(app, startResult, startSeq); } } catch (RuntimeException e) { synchronized (mService) { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); mPendingStarts.remove(startSeq); app.pendingStart = false; mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); }}}); return true; } else { try { final Process.ProcessStartResult startResult = startProcess(hostingRecord, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper, startSeq, false); } catch (RuntimeException e) { Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e); app.pendingStart = false; mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, app.userId, "start failure"); } return app.pid > 0; } } private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, 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); checkSlow(startTime, "startProcess: asking zygote to start proc"); final Process.ProcessStartResult startResult; if (hostingRecord.usesWebviewZygote()) { startResult = startWebView(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } else if (hostingRecord.usesAppZygote()) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); startResult = appZygote.getProcess().start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, /*useUsapPool=*/ false, 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, app.info.packageName, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } checkSlow(startTime, "startProcess: returned from zygote!" ); return startResult; } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } \frameworks\base\core\java\android\os|Process.java public static ProcessStartResult start(@NonNull final String processClass, @Nullable final String niceName, int uid, int gid, @Nullable int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, @Nullable String[] zygoteArgs) { return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, /*useUsapPool=*/ true, zygoteArgs);Copy the code

ZYGOTE_PROCESS means ZygoteProcess, let’s move on to ZygoteProcess#start

public final Process.ProcessStartResult start(@NonNull final String processClass,
                                              final String niceName,
                                              int uid, int gid, @Nullable int[] gids,
                                              int runtimeFlags, int mountExternal,
                                              int targetSdkVersion,
                                              @Nullable String seInfo,
                                              @NonNull String abi,
                                              @Nullable String instructionSet,
                                              @Nullable String appDataDir,
                                              @Nullable String invokeWith,
                                              @Nullable String packageName,
                                              boolean useUsapPool,
                                              @Nullable String[] zygoteArgs) {
    // TODO (chriswailes): Is there a better place to check this value?
    if (fetchUsapPoolEnabledPropWithMinInterval()) {
        informZygotesOfUsapPoolStatus();
    }

    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
                packageName, useUsapPool, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
        Log.e(LOG_TAG,
                "Starting VM process through Zygote failed");
        throw new RuntimeException(
                "Starting VM process through Zygote failed", ex);
    }
}

private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
                                                  @Nullable final String niceName,
                                                  final int uid, final int gid,
                                                  @Nullable final int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  @Nullable String seInfo,
                                                  @NonNull String abi,
                                                  @Nullable String instructionSet,
                                                  @Nullable String appDataDir,
                                                  @Nullable String invokeWith,
                                                  boolean startChildZygote,
                                                  @Nullable String packageName,
                                                  boolean useUsapPool,
                                                  @Nullable String[] extraArgs)
                                                  throws ZygoteStartFailedEx {
    ArrayList<String> argsForZygote = new ArrayList<>();

    // --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");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
        argsForZygote.add("--mount-external-full");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
        argsForZygote.add("--mount-external-installer");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
        argsForZygote.add("--mount-external-legacy");
    }

    argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

    // --setgroups is a comma-separated list
    if(gids ! = null && gids.length > 0) { StringBuilder sb = new StringBuilder(); sb.append("--setgroups=");

        int sz = gids.length;
        for (int i = 0; i < sz; i++) {
            if(i ! = 0) { sb.append(', ');
            }
            sb.append(gids[i]);
        }

        argsForZygote.add(sb.toString());
    }

    if(niceName ! = null) { argsForZygote.add("--nice-name=" + niceName);
    }

    if(seInfo ! = null) { argsForZygote.add("--seinfo=" + seInfo);
    }

    if(instructionSet ! = null) { argsForZygote.add("--instruction-set=" + instructionSet);
    }

    if(appDataDir ! = null) { argsForZygote.add("--app-data-dir=" + appDataDir);
    }

    if(invokeWith ! = null) { argsForZygote.add("--invoke-with");
        argsForZygote.add(invokeWith);
    }

    if (startChildZygote) {
        argsForZygote.add("--start-child-zygote");
    }

    if(packageName ! = null) { argsForZygote.add("--package-name=" + packageName);
    }

    argsForZygote.add(processClass);

    if(extraArgs ! = null) { Collections.addAll(argsForZygote, extraArgs); } synchronized(mLock) { // The USAP pool can not be usedif the application will not use the systems graphics
        // driver.  If that driver is requested use the Zygote application start path.
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                          useUsapPool,
                                          argsForZygote);
    }
}

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    try {
        attemptConnectionToPrimaryZygote();

        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }

        if(mZygoteSecondarySocketAddress ! = null) { // The primary zygote didn't match. Try the secondary. attemptConnectionToSecondaryZygote(); if (secondaryZygoteState.matches(abi)) { return secondaryZygoteState; } } } catch (IOException ioe) { throw new ZygoteStartFailedEx("Error connecting to zygote", ioe); } throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); } private void attemptConnectionToPrimaryZygote() throws IOException { if (primaryZygoteState == null || primaryZygoteState.isClosed()) { primaryZygoteState = ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress); maybeSetApiBlacklistExemptions(primaryZygoteState, false); maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState); maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState); } } /** * Creates a ZygoteState for the secondary zygote if it doesn't exist or has been disconnected.
 */
@GuardedBy("mLock")
private void attemptConnectionToSecondaryZygote() throws IOException {
    if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
        secondaryZygoteState =
                ZygoteState.connect(mZygoteSecondarySocketAddress,
                        mUsapPoolSecondarySocketAddress);

        maybeSetApiBlacklistExemptions(secondaryZygoteState, false); maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState); maybeSetHiddenApiAccessStatslogSampleRate(secondaryZygoteState); }}Copy the code

As you can see, a new thread is eventually forked through the Zygote communication. The details can be seen in the ZygoteProcess, which won’t be explained too much. The ActivityThread#main method is called after the process is created.

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

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

    // Install selective syscall interception
    AndroidOs.install();

    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser();

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

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

    Looper.prepareMainLooper();

    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    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(); thread.attach(false, startSeq);

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

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

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

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

We can see the creation of the main thread Looper and the beginning of the rotation. There’s an ActivityThread#attach inside. Here system passes false, so it branches up.

private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if(! system) { android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        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 { ActivityTaskManager.getService().releaseSomeActivities(mAppThread); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); }}}}); }else {
        // Don't set application object here -- if the system crashes, // we can't display an alert, we just want to die die die.
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());
        try {
            mInstrumentation = new Instrumentation();
            mInstrumentation.basicInit(this);
            ContextImpl context = ContextImpl.createAppContext(
                    this, getSystemContext().mPackageInfo);
            mInitialApplication = context.mPackageInfo.makeApplication(true, null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }

    ViewRootImpl.ConfigChangedCallback configChangedCallback
            = (Configuration globalConfig) -> {
        synchronized (mResourcesManager) {
            // We need to apply this change to the resources immediately, because upon returning
            // the view hierarchy will be informed about it.
            if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                    null /* compat */)) {
                updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                        mResourcesManager.getConfiguration().getLocales());

                // This actually changed the resources! Tell everyone about it.
                if(mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(globalConfig)) { mPendingConfiguration = globalConfig; sendMessage(H.CONFIGURATION_CHANGED, globalConfig); }}}}; ViewRootImpl.addConfigCallback(configChangedCallback); }Copy the code

ActivityManager#getService returns IActivityManager, which really calls ActivityManagerService#attachApplication

@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);
    }
}

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    ProcessRecord app;
    long startTime = SystemClock.uptimeMillis();
    long bindApplicationTimeMillis; / /... // If this application record is still attached to a previous // process, clean it up now.if(app.thread ! = null) { handleAppDiedLocked(app,true.true);
    }

    final String processName = app.processName;
    try {
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        mProcessList.startProcessLocked(app,
                new HostingRecord("link fail", processName));
        return false;
    }
    checkTime(startTime, "attachApplicationLocked: before bindApplication");

    try {
        checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
        bindApplicationTimeMillis = SystemClock.elapsedRealtime();
        mAtmInternal.preBindApplication(app.getWindowProcessController());
        final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
        if(app.isolatedEntryPoint ! = null) { // This is an isolated processwhich should just call an entry point instead of
            // being bound to an application.
            thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
        } else if(instr2 ! = null) { thread.bindApplication(processName, appInfo, providers, instr2.mClass, profilerInfo, instr2.mArguments, instr2.mWatcher, instr2.mUiAutomationConnection,testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.isPersistent(), new Configuration(app.getWindowProcessController().getConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions); }else {
            thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                    null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.isPersistent(), new Configuration(app.getWindowProcessController().getConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions); }if(profilerInfo ! = null) { profilerInfo.closeFd(); profilerInfo = null; } // Make app active after binding application or client may be running requests (e.g // starting activities) before it is ready. app.makeActive(thread, mProcessStats); checkTime(startTime,"attachApplicationLocked: immediately after bindApplication");
        mProcessList.updateLruProcessLocked(app, false, null);
        checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked"); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); } catch (Exception e) { //... Omit code} / / 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...
    if (normalMode) {
        try {
            didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }

    // Find any services that should be running in this process...
    if(! badApp) { try { didSomething |= mServices.attachApplicationLocked(app, processName); checkTime(startTime,"attachApplicationLocked: after mServices.attachApplicationLocked");
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
            badApp = true;
        }
    }

    // Check if a next-broadcast receiver is in this process...
    if(! badApp && isPendingBroadcastProcessLocked(pid)) { try { didSomething |= sendPendingBroadcastsLocked(app); checkTime(startTime,"attachApplicationLocked: after sendPendingBroadcastsLocked");
        } catch (Exception e) {
            // If the app died trying to launch the receiver we declare it 'bad'
            Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
            badApp = true;
        }
    }

    // Check whether the next backup agent is in this process...
    if(! badApp && backupTarget ! = null && backupTarget.app == app) {if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
                "New app is backup target, launching agent for " + app);
        notifyPackageUse(backupTarget.appInfo.packageName,
                         PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
        try {
            thread.scheduleCreateBackupAgent(backupTarget.appInfo,
                    compatibilityInfoForPackage(backupTarget.appInfo),
                    backupTarget.backupMode, backupTarget.userId);
        } catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
            badApp = true; }}if (badApp) {
        app.kill("error during init".true);
        handleAppDiedLocked(app, false.true);
        return false;
    }

    if(! didSomething) { updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); checkTime(startTime,"attachApplicationLocked: after updateOomAdjLocked");
    }
    return true;
}
Copy the code

We can see the processing of activities, services, BroadcastReceiver, which focuses on the processing of activities. The key code is mAtmInternal#attachApplication. MAtmInternal ActivityTaskManagerInternal.

mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
Copy the code

In ActivityTaskManagerService# start set in

\frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java

private void start() {
    LocalServices.addService(ActivityTaskManagerInternal.class, mInternal);
}

public ActivityTaskManagerService(Context context) {
    mContext = context;
    mFactoryTest = FactoryTest.getMode();
    mSystemThread = ActivityThread.currentActivityThread();
    mUiContext = mSystemThread.getSystemUiContext();
    mLifecycleManager = new ClientLifecycleManager();
    mInternal = new LocalService();
    GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
}
Copy the code

So it’s the call is the inner class ActivityTaskManagerService LocalService# attachApplication

\frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java

@Override
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
    synchronized (mGlobalLockWithoutBoost) {
        return mRootActivityContainer.attachApplication(wpc);
    }
}

\frameworks\base\services\core\java\com\android\server\wm\RootActivityContainer.java

boolean attachApplication(WindowProcessController app) throws RemoteException {
    final String processName = app.mName;
    boolean didSomething = false;
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        final ActivityDisplay display = mActivityDisplays.get(displayNdx);
        final ActivityStack stack = display.getFocusedStack();
        if(stack ! = null) { 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.mUid == activity.info.applicationInfo.uid
                        && processName.equals(activity.processName)) {
                    try {
                        if (mStackSupervisor.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) { ensureActivitiesVisible(null, 0,false /* preserve_windows */);
    }
    return didSomething;
}
Copy the code

And you can see here we’re calling activitystackcontainer #realStartActivityLocked. If you are familiar with this, you will call this directly if the process exists. See the previous analysis for details.

conclusion

The startup process of an Activity is very complicated. Here we just sort out the general process, and there are many details that need to be studied by code. All I’m doing here is setting the stage. Source code involves a lot, we track the flow of time do not be too limited and details, otherwise you will fall into an endless loop, we can first grasp the general process, and then go back to see the details

Solemnly declare

This article is issued by Android Institute, the original author is Frank, copyright belongs to the original author, without permission, prohibit reprint, infringement will be investigated!

The original link: www.jianshu.com/p/b78a38c85…