美文网首页Android 开发进阶
Android10.0(Q)中 Activity finish(

Android10.0(Q)中 Activity finish(

作者: JeffreyWorld | 来源:发表于2020-11-26 16:48 被阅读0次

    一个 Activity 为 FirstActivity finish()后,进入新的 Activity 为 SecondActivity ,生命周期里的源码到底是个怎样的实现流程呢。下面我们一起来剖析一下。
    在 Android 10.0的源码中:

    > Activity.java
        /**
         * Call this when your activity is done and should be closed.  The
         * ActivityResult is propagated back to whoever launched you via
         * onActivityResult().
         */
        public void finish() {
            finish(DONT_FINISH_TASK_WITH_ACTIVITY);
        }
    

    重载了带参数的 finish() 方法。参数是 DONT_FINISH_TASK_WITH_ACTIVITY ,含义也很直白,不会销毁 Activity 所在的任务栈。

    > Activity.java
        /**
         * Finishes the current activity and specifies whether to remove the task associated with this
         * activity.
         */
        private void finish(int finishTask) {
            // mParent 一般为 null,在 ActivityGroup 中会使用到
            if (mParent == null) {
                int resultCode;
                Intent resultData;
                synchronized (this) {
                    resultCode = mResultCode;
                    resultData = mResultData;
                }
                if (false) Log.v(TAG, "Finishing self: token=" + mToken);
                try {
                    if (resultData != null) {
                        resultData.prepareToLeaveProcess(this);
                    }
                    // Binder 调用 AMS.finishActivity()
                    if (ActivityTaskManager.getService()
                            .finishActivity(mToken, resultCode, resultData, finishTask)) {
                        mFinished = true;
                    }
                } catch (RemoteException e) {
                    // Empty
                }
            } else {
                mParent.finishFromChild(this);
            }
    
            // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
            // be restored now.
            if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
                getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_RESTORE,
                        mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
            }
        }
    

    这里的 mParent 大多数情况下都是 null ,不需要考虑 else 分支的情况。其中 Binder 调用了 ATMS.finishActivity() 方法。
    Google 将 Android 的版本更新到10.0版本(sdk-29)之后,Acitivity的启动流程相比之前的版本发生了些变化,首先最大的变化是我们常见的用来管理 Activity 的AMS,变成了现在的ATMS(ActivityTaskManagerService)。

    > IActivityTaskManager.aidl
    boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask);
    
    >ActivityTaskManagerService.java
        /**
         * This is the internal entry point for handling Activity.finish().
         *
         * @param token The Binder token referencing the Activity we want to finish.
         * @param resultCode Result code, if any, from this Activity.
         * @param resultData Result data (Intent), if any, from this Activity.
         * @param finishTask Whether to finish the task associated with this Activity.
         *
         * @return Returns true if the activity successfully finished, or false if it is still running.
         */
        @Override
        public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
                int finishTask) {
            // Refuse possible leaked file descriptors
            if (resultData != null && resultData.hasFileDescriptors()) {
                throw new IllegalArgumentException("File descriptors passed in Intent");
            }
    
            synchronized (mGlobalLock) {
                ActivityRecord r = ActivityRecord.isInStackLocked(token);
                if (r == null) {
                    return true;
                }
                // Keep track of the root activity of the task before we finish it
                final TaskRecord tr = r.getTaskRecord();
                ActivityRecord rootR = tr.getRootActivity();
                if (rootR == null) {
                    Slog.w(TAG, "Finishing task with all activities already finished");
                }
                // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
                // finish.
                if (getLockTaskController().activityBlockedFromFinish(r)) {
                    return false;
                }
    
                // TODO: There is a dup. of this block of code in ActivityStack.navigateUpToLocked
                // We should consolidate.
                if (mController != null) {
                    // Find the first activity that is not finishing.
                    final ActivityRecord next = r.getActivityStack().topRunningActivityLocked(token, 0);
                    if (next != null) {
                        // ask watcher if this is allowed
                        boolean resumeOK = true;
                        try {
                            resumeOK = mController.activityResuming(next.packageName);
                        } catch (RemoteException e) {
                            mController = null;
                            Watchdog.getInstance().setActivityController(null);
                        }
    
                        if (!resumeOK) {
                            Slog.i(TAG, "Not finishing activity because controller resumed");
                            return false;
                        }
                    }
                }
    
                // note down that the process has finished an activity and is in background activity
                // starts grace period
                if (r.app != null) {
                    r.app.setLastActivityFinishTimeIfNeeded(SystemClock.uptimeMillis());
                }
    
                final long origId = Binder.clearCallingIdentity();
                try {
                    boolean res;
                    final boolean finishWithRootActivity =
                            finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
                    if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
                            || (finishWithRootActivity && r == rootR)) {
                        // If requested, remove the task that is associated to this activity only if it
                        // was the root activity in the task. The result code and data is ignored
                        // because we don't support returning them across task boundaries. Also, to
                        // keep backwards compatibility we remove the task from recents when finishing
                        // task with root activity.
                        res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
                                finishWithRootActivity, "finish-activity");
                        if (!res) {
                            Slog.i(TAG, "Removing task failed to finish activity");
                        }
                        // Explicitly dismissing the activity so reset its relaunch flag.
                        r.mRelaunchReason = RELAUNCH_REASON_NONE;
                    } else {
                        res = tr.getStack().requestFinishActivityLocked(token, resultCode,
                                resultData, "app-request", true);
                        if (!res) {
                            Slog.i(TAG, "Failed to finish by app-request");
                        }
                    }
                    return res;
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }
        }
    
    > ActivityManagerService.java
        /**
         * This is the internal entry point for handling Activity.finish().
         *
         * @param token The Binder token referencing the Activity we want to finish.
         * @param resultCode Result code, if any, from this Activity.
         * @param resultData Result data (Intent), if any, from this Activity.
         * @param finishTask Whether to finish the task associated with this Activity.
         *
         * @return Returns true if the activity successfully finished, or false if it is still running.
         */
        @Override
        public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
                int finishTask) {
            // token 持有 ActivityRecord 的弱引用
            return mActivityTaskManager.finishActivity(token, resultCode, resultData, finishTask);
        }
    

    注意方法参数中的 token 对象是 ActivityRecord 的静态内部类,它持有外部 ActivityRecord 的弱引用。继承自 IApplicationToken.Stub ,是一个 Binder 对象。ActivityRecord 就是对当前 Activity 的具体描述,包含了 Activity 的所有信息。
    传入的 finishTask() 方法的参数是 DONT_FINISH_TASK_WITH_ACTIVITY,所以接着会调用 ActivityStack.requestFinishActivityLocked() 方法。

    > ActivityRecord.java 
        static class Token extends IApplicationToken.Stub {
            private final WeakReference<ActivityRecord> weakActivity; //持有外部 ActivityRecord 的弱引用
            private final String name;
    
            Token(ActivityRecord activity, Intent intent) {
                weakActivity = new WeakReference<>(activity);
                name = intent.getComponent().flattenToShortString();
            }
    
            private static @Nullable ActivityRecord tokenToActivityRecordLocked(Token token) {
                if (token == null) {
                    return null;
                }
                ActivityRecord r = token.weakActivity.get();
                if (r == null || r.getActivityStack() == null) {
                    return null;
                }
                return r;
            }
    
            @Override
            public String toString() {
                StringBuilder sb = new StringBuilder(128);
                sb.append("Token{");
                sb.append(Integer.toHexString(System.identityHashCode(this)));
                sb.append(' ');
                sb.append(weakActivity.get());
                sb.append('}');
                return sb.toString();
            }
    
            @Override
            public String getName() {
                return name;
            }
        }
    
    > ActivityStack.java
        /**
         * @return Returns true if the activity is being finished, false if for
         * some reason it is being left as-is.
         */
        final boolean requestFinishActivityLocked(IBinder token, int resultCode,
                Intent resultData, String reason, boolean oomAdj) {
            ActivityRecord r = isInStackLocked(token);
            if (DEBUG_RESULTS || DEBUG_STATES) Slog.v(TAG_STATES,
                    "Finishing activity token=" + token + " r="
                    + ", result=" + resultCode + ", data=" + resultData
                    + ", reason=" + reason);
            if (r == null) {
                return false;
            }
    
            finishActivityLocked(r, resultCode, resultData, reason, oomAdj);
            return true;
        }
    

    最后调用的是一个重载的 finishActivityLocked() 方法。

    > ActivityStack.java
       /**
         * @return Returns true if this activity has been removed from the history
         * list, or false if it is still in the list and will be removed later.
         */
        final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
                String reason, boolean oomAdj, boolean pauseImmediately) {
            if (r.finishing) { //重复 finishing 的情况
                Slog.w(TAG, "Duplicate finish request for " + r);
                return false;
            }
    
            mWindowManager.deferSurfaceLayout();
            try {
            // 标记 r.finishing = true,
            // 前面会做重复 finish 的检测就是依赖这个值
                r.makeFinishingLocked();
                final TaskRecord task = r.getTaskRecord();
                EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                        r.mUserId, System.identityHashCode(r),
                        task.taskId, r.shortComponentName, reason);
                final ArrayList<ActivityRecord> activities = task.mActivities;
                final int index = activities.indexOf(r);
                if (index < (activities.size() - 1)) {
                    task.setFrontOfTask();
                    if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
                        // If the caller asked that this activity (and all above it)
                        // be cleared when the task is reset, don't lose that information,
                        // but propagate it up to the next activity.
                        ActivityRecord next = activities.get(index+1);
                        next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                    }
                }
                // 暂停事件分发
                r.pauseKeyDispatchingLocked();
    
                adjustFocusedActivityStack(r, "finishActivity");
                // 处理 activity result
                finishActivityResultsLocked(r, resultCode, resultData);
    
                final boolean endTask = index <= 0 && !task.isClearingToReuseTask();
                final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
                // mResumedActivity 就是当前 Activity,会进入此分支
                if (mResumedActivity == r) {
                    if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                            "Prepare close transition: finishing " + r);
                    if (endTask) {
                        mService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
                                task.getTaskInfo());
                    }
                    getDisplay().mDisplayContent.prepareAppTransition(transit, false);
    
                    // Tell window manager to prepare for this one to be removed.
                    r.setVisibility(false);
    
                    if (mPausingActivity == null) {
                        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
                        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                                "finish() => pause with userLeaving=false");
                        // 开始 pause mResumedActivity
                        startPausingLocked(false, false, null, pauseImmediately);
                    }
    
                    if (endTask) {
                        mService.getLockTaskController().clearLockedTask(task);
                    }
                } else if (!r.isState(PAUSING)) {
                    // If the activity is PAUSING, we will complete the finish once
                    // it is done pausing; else we can just directly finish it here.
                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
                    if (r.visible) {
                        prepareActivityHideTransitionAnimation(r, transit);
                    }
    
                    final int finishMode = (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE
                            : FINISH_AFTER_PAUSE;
                    final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj,
                            "finishActivityLocked") == null;
    
                    // The following code is an optimization. When the last non-task overlay activity
                    // is removed from the task, we remove the entire task from the stack. However,
                    // since that is done after the scheduled destroy callback from the activity, that
                    // call to change the visibility of the task overlay activities would be out of
                    // sync with the activitiy visibility being set for this finishing activity above.
                    // In this case, we can set the visibility of all the task overlay activities when
                    // we detect the last one is finishing to keep them in sync.
                    if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {
                        for (ActivityRecord taskOverlay : task.mActivities) {
                            if (!taskOverlay.mTaskOverlay) {
                                continue;
                            }
                            prepareActivityHideTransitionAnimation(taskOverlay, transit);
                        }
                    }
                    return removedActivity;
                } else {
                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
                }
    
                return false;
            } finally {
                mWindowManager.continueSurfaceLayout();
            }
        }
    
        void makeFinishingLocked() {
            if (finishing) {
                return;
            }
            finishing = true;
            if (stopped) {
                clearOptionsLocked();
            }
    
            if (mAtmService != null) {
                mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
            }
        }
    

    调用 finish 之后肯定是要先 pause 当前 Activity,没毛病。接着看 startPausingLocked() 方法。

    ActivityStack.java
        /**
         * Start pausing the currently resumed activity.  It is an error to call this if there
         * is already an activity being paused or there is no resumed activity.
         *
         * @param userLeaving True if this should result in an onUserLeaving to the current activity.
         * @param uiSleeping True if this is happening with the user interface going to sleep (the
         * screen turning off).
         * @param resuming The activity we are currently trying to resume or null if this is not being
         *                 called as part of resuming the top activity, so we shouldn't try to instigate
         *                 a resume here if not null.
         * @param pauseImmediately True if the caller does not want to wait for the activity callback to
         *                         complete pausing.
         * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
         * it to tell us when it is done.
         */
        final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
                ActivityRecord resuming, boolean pauseImmediately) {
            if (mPausingActivity != null) {
                Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
                        + " state=" + mPausingActivity.getState());
                if (!shouldSleepActivities()) {
                    // Avoid recursion among check for sleep and complete pause during sleeping.
                    // Because activity will be paused immediately after resume, just let pause
                    // be completed by the order of activity paused from clients.
                    completePauseLocked(false, resuming);
                }
            }
            ActivityRecord prev = mResumedActivity;
    
            if (prev == null) {
              // 没有 onResume 的 Activity,不能执行 pause
                if (resuming == null) {
                    Slog.wtf(TAG, "Trying to pause when nothing is resumed");
                    mRootActivityContainer.resumeFocusedStacksTopActivities();
                }
                return false;
            }
    
            if (prev == resuming) {
                Slog.wtf(TAG, "Trying to pause activity that is in process of being resumed");
                return false;
            }
    
            if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSING: " + prev);
            else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
            mPausingActivity = prev;
            mLastPausedActivity = prev;
            mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                    || (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
            // 设置当前 Activity 状态为 PAUSING
            prev.setState(PAUSING, "startPausingLocked");
            prev.getTaskRecord().touchActiveTime();
            clearLaunchTime(prev);
    
            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);
                    // 1. 通过 ClientLifecycleManager 分发生命周期事件
                    // 最终会向 H 发送 EXECUTE_TRANSACTION 事件
                    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;
            }
    
            // If we are not going to sleep, we want to ensure the device is
            // awake until the next activity is started.
            if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
                mStackSupervisor.acquireLaunchWakelock();
            }
            // mPausingActivity 在前面已经赋值,就是当前 Activity
            if (mPausingActivity != null) {
                // Have the window manager pause its key dispatching until the new
                // activity has started.  If we're pausing the activity just because
                // the screen is being turned off and the UI is sleeping, don't interrupt
                // key dispatch; the same activity will pick it up again on wakeup.
                if (!uiSleeping) {
                    prev.pauseKeyDispatchingLocked();
                } else if (DEBUG_PAUSE) {
                     Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off");
                }
    
                if (pauseImmediately) { // 这里是 false,进入 else 分支
                    // If the caller said they don't want to wait for the pause, then complete
                    // the pause now.
                    completePauseLocked(false, resuming);
                    return false;
    
                } else {
                    // 2. 发送一个延时 500ms 的消息,等待 pause 流程一点时间,最终会回调 activityPausedLocked() 方法
                    schedulePauseTimeout(prev);
                    return true;
                }
    
            } else {
                // This activity failed to schedule the
                // pause, so just treat it as being paused now.
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
                if (resuming == null) {
                    mRootActivityContainer.resumeFocusedStacksTopActivities();
                }
                return false;
            }
        }
    
        /**
         * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
         * this directly impacts the responsiveness seen by the user.
         */
        private void schedulePauseTimeout(ActivityRecord r) {
            final Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
            msg.obj = r;
            r.pauseTime = SystemClock.uptimeMillis();
            mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
        }
    

    这里面有两步重点操作。第一步是注释 1 处通过 ClientLifecycleManager 分发生命周期流程。第二步是发送一个延时 500ms 的消息,等待一下 onPause 流程。但是如果第一步中在 500ms 内已经完成了流程,则会取消这个消息。所以这两步的最终逻辑其实是一致的。这里就直接看第一步。

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

    ClientLifecycleManager 它会向主线程的 Handler H 发送 EXECUTE_TRANSACTION 事件,调用 XXXActivityItemexecute()postExecute() 方法。execute() 方法中会 Binder 调用
    ActivityThread 中对应的 handleXXXActivity() 方法。在这里就是 handlePauseActivity() 方法,其中会通过 Instrumentation.callActivityOnPause(r.activity) 方法回调 Activity.onPause()

    > Instrumentation.java
        /**
         * Perform calling of an activity's {@link Activity#onPause} method.  The
         * default implementation simply calls through to that method.
         * 
         * @param activity The activity being paused.
         */
        public void callActivityOnPause(Activity activity) {
            activity.performPause();
        }
    

    到这里,onPause() 方法就被执行了。但是流程没有结束,接着就该显示下一个 Activity 了。前面刚刚说过会调用 PauseActivityItemexecute()postExecute() 方法。execute() 方法回调了当前 Activity.onPause(),而 postExecute() 方法就是去寻找要显示的 Activity 。

    > PauseActivityItem.java
        @Override
        public void postExecute(ClientTransactionHandler client, IBinder token,
                PendingTransactionActions pendingActions) {
            if (mDontReport) {
                return;
            }
            try {
                // TODO(lifecycler): Use interface callback instead of AMS.
                ActivityTaskManager.getService().activityPaused(token);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    

    Binder 调用了 ActivityTaskManager.activityPaused() 方法。

    > IActivityTaskManager.aidl
    void activityPaused(in IBinder token);
    
    > ActivityTaskManagerService.java
        @Override
        public final void activityPaused(IBinder token) {
            final long origId = Binder.clearCallingIdentity();
            synchronized (mGlobalLock) {
                ActivityStack stack = ActivityRecord.getStackLocked(token);
                if (stack != null) {
                    stack.activityPausedLocked(token, false);
                }
            }
            Binder.restoreCallingIdentity(origId);
        }
    

    调用了 ActivityStack.activityPausedLocked() 方法。

    > ActivityStack.java
        final void activityPausedLocked(IBinder token, boolean timeout) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
                "Activity paused: token=" + token + ", timeout=" + timeout);
    
            final ActivityRecord r = isInStackLocked(token);
    
            if (r != null) {
                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); //标记1
                if (mPausingActivity == r) {
                    if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
                            + (timeout ? " (due to timeout)" : " (pause complete)"));
                    mService.mWindowManager.deferSurfaceLayout();
                    try {
                        //标记2
                        completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
                    } finally {
                        mService.mWindowManager.continueSurfaceLayout();
                    }
                    return;
                } else {
                    EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
                            r.mUserId, System.identityHashCode(r), r.shortComponentName,
                            mPausingActivity != null
                                ? mPausingActivity.shortComponentName : "(none)");
                    if (r.isState(PAUSING)) {
                        r.setState(PAUSED, "activityPausedLocked");
                        if (r.finishing) {
                            if (DEBUG_PAUSE) Slog.v(TAG,
                                    "Executing finish of failed to pause activity: " + r);
                            finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false,
                                    "activityPausedLocked");
                        }
                    }
                }
            }
            mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
        }
    

    上面有这么一行代码 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r) ,移除的就是之前延迟 500ms 的消息。接着看 completePauseLocked() 方法。

    > ActivityStack.java
        private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
            ActivityRecord prev = mPausingActivity;
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
    
            if (prev != null) {
                prev.setWillCloseOrEnterPip(false);
                final boolean wasStopping = prev.isState(STOPPING);
                // 设置状态为 PAUSED
                prev.setState(PAUSED, "completePausedLocked");
                if (prev.finishing) { // 1. finishing 为 true,进入此分支
                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
                    prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
                            "completePausedLocked");
                } else if (prev.hasProcess()) {
                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
                            + " wasStopping=" + wasStopping + " visible=" + prev.visible);
                    if (prev.deferRelaunchUntilPaused) {
                        // Complete the deferred relaunch that was waiting for pause to complete.
                        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
                        prev.relaunchActivityLocked(false /* andResume */,
                                prev.preserveWindowOnDeferredRelaunch);
                    } else if (wasStopping) {
                        // We are also stopping, the stop request must have gone soon after the pause.
                        // We can't clobber it, because the stop confirmation will not be handled.
                        // We don't need to schedule another stop, we only need to let it happen.
                        prev.setState(STOPPING, "completePausedLocked");
                    } else if (!prev.visible || shouldSleepOrShutDownActivities()) {
                        // Clear out any deferred client hide we might currently have.
                        prev.setDeferHidingClient(false);
                        // If we were visible then resumeTopActivities will release resources before
                        // stopping.
                        addToStopping(prev, true /* scheduleIdle */, false /* idleDelayed */,
                                "completePauseLocked");
                    }
                } else {
                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
                    prev = null;
                }
                // It is possible the activity was freezing the screen before it was paused.
                // In that case go ahead and remove the freeze this activity has on the screen
                // since it is no longer visible.
                if (prev != null) {
                    prev.stopFreezingScreenLocked(true /*force*/);
                }
                mPausingActivity = null;
            }
    
            if (resumeNext) {
                // 当前获取焦点的 ActivityStack
                final ActivityStack topStack = mRootActivityContainer.getTopDisplayFocusedStack();
                if (!topStack.shouldSleepOrShutDownActivities()) {
                    // 2. 恢复要显示的 activity
                    mRootActivityContainer.resumeFocusedStacksTopActivities(topStack, prev, null);
                } else {
                    checkReadyForSleep();
                    ActivityRecord top = topStack.topRunningActivityLocked();
                    if (top == null || (prev != null && top != prev)) {
                        // If there are no more activities available to run, do resume anyway to start
                        // something. Also if the top activity on the stack is not the just paused
                        // activity, we need to go ahead and resume it to ensure we complete an
                        // in-flight app switch.
                        mRootActivityContainer.resumeFocusedStacksTopActivities();
                    }
                }
            }
    
            if (prev != null) {
                prev.resumeKeyDispatchingLocked();
    
                if (prev.hasProcess() && prev.cpuTimeAtResume > 0) {
                    final long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume;
                    if (diff > 0) {
                        final Runnable r = PooledLambda.obtainRunnable(
                                ActivityManagerInternal::updateForegroundTimeIfOnBattery,
                                mService.mAmInternal, prev.info.packageName,
                                prev.info.applicationInfo.uid,
                                diff);
                        mService.mH.post(r);
                    }
                }
                prev.cpuTimeAtResume = 0; // reset it
            }
    
            // Notify when the task stack has changed, but only if visibilities changed (not just
            // focus). Also if there is an active pinned stack - we always want to notify it about
            // task stack changes, because its positioning may depend on it.
            if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause
                    || (getDisplay() != null && getDisplay().hasPinnedStack())) {
                mService.getTaskChangeNotificationController().notifyTaskStackChanged();
                mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
            }
    
            mRootActivityContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
        }
    

    这里分了两步走。注释1 处判断了 finishing 状态,还记得 finishing 在何处被赋值为 true 的吗?在 Activity.finish() -> AMS.finishActivity() -> ActivityStack.requestFinishActivityLocked() -> ActivityStack.finishActivityLocked() 方法中。所以接着调用的是 finishCurrentActivityLocked() 方法。注释2 处就是来显示应该显示的 Activity ,就不再追进去细看了。
    再跟到 finishCurrentActivityLocked() 方法中,看这名字,肯定是要 stop/destroy 没跑了。

    > ActivityStack.java
       /*
        * 把前面带过来的参数标出来
        * prev, FINISH_AFTER_VISIBLE, false,"completedPausedLocked"
        */
        final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj,
                String reason) {
            // First things first: if this activity is currently visible,
            // and the resumed activity is not yet visible, then hold off on
            // finishing until the resumed one becomes visible.
    
            // The activity that we are finishing may be over the lock screen. In this case, we do not
            // want to consider activities that cannot be shown on the lock screen as running and should
            // proceed with finishing the activity if there is no valid next top running activity.
            // Note that if this finishing activity is floating task, we don't need to wait the
            // next activity resume and can destroy it directly.
            final ActivityDisplay display = getDisplay();
            // 获取将要显示的栈顶 Activity
            final ActivityRecord next = display.topRunningActivity(true /* considerKeyguardState */);
            final boolean isFloating = r.getConfiguration().windowConfiguration.tasksAreFloating();
            // 1. mode 是 FINISH_AFTER_VISIBLE,进入此分支
            if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
                    && next != null && !next.nowVisible && !isFloating) {
                if (!mStackSupervisor.mStoppingActivities.contains(r)) {
                    // 加入到 mStackSupervisor.mStoppingActivities
                    addToStopping(r, false /* scheduleIdle */, false /* idleDelayed */,
                            "finishCurrentActivityLocked");
                }
                if (DEBUG_STATES) Slog.v(TAG_STATES,
                        "Moving to STOPPING: "+ r + " (finish requested)");
                // 设置状态为 STOPPING
                r.setState(STOPPING, "finishCurrentActivityLocked");
                if (oomAdj) {
                    mService.updateOomAdj();
                }
                return r;
            }
    
            // make sure the record is cleaned out of other places.
            mStackSupervisor.mStoppingActivities.remove(r);
            mStackSupervisor.mGoingToSleepActivities.remove(r);
            final ActivityState prevState = r.getState();
            if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
    
            r.setState(FINISHING, "finishCurrentActivityLocked");
    
            // Don't destroy activity immediately if the display contains home stack, although there is
            // no next activity at the moment but another home activity should be started later. Keep
            // this activity alive until next home activity is resumed then user won't see a temporary
            // black screen.
            final boolean noRunningStack = next == null && display.topRunningActivity() == null
                    && display.getHomeStack() == null;
            final boolean noFocusedStack = r.getActivityStack() != display.getFocusedStack();
            final boolean finishingInNonFocusedStackOrNoRunning = mode == FINISH_AFTER_VISIBLE
                    && prevState == PAUSED && (noFocusedStack || noRunningStack);
            // 下面的代码会执行 destroy 流程
            if (mode == FINISH_IMMEDIATELY
                    || (prevState == PAUSED
                        && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
                    || finishingInNonFocusedStackOrNoRunning
                    || prevState == STOPPING
                    || prevState == STOPPED
                    || prevState == ActivityState.INITIALIZING) {
                r.makeFinishingLocked();
                boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason);
    
                if (finishingInNonFocusedStackOrNoRunning) {
                    // Finishing activity that was in paused state and it was in not currently focused
                    // stack, need to make something visible in its place. Also if the display does not
                    // have running activity, the configuration may need to be updated for restoring
                    // original orientation of the display.
                    mRootActivityContainer.ensureVisibilityAndConfig(next, mDisplayId,
                            false /* markFrozenIfConfigChanged */, true /* deferResume */);
                }
                if (activityRemoved) {
                    mRootActivityContainer.resumeFocusedStacksTopActivities();
                }
                if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
                        "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
                        " destroy returned removed=" + activityRemoved);
                return activityRemoved ? null : r;
            }
    
            // Need to go through the full pause cycle to get this
            // activity into the stopped state and then finish it.
            if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
            mStackSupervisor.mFinishingActivities.add(r);
            r.resumeKeyDispatchingLocked();
            mRootActivityContainer.resumeFocusedStacksTopActivities();
            // If activity was not paused at this point - explicitly pause it to start finishing
            // process. Finishing will be completed once it reports pause back.
            if (r.isState(RESUMED) && mPausingActivity != null) {
                startPausingLocked(false /* userLeaving */, false /* uiSleeping */, next /* resuming */,
                        false /* dontWait */);
            }
            return r;
        }
    

    注释 1 处 mode 的值是 FINISH_AFTER_VISIBLE ,并且现在新的 Activity 还没有 onResume,所以 r.visible || r.nowVisiblenext != null && !next.nowVisible 都是成立的,并不会进入后面的 destroy 流程。虽然看到这还没得到想要的答案,但是起码是符合预期的。如果在这就直接 destroy 了,延迟 10s 才 onDestroy 的问题就无疾而终了。
    对于这些暂时还不销毁的 Activity 都执行了 addToStopping(r, false, false) 方法。我们继续追进去。

    > ActivityStack.java
        private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed,
                String reason) {
            if (!mStackSupervisor.mStoppingActivities.contains(r)) {
                EventLog.writeEvent(EventLogTags.AM_ADD_TO_STOPPING, r.mUserId,
                        System.identityHashCode(r), r.shortComponentName, reason);
                mStackSupervisor.mStoppingActivities.add(r);
            }
    
            // If we already have a few activities waiting to stop, then give up
            // on things going idle and start clearing them out. Or if r is the
            // last of activity of the last task the stack will be empty and must
            // be cleared immediately.
            //对 mStoppingActivities 的存储容量做了限制。超出限制可能会提前触发销毁流程
            boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
                    || (r.frontOfTask && mTaskHistory.size() <= 1);
            if (scheduleIdle || forceIdle) {
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle="
                        + forceIdle + "immediate=" + !idleDelayed);
                if (!idleDelayed) {
                    mStackSupervisor.scheduleIdleLocked();
                } else {
                    mStackSupervisor.scheduleIdleTimeoutLocked(r);
                }
            } else {
                checkReadyForSleep();
            }
        }
    

    这些在等待销毁的 Activity 被保存在了 ActivityStackSupervisor 的 mStoppingActivities 集合中,它是一个 ArrayList<ActivityRecord> 。
    整个 finish 流程就到此为止了。前一个 Activity 被保存在了ActivityStackSupervisor.mStoppingActivities 集合中,新的 Activity 被显示出来了。
    问题似乎进入了困境,什么时候回调 onStop/onDestroy 呢?其实这个才是根本问题。上面撸了一遍 finish() 并看不到本质,但是可以帮助我们形成一个完整的流程,这个一直是看 AOSP 最大的意义,帮助我们把零碎的上层知识形成一个完整的闭环

    回到正题来,在 Activity 跳转过程中,为了保证流畅的用户体验,只要前一个 Activity 与用户不可交互,即 onPause() 被回调之后,下一个 Activity 就要开始自己的生命周期流程了。所以
    onStop/onDestroy 的调用时间是不确定的,可能整整过了 10s 才回调。那么,到底是由谁来驱动 onStop/onDestroy 的执行呢?我们来看看下一个 Activity 的 onResume 过程。
    直接看 ActivityThread.handleResumeActivity() 方法,相信大家对生命周期的调用流程也很熟悉了。

    > 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 Push resumeArgs into the activity for consideration
            // 回调 onResume
            final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
            if (r == null) {
                // We didn't actually resume the activity, so skipping any follow-up actions.
                return;
            }
            if (mActivitiesToBeDestroyed.containsKey(token)) {
                // Although the activity is resumed, it is going to be destroyed. So the following
                // UI operations are unnecessary and also prevents exception because its token may
                // be gone that window manager cannot recognize it. All necessary cleanup actions
                // performed below will be done while handling destruction.
                return;
            }
    
            final Activity a = r.activity;
    
            if (localLOGV) {
                Slog.v(TAG, "Resume " + r + " started activity: " + a.mStartedActivity
                        + ", hideForNow: " + r.hideForNow + ", finished: " + a.mFinished);
            }
    
            final int forwardBit = isForward
                    ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
    
            // If the window hasn't yet been added to the window manager,
            // and this guy didn't finish itself or start another activity,
            // then go ahead and add the window.
            boolean willBeVisible = !a.mStartedActivity;
            if (!willBeVisible) {
                try {
                    willBeVisible = ActivityTaskManager.getService().willActivityBeVisible(
                            a.getActivityToken());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    // Normally the ViewRoot sets up callbacks with the Activity
                    // in addView->ViewRootImpl#setView. If we are instead reusing
                    // the decor view we have to notify the view root that the
                    // callbacks may have changed.
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        // 添加 decorView 到 WindowManager
                        wm.addView(decor, l);
                    } else {
                        // The activity will get a callback for this {@link LayoutParams} change
                        // earlier. However, at that time the decor will not be set (this is set
                        // in this method), so no action will be taken. This call ensures the
                        // callback occurs with the decor set.
                        a.onWindowAttributesChanged(l);
                    }
                }
    
                // If the window has already been added, but during resume
                // we started another activity, then don't yet make the
                // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }
    
            // Get rid of anything left hanging around.
            cleanUpPendingRemoveWindows(r, false /* force */);
    
            // The window is now visible if it has been added, we are not
            // simply finishing, and we are not starting another activity.
            if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
                if (r.newConfig != null) {
                    performConfigurationChangedForActivity(r, r.newConfig);
                    if (DEBUG_CONFIGURATION) {
                        Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig "
                                + r.activity.mCurrentConfig);
                    }
                    r.newConfig = null;
                }
                if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward=" + isForward);
                WindowManager.LayoutParams l = r.window.getAttributes();
                if ((l.softInputMode
                        & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                        != forwardBit) {
                    l.softInputMode = (l.softInputMode
                            & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
                            | forwardBit;
                    if (r.activity.mVisibleFromClient) {
                        ViewManager wm = a.getWindowManager();
                        View decor = r.window.getDecorView();
                        wm.updateViewLayout(decor, l);
                    }
                }
    
                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }
    
            r.nextIdle = mNewActivities;
            mNewActivities = r;
            if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r);
            // 主线程空闲时会执行 Idler
            Looper.myQueue().addIdleHandler(new Idler());
        }
    

    handleResumeActivity() 方法是整个 UI 显示流程的重中之重,它首先会回调 Activity.onResume() , 然后将 DecorView 添加到 Window 上,其中又包括了创建 ViewRootImpl,创建 Choreographer,与 WMS 进行 Binder 通信,注册 vsync 信号,执行measure/draw/layout。
    在完成最终的界面绘制和显示之后,有这么一句代码 Looper.myQueue().addIdleHandler(new Idler())IdleHandler 不知道大家是否熟悉,它提供了一种机制,当主线程消息队列空闲时,会执行 IdleHandler 的回调方法。至于怎么算 “空闲”,我们可以看一下 MessageQueue.next() 方法。

    >MessageQueue.java
        Message next() {
            // Return here if the message loop has already quit and been disposed.
            // This can happen if the application tries to restart a looper after quit
            // which is not supported.
            final long ptr = mPtr;
            if (ptr == 0) {
                return null;
            }
    
            int pendingIdleHandlerCount = -1; // -1 only during first iteration
            int nextPollTimeoutMillis = 0;
            for (;;) {
                if (nextPollTimeoutMillis != 0) {
                    Binder.flushPendingCommands();
                }
                // 阻塞方法,主要是通过 native 层的 epoll 监听文件描述符的写入事件来实现的。
                // 如果 nextPollTimeoutMillis = -1,一直阻塞不会超时。
                // 如果 nextPollTimeoutMillis = 0,不会阻塞,立即返回。
                // 如果 nextPollTimeoutMillis > 0,最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回。
                nativePollOnce(ptr, nextPollTimeoutMillis);
    
                synchronized (this) {
                    // Try to retrieve the next message.  Return if found.
                    final long now = SystemClock.uptimeMillis();
                    Message prevMsg = null;
                    Message msg = mMessages;
                    if (msg != null && msg.target == null) {
                        // Stalled by a barrier.  Find the next asynchronous message in the queue.
                       // msg.target == null表示此消息为消息屏障(通过postSyncBarrier方法发送来的)
                       // 如果发现了一个消息屏障,会循环找出第一个异步消息(如果有异步消息的话),所有同步消息都将忽略(平常发送的一般都是同步消息)
                        do {
                            prevMsg = msg;
                            msg = msg.next;
                        } while (msg != null && !msg.isAsynchronous());
                    }
                    if (msg != null) {
                        if (now < msg.when) {
                            // Next message is not ready.  Set a timeout to wake up when it is ready.
                            // 消息触发时间未到,设置下一次轮询的超时时间
                            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                        } else {
                            // Got a message.
                            // 得到 Message
                            mBlocked = false;
                            if (prevMsg != null) {
                                prevMsg.next = msg.next;
                            } else {
                                mMessages = msg.next;
                            }
                            msg.next = null;
                            if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                            msg.markInUse(); // 标记 FLAG_IN_USE
                            return msg;
                        }
                    } else {
                        // No more messages.
                        nextPollTimeoutMillis = -1;
                    }
    
                    // Process the quit message now that all pending messages have been handled.
                    if (mQuitting) {
                        dispose();
                        return null;
                    }
    
                    // If first time idle, then get the number of idlers to run.
                    // Idle handles only run if the queue is empty or if the first message
                    // in the queue (possibly a barrier) is due to be handled in the future.
                   /*
                    * 两个条件:
                    * 1. pendingIdleHandlerCount = -1
                    * 2. 此次取到的 mMessage 为空或者需要延迟处理
                    */
                    if (pendingIdleHandlerCount < 0
                            && (mMessages == null || now < mMessages.when)) {
                        pendingIdleHandlerCount = mIdleHandlers.size();
                    }
                    if (pendingIdleHandlerCount <= 0) {
                        // No idle handlers to run.  Loop and wait some more.
                        // 没有 idle handler 需要运行,继续循环
                        mBlocked = true;
                        continue;
                    }
    
                    if (mPendingIdleHandlers == null) {
                        mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                    }
                    mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
                }
    
                // Run the idle handlers.
                // We only ever reach this code block during the first iteration.
                // 下一次 next 时,pendingIdleHandlerCount 又会被置为 -1,不会导致死循环
                for (int i = 0; i < pendingIdleHandlerCount; i++) {
                    final IdleHandler idler = mPendingIdleHandlers[i];
                    mPendingIdleHandlers[i] = null; // release the reference to the handler
    
                    boolean keep = false;
                    try {
                        // 执行 Idler
                        keep = idler.queueIdle();
                    } catch (Throwable t) {
                        Log.wtf(TAG, "IdleHandler threw exception", t);
                    }
    
                    if (!keep) {
                        synchronized (this) {
                            mIdleHandlers.remove(idler);
                        }
                    }
                }
    
                // Reset the idle handler count to 0 so we do not run them again.
                // 将 pendingIdleHandlerCount 置零
                pendingIdleHandlerCount = 0;
    
                // While calling an idle handler, a new message could have been delivered
                // so go back and look again for a pending message without waiting.
                nextPollTimeoutMillis = 0;
            }
        }
    

    在正常的消息处理机制之后,额外对 IdleHandler 进行了处理。当本次取到的 Message 为空或者需要延时处理的时候,就会去执行 mIdleHandlers 数组中的 IdleHandler 对象。其中还有一些关于 pendingIdleHandlerCount 的额外逻辑来防止循环处理。
    所以,不出意外的话,当新的 Activity 完成页面绘制并显示之后,主线程就可以停下歇一歇,来执行 IdleHandler 了。再回来 handleResumeActivity() 中来,Looper.myQueue().addIdleHandler(new Idler()) ,这里的 IdlerIdleHandler 的一个具体实现类。

    >ActivityThread.java
        private class Idler implements MessageQueue.IdleHandler {
            @Override
            public final boolean queueIdle() {
                ActivityClientRecord a = mNewActivities;
                boolean stopProfiling = false;
                if (mBoundApplication != null && mProfiler.profileFd != null
                        && mProfiler.autoStopProfiler) {
                    stopProfiling = true;
                }
                if (a != null) {
                    mNewActivities = null;
                    IActivityTaskManager am = ActivityTaskManager.getService();
                    ActivityClientRecord prev;
                    do {
                        if (localLOGV) Slog.v(
                            TAG, "Reporting idle of " + a +
                            " finished=" +
                            (a.activity != null && a.activity.mFinished));
                        if (a.activity != null && !a.activity.mFinished) {
                            try {
                                // 调用 ActivityTaskManagerService.activityIdle()
                                am.activityIdle(a.token, a.createdConfig, stopProfiling);
                                a.createdConfig = null;
                            } catch (RemoteException ex) {
                                throw ex.rethrowFromSystemServer();
                            }
                        }
                        prev = a;
                        a = a.nextIdle;
                        prev.nextIdle = null;
                    } while (a != null);
                }
                if (stopProfiling) {
                    mProfiler.stopProfiling();
                }
                applyPendingProcessState();
                return false;
            }
        }
    

    Binder 调用了 ActivityTaskManagerService.activityIdle()

    >ActivityTaskManagerService.java
        @Override
        public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
            final long origId = Binder.clearCallingIdentity();
            try {
                WindowProcessController proc = null;
                synchronized (mGlobalLock) {
                    ActivityStack stack = ActivityRecord.getStackLocked(token);
                    if (stack == null) {
                        return;
                    }
                    final ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token,
                            false /* fromTimeout */, false /* processPausingActivities */, config);
                    if (r != null) {
                        proc = r.app;
                    }
                    if (stopProfiling && proc != null) {
                        proc.clearProfilerIfNeeded();
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    

    调用了 ActivityStackSupervisor.activityIdleInternalLocked() 方法。

    >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);
            if (r != null) {
                if (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternalLocked: Callers="
                        + Debug.getCallers(4));
                mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
                r.finishLaunchTickingLocked();
                if (fromTimeout) {
                    reportActivityLaunchedLocked(fromTimeout, r, INVALID_DELAY,
                            -1 /* launchState */);
                }
    
                // This is a hack to semi-deal with a race condition
                // in the client where it can be constructed with a
                // newer configuration from when we asked it to launch.
                // We'll update with whatever configuration it now says
                // it used to launch.
                if (config != null) {
                    r.setLastReportedGlobalConfiguration(config);
                }
    
                // We are now idle.  If someone is waiting for a thumbnail from
                // us, we can now deliver.
                r.idle = true;
    
                //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
    
                // Check if able to finish booting when device is booting and all resumed activities
                // are idle.
                if ((mService.isBooting() && mRootActivityContainer.allResumedActivitiesIdle())
                        || fromTimeout) {
                    booting = checkFinishBootingLocked();
                }
    
                // When activity is idle, we consider the relaunch must be successful, so let's clear
                // the flag.
                r.mRelaunchReason = RELAUNCH_REASON_NONE;
            }
    
            if (mRootActivityContainer.allResumedActivitiesIdle()) {
                if (r != null) {
                    mService.scheduleAppGcsLocked();
                }
    
                if (mLaunchingActivityWakeLock.isHeld()) {
                    mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
                    if (VALIDATE_WAKE_LOCK_CALLER &&
                            Binder.getCallingUid() != Process.myUid()) {
                        throw new IllegalStateException("Calling must be system uid");
                    }
                    mLaunchingActivityWakeLock.release();
                }
                mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
            }
    
            // Atomically retrieve all of the other things to do.
            // 获取要 stop 的 Activity
            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.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.
            // 该 stop 的 stop 掉
            for (int i = 0; i < NS; i++) {
                r = stops.get(i);
                final ActivityStack stack = r.getActivityStack();
                if (stack != null) {
                    if (r.finishing) {
                        stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
                                "activityIdleInternalLocked");
                    } else {
                        stack.stopActivityLocked(r);
                    }
                }
            }
    
            // Finish any activities that are scheduled to do so but have been
            // waiting for the next one to start.
            // 该 destroy 的 destroy 掉
            for (int i = 0; i < NF; i++) {
                r = finishes.get(i);
                final ActivityStack stack = r.getActivityStack();
                if (stack != null) {
                    activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
                }
            }
    
            if (!booting) {
                // Complete user switch
                if (startingUsers != null) {
                    for (int i = 0; i < startingUsers.size(); i++) {
                        mService.mAmInternal.finishUserSwitch(startingUsers.get(i));
                    }
                }
            }
    
            mService.mH.post(() -> mService.mAmInternal.trimApplications());
            //dump();
            //mWindowManager.dump();
    
            if (activityRemoved) {
                mRootActivityContainer.resumeFocusedStacksTopActivities();
            }
    
            return r;
        }
    

    stopsfinishes 分别是要 stop 和 destroy 的两个 ActivityRecord 数组。stops 数组是通过 ActivityStackSuperVisor.processStoppingActivitiesLocked() 方法获取的,追进去看一下。

    >ActivityStackSuperVisor.java
        final ArrayList<ActivityRecord> processStoppingActivitiesLocked(ActivityRecord idleActivity,
                boolean remove, boolean processPausingActivities) {
            ArrayList<ActivityRecord> stops = null;
    
            final boolean nowVisible = mRootActivityContainer.allResumedActivitiesVisible();
            // 遍历 mStoppingActivities
            for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
                ActivityRecord s = mStoppingActivities.get(activityNdx);
    
                final boolean animating = s.mAppWindowToken.isSelfAnimating();
    
                if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
                        + " animating=" + animating + " finishing=" + s.finishing);
                if (nowVisible && s.finishing) {
    
                    // If this activity is finishing, it is sitting on top of
                    // everyone else but we now know it is no longer needed...
                    // so get rid of it.  Otherwise, we need to go through the
                    // normal flow and hide it once we determine that it is
                    // hidden by the activities in front of it.
                    if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
                    s.setVisibility(false);
                }
                if (remove) {
                    final ActivityStack stack = s.getActivityStack();
                    final boolean shouldSleepOrShutDown = stack != null
                            ? stack.shouldSleepOrShutDownActivities()
                            : mService.isSleepingOrShuttingDownLocked();
                    if (!animating || shouldSleepOrShutDown) {
                        if (!processPausingActivities && s.isState(PAUSING)) {
                            // Defer processing pausing activities in this iteration and reschedule
                            // a delayed idle to reprocess it again
                            removeTimeoutsForActivityLocked(idleActivity);
                            scheduleIdleTimeoutLocked(idleActivity);
                            continue;
                        }
    
                        if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
                        if (stops == null) {
                            stops = new ArrayList<>();
                        }
                        stops.add(s);
    
                        mStoppingActivities.remove(activityNdx);
                    }
                }
            }
    
            return stops;
        }
    

    中间的详细处理逻辑就不看了,我们只需要关注这里遍历的是 ActivityStackSuperVisor 中的 mStoppingActivities 集合 。在前面分析 finish() 流程到最后的 addToStopping() 方法时提到过,

    这些在等待销毁的 Activity 被保存在了 ActivityStackSupervisormStoppingActivities 集合中,它是一个 ArrayList<ActivityRecord>

    看到这里,终于打通了流程。再回头想一下文章开头的例子,由于人为的在 SecondActivity 不间断的向主线程塞消息,导致 Idler 迟迟无法被执行,按理说 onStop/onDestroy 也就不会被回调。可实际情况是这样吗?并不是,明明是过了 10s 被回调。这就说明了即使主线程迟迟没有机会执行 Idler,系统仍然提供了兜底机制,防止已经不需要的 Activity 长时间无法被回收,从而造成内存泄漏等问题。从实际现象就可以猜测到,这个兜底机制就是 onResume 之后 10s 主动去进行释放操作。
    再回到之前显示待跳转 Activity 的 ActivityStackSuperVisor.resumeFocusedStackTopActivityLocked() 方法。我这里就不带着大家追进去了,直接给出调用链。

    ASS.resumeFocusedStackTopActivityLocked() -> ActivityStack.resumeTopActivityUncheckedLocked() -> ActivityStack.resumeTopActivityInnerLocked() -> ActivityRecord.completeResumeLocked() -> ASS.scheduleIdleTimeoutLocked()

    > ActivityStackSuperVisor.java
        void scheduleIdleTimeoutLocked(ActivityRecord next) {
            if (DEBUG_IDLE) Slog.d(TAG_IDLE,
                    "scheduleIdleTimeoutLocked: Callers=" + Debug.getCallers(4));
            Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG, next);
            mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
        }
    

    IDLE_TIMEOUT 的值是 10,这里延迟 10s 发送了一个消息。这个消息是在 ActivityStackSupervisorHandler 中处理的。

        private final class ActivityStackSupervisorHandler extends Handler {
    
            public ActivityStackSupervisorHandler(Looper looper) {
                super(looper);
            }
    
            void activityIdleInternal(ActivityRecord r, boolean processPausingActivities) {
                synchronized (mService.mGlobalLock) {
                    //进入此处
                    activityIdleInternalLocked(r != null ? r.appToken : null, true /* fromTimeout */,
                            processPausingActivities, null);
                }
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case REPORT_MULTI_WINDOW_MODE_CHANGED_MSG: {
                        synchronized (mService.mGlobalLock) {
                            for (int i = mMultiWindowModeChangedActivities.size() - 1; i >= 0; i--) {
                                final ActivityRecord r = mMultiWindowModeChangedActivities.remove(i);
                                r.updateMultiWindowMode();
                            }
                        }
                    } break;
                    case REPORT_PIP_MODE_CHANGED_MSG: {
                        synchronized (mService.mGlobalLock) {
                            for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
                                final ActivityRecord r = mPipModeChangedActivities.remove(i);
                                r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds,
                                        false /* forceUpdate */);
                            }
                        }
                    } break;
                    case IDLE_TIMEOUT_MSG: { //进入此处
                        if (DEBUG_IDLE) Slog.d(TAG_IDLE,
                                "handleMessage: IDLE_TIMEOUT_MSG: r=" + msg.obj);
                        // We don't at this point know if the activity is fullscreen,
                        // so we need to be conservative and assume it isn't.
                        activityIdleInternal((ActivityRecord) msg.obj,
                                true /* processPausingActivities */);
                    } break;
                    case IDLE_NOW_MSG: {
                        if (DEBUG_IDLE) Slog.d(TAG_IDLE, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj);
                        activityIdleInternal((ActivityRecord) msg.obj,
                                false /* processPausingActivities */);
                    } break;
                    case RESUME_TOP_ACTIVITY_MSG: {
                        synchronized (mService.mGlobalLock) {
                            mRootActivityContainer.resumeFocusedStacksTopActivities();
                        }
                    } break;
                    case SLEEP_TIMEOUT_MSG: {
                        synchronized (mService.mGlobalLock) {
                            if (mService.isSleepingOrShuttingDownLocked()) {
                                Slog.w(TAG, "Sleep timeout!  Sleeping now.");
                                checkReadyForSleepLocked(false /* allowDelay */);
                            }
                        }
                    } break;
                    case LAUNCH_TIMEOUT_MSG: {
                        synchronized (mService.mGlobalLock) {
                            if (mLaunchingActivityWakeLock.isHeld()) {
                                Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
                                if (VALIDATE_WAKE_LOCK_CALLER
                                        && Binder.getCallingUid() != Process.myUid()) {
                                    throw new IllegalStateException("Calling must be system uid");
                                }
                                mLaunchingActivityWakeLock.release();
                            }
                        }
                    } break;
                    case LAUNCH_TASK_BEHIND_COMPLETE: {
                        synchronized (mService.mGlobalLock) {
                            ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
                            if (r != null) {
                                handleLaunchTaskBehindCompleteLocked(r);
                            }
                        }
                    } break;
                    case RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG: {
                        final ActivityRecord r = (ActivityRecord) msg.obj;
                        String processName = null;
                        int uid = 0;
                        synchronized (mService.mGlobalLock) {
                            if (r.attachedToProcess()
                                    && r.isState(ActivityStack.ActivityState.RESTARTING_PROCESS)) {
                                processName = r.app.mName;
                                uid = r.app.mUid;
                            }
                        }
                        if (processName != null) {
                            mService.mAmInternal.killProcess(processName, uid,
                                    "restartActivityProcessTimeout");
                        }
                    } break;
                    case REPORT_HOME_CHANGED_MSG: {
                        synchronized (mService.mGlobalLock) {
                            mHandler.removeMessages(REPORT_HOME_CHANGED_MSG);
    
                            // Start home activities on displays with no activities.
                            mRootActivityContainer.startHomeOnEmptyDisplays("homeChanged");
                        }
                    } break;
                    case TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG: {
                        ActivityRecord r = (ActivityRecord) msg.obj;
                        Slog.w(TAG, "Activity top resumed state loss timeout for " + r);
                        synchronized (mService.mGlobalLock) {
                            if (r.hasProcess()) {
                                mService.logAppTooSlow(r.app, r.topResumedStateLossTime,
                                        "top state loss for " + r);
                            }
                        }
                        handleTopResumedStateReleased(true /* timeout */);
                    } break;
                }
            }
        }
    

    忘记 activityIdleInternalLocked 方法的话可以 ctrl+F 向上搜索一下。如果 10s 内主线程执行了 Idler 的话,就会移除这个消息。

    到这里,所有的问题就全部理清了。

    Activity 的 onStop/onDestroy 是依赖 IdleHandler 来回调的,正常情况下当主线程空闲时会调用。但是由于某些特殊场景下的问题,导致主线程迟迟无法空闲,onStop/onDestroy 也会迟迟得不到调用。但这并不意味着 Activity 永远得不到回收,系统提供了一个兜底机制,当 onResume 回调 10s 之后,如果仍然没有得到调用,会主动触发。
    虽然有兜底机制,但无论如何这肯定不是我们想看到的。如果我们项目中的 onStop/onDestroy 延迟了 10s 调用,该如何排查问题呢?可以利用 Looper.getMainLooper().setMessageLogging() 方法,打印出主线程消息队列中的消息。每处理一条消息,都会打印如下内容:

    logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    

    此日志消息来源于

    >Looper.java
        public static void loop() {
            final Looper me = myLooper();
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            final MessageQueue queue = me.mQueue;
    
            // Make sure the identity of this thread is that of the local process,
            // and keep track of what that identity token actually is.
            Binder.clearCallingIdentity();
            final long ident = Binder.clearCallingIdentity();
    
            // Allow overriding a threshold with a system prop. e.g.
            // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
            final int thresholdOverride =
                    SystemProperties.getInt("log.looper."
                            + Process.myUid() + "."
                            + Thread.currentThread().getName()
                            + ".slow", 0);
    
            boolean slowDeliveryDetected = false;
    
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
    
                // This must be in a local variable, in case a UI event sets the logger
                final Printer logging = me.mLogging;
                if (logging != null) {
                    //获取主线程 Dispatching to 该 message 的日志
                    logging.println(">>>>> Dispatching to " + msg.target + " " +
                            msg.callback + ": " + msg.what);
                }
                // Make sure the observer won't change while processing a transaction.
                final Observer observer = sObserver;
    
                final long traceTag = me.mTraceTag;
                long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
                long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
                if (thresholdOverride > 0) {
                    slowDispatchThresholdMs = thresholdOverride;
                    slowDeliveryThresholdMs = thresholdOverride;
                }
                final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
                final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
    
                final boolean needStartTime = logSlowDelivery || logSlowDispatch;
                final boolean needEndTime = logSlowDispatch;
    
                if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                    Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
                }
    
                final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
                final long dispatchEnd;
                Object token = null;
                if (observer != null) {
                    token = observer.messageDispatchStarting();
                }
                long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
                try {
                    msg.target.dispatchMessage(msg);
                    if (observer != null) {
                        observer.messageDispatched(token, msg);
                    }
                    dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
                } catch (Exception exception) {
                    if (observer != null) {
                        observer.dispatchingThrewException(token, msg, exception);
                    }
                    throw exception;
                } finally {
                    ThreadLocalWorkSource.restore(origWorkSource);
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
                if (logSlowDelivery) {
                    if (slowDeliveryDetected) {
                        if ((dispatchStart - msg.when) <= 10) {
                            Slog.w(TAG, "Drained");
                            slowDeliveryDetected = false;
                        }
                    } else {
                        if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                                msg)) {
                            // Once we write a slow delivery log, suppress until the queue drains.
                            slowDeliveryDetected = true;
                        }
                    }
                }
                if (logSlowDispatch) {
                    showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
                }
    
                if (logging != null) {
                    //获取主线程 Finished to 该 message 的日志
                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                }
    
                // Make sure that during the course of dispatching the
                // identity of the thread wasn't corrupted.
                final long newIdent = Binder.clearCallingIdentity();
                if (ident != newIdent) {
                    Log.wtf(TAG, "Thread identity changed from 0x"
                            + Long.toHexString(ident) + " to 0x"
                            + Long.toHexString(newIdent) + " while dispatching to "
                            + msg.target.getClass().getName() + " "
                            + msg.callback + " what=" + msg.what);
                }
    
                msg.recycleUnchecked();
            }
        }
    

    另外,由于 onStop/onDestroy 调用时机的不确定性,在做资源释放等操作的时候,一定要考虑好,以避免产生资源没有及时释放的情况。

    本文参考链接:https://juejin.cn/post/6898588053451833351

    最后,感兴趣的同学可以顺着目前最新的 Android 11.0(R) 的 AOSP 中,去走一遍这个流程看看。

    相关文章

      网友评论

        本文标题:Android10.0(Q)中 Activity finish(

        本文链接:https://www.haomeiwen.com/subject/ylvniktx.html