当前位置: 首页 > article >正文

Android 系统进程启动Activity方法说明

  前面文章Android Activity的启动器ActivityStarter入口说到Activity的恢复执行是由 mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch)来实现的,下面就看下它的实现。

RootWindowContainer类的resumeFocusedTasksTopActivities方法

它的代码在RootWindowContainer类中,如下:

    boolean resumeFocusedTasksTopActivities(
            Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
            boolean deferPause) {
        if (!mTaskSupervisor.readyToResume()) {
            return false;
        }

        boolean result = false;
        if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
                || getTopDisplayFocusedRootTask() == targetRootTask)) {
            result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
                    deferPause);
        }

        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
            final DisplayContent display = getChildAt(displayNdx);
            final boolean curResult = result;
            boolean[] resumedOnDisplay = new boolean[1];
            display.forAllRootTasks(rootTask -> {
                final ActivityRecord topRunningActivity = rootTask.topRunningActivity();
                if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) {
                    return;
                }
                if (rootTask == targetRootTask) {
                    // Simply update the result for targetRootTask because the targetRootTask
                    // 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[0] |= curResult;
                    return;
                }
                if (rootTask.getDisplayArea().isTopRootTask(rootTask)
                        && topRunningActivity.isState(RESUMED)) {
                    // Kick off any lingering app transitions form the MoveTaskToFront
                    // operation, but only consider the top task and root-task on that
                    // display.
                    rootTask.executeAppTransition(targetOptions);
                } else {
                    resumedOnDisplay[0] |= topRunningActivity.makeActiveIfNeeded(target);
                }
            });
            result |= resumedOnDisplay[0];
            if (!resumedOnDisplay[0]) {
                // 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 root task explicitly will make sure that at least home
                // activity is started and resumed, and no recursion occurs.
                final Task focusedRoot = display.getFocusedRootTask();
                if (focusedRoot != null) {
                    result |= focusedRoot.resumeTopActivityUncheckedLocked(target, targetOptions);
                } else if (targetRootTask == null) {
                    result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
                            display.getDefaultTaskDisplayArea());
                }
            }
        }

        return result;
    }

  参数targetRootTask是启动Activity的根Task,target则是待启动的Activity对象,targetOptions则是待启动的参数,deferPause则是延迟暂停当前启动的Activity。
  mTaskSupervisor.readyToResume()如果为true,代表ActivityTaskSupervisor类对象没有设置延缓恢复,延缓恢复是由一个int成员变量控制的,设置延缓就加1,取消延缓就减1。如果设置了,这里是不能恢复Activity启动的。
  接着就判断根任务是它所属TaskDisplayArea中的最顶层的根任务或者RootWindowContainer中的最顶层的根任务。Android是支持多屏幕的,RootWindowContainer的下一层就对应屏幕,而每个屏幕上是有一个TaskDisplayArea对象。如果是单屏幕这俩条件应该是一致的。下面就是调用目标Task的resumeTopActivityUncheckedLocked()方法,来执行Activity的启动。
  上面执行完毕之后,开始从上到下遍历屏幕,屏幕对应DisplayContent对象。
  接着DisplayContent对象通过forAllRootTasks遍历每个根任务对象,
  如果根任务不是isFocusableAndVisible()或者根任务的最顶层的没有可以运行的Activity的话,直接返回。任务的isFocusableAndVisible()要求可Focusable并且要求Task可见。
  如果现在的根任务和上面执行resumeTopActivityUncheckedLocked()方法的根任务一样,这里就不再执行,不过会将resumedOnDisplay[0]赋值为上面执行的结果。
  接下来如果根任务是TaskDisplayArea对象中最顶层的并且任务中的最顶层可以运行的Activity是RESUMED状态,这里会执行该根任务的AppTransition。如果不是,则会调用topRunningActivity.makeActiveIfNeeded(target),使topRunningActivity恢复运行,恢复成功返回true,并将结果存在resumedOnDisplay[0]。
  遍历完所有根任务之后,就将结果合并到变量result中。只要有恢复运行成功的Activity,这里result都为true。
  如果resumedOnDisplay[0]为false,代表当前屏幕没有执行恢复Activity运行,注释里说了两种情况(刚系统启动或者Launcher崩溃)。这样,会得到当前屏幕的可Focusable并且要求Task可见的根任务,让它执行恢复Activity的工作。如果这个条件不满足,并且参数targetRootTask == null,就去恢复HomeActivity。
  最后将结果result返回。

Task的resumeTopActivityUncheckedLocked方法

  所以看到真正的执行Activity恢复的,是由任务Task类来执行的,接着看下它的实现:

    @GuardedBy("mService")
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
            boolean deferPause) {
        if (mInResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean someActivityResumed = false;
        try {
            // Protect against recursion.
            mInResumeTopActivity = true;

            if (isLeafTask()) {
                if (isFocusableAndVisible()) {
                    someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
                }
            } else {
                int idx = mChildren.size() - 1;
                while (idx >= 0) {
                    final Task child = (Task) getChildAt(idx--);
                    if (!child.isTopActivityFocusable()) {
                        continue;
                    }
                    if (child.getVisibility(null /* starting */) != TASK_VISIBILITY_VISIBLE) {
                        break;
                    }

                    someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options,
                            deferPause);
                    // Doing so in order to prevent IndexOOB since hierarchy might changes while
                    // resuming activities, for example dismissing split-screen while starting
                    // non-resizeable activity.
                    if (idx >= mChildren.size()) {
                        idx = mChildren.size() - 1;
                    }
                }
            }

            // When resuming the top activity, it may be necessary to pause the top activity (for
            // example, returning to the lock screen. We suppress the normal pause logic in
            // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the
            // end. We call the {@link ActivityTaskSupervisor#checkReadyForSleepLocked} again here
            // to ensure any necessary pause logic occurs. In the case where the Activity will be
            // shown regardless of the lock screen, the call to
            // {@link ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped.
            final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
            if (next == null || !next.canTurnScreenOn()) {
                checkReadyForSleep();
            }
        } finally {
            mInResumeTopActivity = false;
        }

        return someActivityResumed;
    }

   Task的成员变量mInResumeTopActivity代表是在恢复Activity的过程中,如果它为true,代表已经在执行,就直接退出。
   接下来就将mInResumeTopActivity设置为true,代表进入恢复Activity的过程。
  isLeafTask()代表任务是不是叶子任务,Task里面是可以嵌套Task的,只有Task里面没有任何Task的情况下,它为叶子任务。如果为叶子任务,并且它可以Focusable并且可见的情况下,直接调用resumeTopActivityInnerLocked(prev, options, deferPause)方法来执行。
   如果不是叶子任务,需要检查它的孩子任务,孩子任务得是它最上面的Activity是Focusable,如果不是,进入下个循环。孩子任务如果不可见,就直接跳出循环了,因为检查孩子任务是从顶层往下层检查的,上层不可见,下面的任务就更不可见了,所以跳出,不再往下执行。可以看到,孩子任务也是递归调用resumeTopActivityUncheckedLocked方法,继续执行。
  接下来,这段代码看注释,是处理恢复Activity之后,回到了锁屏状态的情况,需要让当前恢复的Activity暂停。在锁屏状态下,获取任务的topRunningActivity(true)会返回null。所以在next == null时,调用checkReadyForSleep()去处理,该方法里面就有注释里面提到的ActivityTaskSupervisor#checkReadyForSleepLocked。同时,如果next不为null,并且它可以打开屏幕,就可以跳过检查了。
   将成员变量mInResumeTopActivity = false,并返回Activity恢复启动的结果。

Task的resumeTopActivityInnerLocked方法

  Task的resumeTopActivityInnerLocked方法,该段代码特别长,分段看下。

resumeTopActivityInnerLocked方法分段一

  分段一如下:

    @GuardedBy("mService")
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
            boolean deferPause) {
        if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
            // Not ready yet!
            return false;
        }

        // Find the next top-most activity to resume in this root task that is not finishing and is
        // focusable. If it is not focusable, we will fall into the case below to resume the
        // top activity in the next focusable task.
        ActivityRecord next = topRunningActivity(true /* focusableOnly */);

        final boolean hasRunningActivity = next != null;

        // TODO: Maybe this entire condition can get removed?
        if (hasRunningActivity && !isAttached()) {
            return false;
        }

        mRootWindowContainer.cancelInitializingActivities();

        if (!hasRunningActivity) {
            // There are no activities left in the root task, let's look somewhere else.
            return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options);
        }

        next.delayedResume = false;
        final TaskDisplayArea taskDisplayArea = getDisplayArea();

        // If the top activity is the resumed one, nothing to do.
        if (mResumedActivity == next && next.isState(RESUMED)
                && taskDisplayArea.allResumedActivitiesComplete()) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            executeAppTransition(options);
            // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
            // we still want to check if the visibility of other windows have changed (e.g. bringing
            // a fullscreen window forward to cover another freeform activity.)
            if (taskDisplayArea.inMultiWindowMode()) {
                taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                        false /* preserveWindows */, true /* notifyClients */);
            }
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity "
                    + "resumed %s", next);
            return false;
        }

        if (!next.canResumeByCompat()) {
            return false;
        }

        // If we are currently pausing an activity, then don't do anything until that is done.
        final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
        if (!allPausedComplete) {
            ProtoLog.v(WM_DEBUG_STATES,
                    "resumeTopActivityLocked: Skip resume: some activity pausing.");

            return false;
        }

        // If we are sleeping, and there is no resumed activity, and the top activity is paused,
        // well that is the state we want.
        if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            executeAppTransition(options);
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Going to sleep and"
                    + " all paused");
            return false;
        }

        // Make sure that the user who owns this activity is started.  If not,
        // we will just leave it as is because someone should be bringing
        // another user's activities to the top of the stack.
        if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
            Slog.w(TAG, "Skipping resume of top activity " + next
                    + ": user " + next.mUserId + " is stopped");
            return false;
        }

   mAtmService.isBooting()是在系统启动中,mAtmService.isBooted()是系统启动了,如果不是在这两个状态,直接返回false。
   topRunningActivity(true)得到的是任务的最上面可以运行的Activity。它即为需要恢复的Activity。Android Activity的启动器ActivityStarter入口 该篇文章可知,是会将待启动的Activity放在目标任务的最上面。看一下topRunningActivity(true)的相关实现:

    ActivityRecord topRunningActivity(boolean focusableOnly) {
        // Split into 2 to avoid object creation due to variable capture.
        if (focusableOnly) {
            return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
        } else {
            return getActivity(ActivityRecord::canBeTopRunning);
        }
    }

  getActivity是从上到下,检查任务中的Activity,找到的Activity满足canBeTopRunning()和isFocusable()。isFocusable()就是Activity可以获取焦点,canBeTopRunning()看一下它的实现:

    boolean canBeTopRunning() {
        return !finishing && okToShowLocked();
    }

    public boolean okToShowLocked() {
        // We cannot show activities when the device is locked and the application is not
        // encryption aware.
        if (!StorageManager.isUserKeyUnlocked(mUserId)
                && !info.applicationInfo.isEncryptionAware()) {
            return false;
        }

        return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
                || (mTaskSupervisor.isCurrentProfileLocked(mUserId)
                && mAtmService.mAmInternal.isUserRunning(mUserId, 0 /* flags */));
    }

  要求Activity不能是finishing ,并且设备不是被锁、应用不是encryption aware的。所以如果设备被锁定,获取到的topRunningActivity()可能会为null(如果应用没有配置EncryptionAware)。接着okToShowLocked() 要想返回为true,要么配置FLAG_SHOW_FOR_ALL_USERS标识,要么检查该Activity运行在的用户是和当前系统用户一致或者它是Profile用户,并且该用户的状态是运行状态。
  !isAttached()代表任务没加到TaskDisplayArea对象中,如果存在待启动的Activity,但是任务没有添加进TaskDisplayArea对象中,返回false。
   mRootWindowContainer.cancelInitializingActivities(),它是处理RootWindowContainer类对象里所有不可见任务里的和被遮挡的Activity的starting window,如果它有,将它去除。
   如果任务里不存在可以运行的Activity,它会调用resumeNextFocusableActivityWhenRootTaskIsEmpty方法找到下一个可以Focusable,并且可见的Task,调用它的里面的Activity的恢复执行。
   接着将待启动的Activity next的delayedResume = false,它代表延迟恢复启动,这里不需要。
   mResumedActivity代表任务中目前恢复启动的Activity,如果它和待启动的Activity一样,并且它已经是RESUMED状态了,并且taskDisplayArea中所有的任务的mResumedActivity都为RESUMED状态(如果存在),则调用executeAppTransition(options)执行等待的过渡。如果taskDisplayArea的窗口模式为多窗口模式,则taskDisplayArea.ensureActivitiesVisible方法处理它里面的Activity的可见性。如果属于这种情况,这里直接返回false。
   next.canResumeByCompat()代表可以Resume。如果不可以,直接返回false。
   mRootWindowContainer.allPausedActivitiesComplete()是检查RootWindowContainer对象中所有Task中的mPausingActivity如果有PAUSED、 STOPPED,、STOPPING,、FINISHING这四种状态之外的其他状态,代表没有全部完成,这个时候,也是直接返回false,等待着Activity暂停完成。
   如果待启动的Activity和最后暂停的Activity相同,并且系统正在睡眠,这种情况下,什么也不做,返回false。
   如果拥有这个Activity的用户不是启动状态,也是返回false,将该Activity遗放在任务上面。

resumeTopActivityInnerLocked方法分段二

  分段二代码:

        // The activity may be waiting for stop, but that is no longer
        // appropriate for it.
        mTaskSupervisor.mStoppingActivities.remove(next);

        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);

        mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);

        ActivityRecord lastResumed = null;
        final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask();
        if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTask()) {
            // So, why aren't we using prev here??? See the param comment on the method. prev
            // doesn't represent the last resumed activity. However, the last focus stack does if
            // it isn't null.
            lastResumed = lastFocusedRootTask.getResumedActivity();
        }

        boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
        if (mResumedActivity != null) {
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
            pausing |= startPausingLocked(false /* uiSleeping */, next,
                    "resumeTopActivityInnerLocked");
        }
        if (pausing) {
            ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivityLocked: Skip resume: need to"
                    + " start pausing");
            // At this point we want to put the upcoming activity's process
            // at the top of the LRU list, since we know we will be needing it
            // very soon and it would be a waste to let it get killed if it
            // happens to be sitting towards the end.
            if (next.attachedToProcess()) {
                next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
                        true /* activityChange */, false /* updateOomAdj */,
                        false /* addPendingTopUid */);
            } else if (!next.isProcessRunning()) {
                // Since the start-process is asynchronous, if we already know the process of next
                // activity isn't running, we can start the process earlier to save the time to wait
                // for the current activity to be paused.
                final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
                mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
                        isTop ? "pre-top-activity" : "pre-activity");
            }
            if (lastResumed != null) {
                lastResumed.setWillCloseOrEnterPip(true);
            }
            return true;
        } else if (mResumedActivity == next && next.isState(RESUMED)
                && taskDisplayArea.allResumedActivitiesComplete()) {
            // It is possible for the activity to be resumed when we paused back stacks above if the
            // next activity doesn't have to wait for pause to complete.
            // So, nothing else to-do except:
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            executeAppTransition(options);
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity resumed "
                    + "(dontWaitForPause) %s", next);
            return true;
        }

  mTaskSupervisor.mStoppingActivities里面是等待需要执行Stop操作的Activity。这里将next如果在里面,就把它删除。
  next.info.applicationInfo.uid是应用的Uid,这里将它设置到mTaskSupervisor中。
  taskDisplayArea.getLastFocusedRootTask()得到的是上一次获得焦点的根Task。如果它存在并且和当前任务的根任务不一样,这样,会把上一次获得焦点的根Task的ResumedActivity赋值给变量lastResumed。
  deferPause是参数,如果它被设置true,这里就不执行taskDisplayArea.pauseBackTasks(next)。taskDisplayArea.pauseBackTasks(next)它是用来暂停TaskDisplayArea对象中,所有根任务中ResumedActivity不为null,并且任务不可见的Task,执行它的startPausingLocked方法,它用来让ResumedActivity暂停。如果存在执行暂停成功的,taskDisplayArea.pauseBackTasks(next)会返回true。
  接着检查该Task的mResumedActivity != null,代表该任务目前存在正在运行的Activity。所以调用startPausingLocked()来暂停它的执行。同样把运行结果并到变量pausing中。前面那个步骤不是调用taskDisplayArea.pauseBackTasks(next)暂停所有根任务的运行Activity了吗,这里怎么还调用呢,这是因为前面的那个暂停的是不可见任务的,而当前任务是可见的。并且方法参数deferPause也可能设置为true,会影响前面的那个执行。
  重点看一下下面的两种情况。
  1、pausing为true,代表是暂停中,还没有完成暂停操作。
  接着看代码,如果next的进程已经存在,调用了next.app.updateProcessInfo方法,看注释是要将待启动的Activity的进程放到LRU list的顶端,以免它在最尾端,被杀掉,还得花时间启动它。
  如果next的进程不存在,那就需要调用mAtmService.startProcessAsync方法,先启动进程之后,再启动对应Activity。
  如果在暂停Activity过程中,如果lastResumed != null,会调用它的setWillCloseOrEnterPip方法,设置它是在关闭或者进入PIP的过程中。最后,是返回true,代码不再往下执行。
  2、pausing为false,不是在暂停Activity过程中。可以分为条件不满足,未执行暂停Activity的过程或者已经执行完Activity暂停的过程。这两种情况pausing都为false。
  下面的代码是待启动的Activity和目前已经在运行的Activity一样,并且TaskDisplayArea对象中所有Activity都已经完成启动了。这种情况,是什么也不做了。直接返回true。

resumeTopActivityInnerLocked方法分段三

  分段三代码:

        // If the most recent activity was noHistory but was only stopped rather
        // than stopped+finished because the device went to sleep, we need to make
        // sure to finish it as we're making a new activity topmost.
        if (shouldSleepActivities()) {
            mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next);
        }

        if (prev != null && prev != next && next.nowVisible) {

            // The next activity is already visible, so hide the previous
            // activity's windows right now so we can show the new one ASAP.
            // We only do this if the previous is finishing, which should mean
            // it is on top of the one being resumed so hiding it quickly
            // is good.  Otherwise, we want to do the normal route of allowing
            // the resumed activity to be shown so we can decide if the
            // previous should actually be hidden depending on whether the
            // new one is found to be full-screen or not.
            if (prev.finishing) {
                prev.setVisibility(false);
                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                        "Not waiting for visible to hide: " + prev
                                + ", nowVisible=" + next.nowVisible);
            } else {
                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                        "Previous already visible but still waiting to hide: " + prev
                                + ", nowVisible=" + next.nowVisible);
            }

        }

        // Launching this app's activity, make sure the app is no longer
        // considered stopped.
        try {
            mTaskSupervisor.getActivityMetricsLogger()
                    .notifyBeforePackageUnstopped(next.packageName);
            mAtmService.getPackageManager().setPackageStoppedState(
                    next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
        } catch (RemoteException e1) {
        } catch (IllegalArgumentException e) {
            Slog.w(TAG, "Failed trying to unstop package "
                    + next.packageName + ": " + e);
        }

        // We are starting up the next activity, so tell the window manager
        // that the previous one will be hidden soon.  This way it can know
        // to ignore it when computing the desired screen orientation.
        boolean anim = true;
        final DisplayContent dc = taskDisplayArea.mDisplayContent;
        if (prev != null) {
            if (prev.finishing) {
                if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                        "Prepare close transition: prev=" + prev);
                if (mTaskSupervisor.mNoAnimActivities.contains(prev)) {
                    anim = false;
                    dc.prepareAppTransition(TRANSIT_NONE);
                } else {
                    dc.prepareAppTransition(TRANSIT_CLOSE);
                }
                prev.setVisibility(false);
            } else {
                if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                        "Prepare open transition: prev=" + prev);
                if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
                    anim = false;
                    dc.prepareAppTransition(TRANSIT_NONE);
                } else {
                    dc.prepareAppTransition(TRANSIT_OPEN,
                            next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
                }
            }
        } else {
            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
            if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
                anim = false;
                dc.prepareAppTransition(TRANSIT_NONE);
            } else {
                dc.prepareAppTransition(TRANSIT_OPEN);
            }
        }

        if (anim) {
            next.applyOptionsAnimation();
        } else {
            next.abortAndClearOptionsAnimation();
        }

        mTaskSupervisor.mNoAnimActivities.clear();        

  代码走到这里,有可能Activity在这里未执行暂停,也有可能已经执行暂停完毕。
  像这个Activity在这里未执行暂停的一种情况是,暂停Activity的流程已经执行完,所以在这个resumeTopActivityInnerLocked方法里面就不会再执行startPausingLocked方法了。这样说有点绕,其实普通Activity的启动这个方法resumeTopActivityInnerLocked是需要执行两次的,第一次,就是上面的第一种情况,pausing为true,就返回true,方法不再向下执行了。等待应用程序端告诉system进程,应用端pause完毕,system进程会再调用一次这个resumeTopActivityInnerLocked方法,这个时候,Task对象的mResumedActivity已经为null,所以不会再去执行startPausingLocked方法。
  已经执行暂停完毕的情况,是待启动的Activity带FLAG_RESUME_WHILE_PAUSING标识,可能导致暂停的Activity进入PIP模式或者不再等待应用端,直接完成暂停。像这种情况,就直接调用一次resumeTopActivityInnerLocked方法,接着往下执行代码。
  这段代码开始,是设备将要睡眠,对于那些noHistory的Activity,如果仅是停止状态,没有finished,在这里就将调用mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next)处理它们完成finished。
  prev != next && next.nowVisible,如果是第二次调用resumeTopActivityInnerLocked方法时,prev为已经暂停的Activity,next 则是待启动的Activity,满足prev != next。这时,如果next已经可见,这里是检查prev 的finishing状态,如果它为true,将prev的可见状态设置为不可见。
  接下来就是通知一些状态。让包的Stopped状态设置为false。
  再接下来是处理Activity的打开或关闭过渡效果。是否应用动画。如果prev已经是finishing,是采用关闭的过渡动画。其他情形,则采用打开的过渡动画。
  最后,会将mTaskSupervisor.mNoAnimActivities里的值清空。

resumeTopActivityInnerLocked方法分段四

  分段四代码:

        if (next.attachedToProcess()) {
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
                    + " stopped=" + next.stopped
                    + " visibleRequested=" + next.mVisibleRequested);

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

            // This activity is now becoming visible.
            if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) {
                next.setVisibility(true);
            }

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

            ActivityRecord lastResumedActivity =
                    lastFocusedRootTask == null ? null : lastFocusedRootTask.getResumedActivity();
            final ActivityState lastState = next.getState();

            mAtmService.updateCpuStats();

            ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next);

            next.setState(RESUMED, "resumeTopActivityInnerLocked");

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

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

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

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

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

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

                EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
                        next.getTask().mTaskId, next.shortComponentName);

                mAtmService.getAppWarningsLocked().onResumeActivity(next);
                next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
                next.abortAndClearOptionsAnimation();
                transaction.setLifecycleStateRequest(
                        ResumeActivityItem.obtain(next.app.getReportedProcState(),
                                dc.isNextTransitionForward()));
                mAtmService.getLifecycleManager().scheduleTransaction(transaction);

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

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

                Slog.i(TAG, "Restarting because process died: " + next);
                if (!next.hasBeenLaunched) {
                    next.hasBeenLaunched = true;
                } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
                        && lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
                    next.showStartingWindow(false /* taskSwitch */);
                }
                mTaskSupervisor.startSpecificActivity(next, true, false);
                return true;
            }

            // From this point on, if something goes wrong there is no way
            // to recover the activity.
            try {
                next.completeResumeLocked();
            } catch (Exception e) {
                // If any exception gets thrown, toss away this
                // activity and try the next one.
                Slog.w(TAG, "Exception thrown during resume of " + next, e);
                next.finishIfPossible("resume-exception", true /* oomAdj */);
                return true;
            }
        } else {
            // Whoops, need to restart this activity!
            if (!next.hasBeenLaunched) {
                next.hasBeenLaunched = true;
            } else {
                if (SHOW_APP_STARTING_PREVIEW) {
                    next.showStartingWindow(false /* taskSwich */);
                }
                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
            }
            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Restarting %s", next);
            mTaskSupervisor.startSpecificActivity(next, true, true);
        }

        return true;

  待启动Activity已经绑定进程了,下面这一长段代码都是这种情况下的处理。
  如果next是不可见或者stopped状态,将它变成可见。lastActivityTranslucent代表上一个获取焦点的任务如果处于多窗口或者它的Activity不遮挡,处于透明状态,这种情况下,也将next变成可见。
  next.startLaunchTickingLocked()则启动计时,后面可以检测它的启动时间。
  接着调用mAtmService.updateCpuStats()更新CPU状态。
  下面调用next.setState(RESUMED, “resumeTopActivityInnerLocked”),将Activity对应的状态设置为RESUMED。在这个方法里,它会更新它所属Task的成员mResumedActivity,将它设置为next。
  现在next应该是可见的,进入到if (shouldBeVisible(next))中,mRootWindowContainer.ensureVisibilityAndConfig是确保所有的Activity可见性设置正确,过渡被更新得到正确的旋转行为。同时它可能处理Activity因为配置发生变化导致重新启动。它的返回值,就代表是否重启Activity。返回false,代表重启Activity;返回true,代表不需要重启。
  接下来,如果notUpdated为true,代表因为配置更新导致重启了一个新的。接着,它重新获得任务上的Activity,如果它和next不一样,调用mTaskSupervisor.scheduleResumeTopActivities()重新调度另一个运行。
  如果next还不可见,或者是stopped,就设置它可见。
  再调用next的completeResumeLocked()方法,完成它的Resume。最后返回true,不再向下执行。
  如果notUpdated为false,代码会继续向下执行。
  构建一个ClientTransaction对象,两个成员变量,next.app.getThread()是在系统进程中应用进程的Binder代理,next.appToken是系统进程中的Activity的Binder对象。这俩都是用来实现Binder通信。
  next.results是应答结果,这里它不为null,并且next不是finishing,将它封装成ActivityResultItem,添加到ClientTransaction对象的回调接口中。
  如果next.newIntents != null,也添加到ClientTransaction对象的回调接口中。
  next.notifyAppResumed(next.stopped)通知Activity恢复启动了。
  mAtmService.getAppWarningsLocked().onResumeActivity(next)则是检查一些警告。
  next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState)设置进程的状态。
  next.abortAndClearOptionsAnimation()用来清除参数。
  接下来,就是将ClientTransaction对象调用setLifecycleStateRequest,将ResumeActivityItem对象设置到它的成员变量mLifecycleStateRequest中。
  mAtmService.getLifecycleManager()是ClientLifecycleManager对象,调用它的scheduleTransaction方法,来执行Activity的生命周期。
  最后也是调用next的completeResumeLocked()方法,完成它的Resume。返回true。
  上面的这种情况都是next已经存在进程的情况下,若进程还不存在呢,它主要是调用mTaskSupervisor.startSpecificActivity(next, true, true)来重新启动Activity,它的实现里面有如果进程不存在,先调用ActivityTaskManagerService对象的startProcessAsync方法,先启动进程,再恢复Activity。

总结

  这里将RootWindowContainer类的resumeFocusedTasksTopActivities方法的执行过程说了一遍,它是通过调用目标任务的resumeTopActivityUncheckedLocked方法来实现。它又是主要通过resumeTopActivityInnerLocked方法来实现的。
  我们理解的时候,需要考虑清楚它调用的情况。像普通Activity启动的时候,它们会在暂停之前Activity完成后,还会再调用一遍该方法启动待启动Activity。还有待启动的Activity的进程还没启动的情况,需要先启动进程,才启动Activity。


http://www.kler.cn/a/597865.html

相关文章:

  • 爬虫:scrapy面试题大全(60个scrapy经典面试题和详解)
  • 多线程编程中什么时候使用锁和原子操作
  • C#单例模式
  • Redis集群模式(优缺点)
  • AI重构工程设计、施工、总承包行业:从智能优化到数字孪生的产业革命
  • 群体智能优化算法-蛾火焰优化算法(Moth-Flame Optimization Algorithm,含Matlab源代码)
  • uboot(bootrom的作用)
  • [快乐学坊_2] 后端api测试
  • 数据结构篇——二叉树的存储与遍历
  • UnoCSS极速入门:下一代原子化CSS引擎实战指南
  • CVPR 2025 | 文本和图像引导的高保真3D数字人高效生成GaussianIP
  • Gradle/Maven 本地仓库默认路径迁移 (减少系统磁盘占用)
  • 【中文翻译】第1章-The Algorithmic Foundations of Differential Privacy
  • OTN(Optical Transport Network,光传输网络)
  • 机器人的位姿变换左乘与右乘
  • The First Indoor Pathloss Radio Map Prediction Challenge
  • 数组作为哈希表的妙用:寻找缺失的第一个正数
  • TensorFlow面试题及参考答案
  • uniapp vue3使用uniapp的生命周期
  • 如何高效参与 GitHub 知名项目开发并成为核心贡献者