# Android之wm-am(1)

RootWindowContainer ---> DisplayContent ---> TaskDisplayArea ---> ActivityStack ---> Task ---> ActivityRecord

RootWindowContainer

根容器会处理Window布局,管理Activity相关的Stack和TaskDisplayArea

/** Root {@link WindowContainer} for the device. */
class RootWindowContainer extends WindowContainer
        implements DisplayManager.DisplayListener {
    // Map from the PID to the top most app which has a focused window of the process.
    final HashMap mTopFocusedAppByProcess = new HashMap<>();//updateFocusedWindowLocked
    ActivityTaskManagerService mService;
    ActivityStackSupervisor mStackSupervisor;
    WindowManagerService mWindowManager;
    /** Reference to default display so we can quickly look it up. */
    private DisplayContent mDefaultDisplay;

updateFocusedWindowLocked

1 mTopFocusedAppByProcess.clear()

2 对每一个子DisplayContent调用updateFocusedWindowLocked更新FocusWindow

3 获取子DisplayContent的mCurrentFocus,将其加入到mTopFocusedAppByProcess

    boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
        mTopFocusedAppByProcess.clear();
        boolean changed = false;
        int topFocusedDisplayId = INVALID_DISPLAY;
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final DisplayContent dc = mChildren.get(i);
            changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows, topFocusedDisplayId);
            final WindowState newFocus = dc.mCurrentFocus;
            if (newFocus != null) {
                final int pidOfNewFocus = newFocus.mSession.mPid;
                if (mTopFocusedAppByProcess.get(pidOfNewFocus) == null) {
                    mTopFocusedAppByProcess.put(pidOfNewFocus, newFocus.mActivityRecord);
                }

hasPendingLayoutChanges和copyAnimToLayoutParams

会检查子DisplayContent的pendingChanges是否已经完成壁纸的布局,如果没有完成,将相关动画的mBulkUpdateParams设置为重新布局壁纸

    boolean hasPendingLayoutChanges(WindowAnimator animator) {
        boolean hasChanges = false;

        final int count = mChildren.size();
        for (int i = 0; i < count; ++i) {
            final int pendingChanges = mChildren.get(i).pendingLayoutChanges;
            if ((pendingChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
                animator.mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;
            }
            if (pendingChanges != 0) {
                hasChanges = true;
            }
        }

        return hasChanges;
    }

将动画的参数同步到布局中,并判断是否需要重新布局

bulkUpdateParams & SET_UPDATE_ROTATION 旋转方向改变

bulkUpdateParams & SET_WALLPAPER_ACTION_PENDING 壁纸需要重新布局

 boolean copyAnimToLayoutParams() {
        boolean doRequest = false;

        final int bulkUpdateParams = mWmService.mAnimator.mBulkUpdateParams;
        if ((bulkUpdateParams & SET_UPDATE_ROTATION) != 0) {
            mUpdateRotation = true;
            doRequest = true;
        }
        if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
            mOrientationChangeComplete = false;
        } else {
            mOrientationChangeComplete = true;
            mLastWindowFreezeSource = mWmService.mAnimator.mLastWindowFreezeSource;
            if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
                doRequest = true;
            }
        }

        if ((bulkUpdateParams & SET_WALLPAPER_ACTION_PENDING) != 0) {
            mWallpaperActionPending = true;
        }

        return doRequest;
    }

performSurfacePlacementNoTrace

window布局

        mWmService.openSurfaceTransaction();
        try {
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");

resumeFocusedStacksTopActivities

Activity切换

targetStack不等于null,且targetStack是TopStackInDisplayArea或者当前TopDisplayFocusedStack为targetStack,直接调用targetStack的resumeTopActivityUncheckedLocked方法,resume最上面的Activity。

stack.topRunningActivity()是调用父类Task的方法

从上往下遍历,如果getFocusedStack不为null,调用resumeTopActivityUncheckedLocked

如果focusedStack为null,且targetStack也为null,则启动resumeHomeActivity

                final ActivityStack focusedStack = display.getFocusedStack();
                if (focusedStack != null) {
                    result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
                } else if (targetStack == null) {
                    result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
                            display.getDefaultTaskDisplayArea());
                }
    boolean resumeFocusedStacksTopActivities() {
        return resumeFocusedStacksTopActivities(null, null, null);
    }

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

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

        boolean result = false;
        if (targetStack != null && (targetStack.isTopStackInDisplayArea()
                || getTopDisplayFocusedStack() == targetStack)) {
            result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }

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

        return result;
    }

moveTopStackActivityToPinnedStack

管理一些特殊的StackActivity

moveStackToDisplay
moveStackToTaskDisplayArea
moveActivityToPinnedStack

r.setWindowingMode(intermediateWindowingMode);

stack.setWindowingMode(WINDOWING_MODE_PINNED);

    void moveActivityToPinnedStack(ActivityRecord r, String reason) {
        mService.deferWindowLayout();

        final TaskDisplayArea taskDisplayArea = r.getDisplayArea();

        try {
            final Task task = r.getTask();
            final ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask();

            // This will change the pinned stack's windowing mode to its original mode, ensuring
            // we only have one stack that is in pinned mode.
            if (pinnedStack != null) {
                pinnedStack.dismissPip();
            }

            // Set a transition to ensure that we don't immediately try and update the visibility
            // of the activity entering PIP
            r.getDisplayContent().prepareAppTransition(TRANSIT_NONE, false);

            final boolean singleActivity = task.getChildCount() == 1;
            final ActivityStack stack;
            if (singleActivity) {
                stack = (ActivityStack) task;
            } else {
                // In the case of multiple activities, we will create a new task for it and then
                // move the PIP activity into the task.
                stack = taskDisplayArea.createStack(WINDOWING_MODE_UNDEFINED, r.getActivityType(),
                        ON_TOP, r.info, r.intent, false /* createdByOrganizer */);
                // It's possible the task entering PIP is in freeform, so save the last
                // non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
                // to its previous freeform bounds.
                stack.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds);

                // There are multiple activities in the task and moving the top activity should
                // reveal/leave the other activities in their original task.
                // On the other hand, ActivityRecord#onParentChanged takes care of setting the
                // up-to-dated pinned stack information on this newly created stack.
                r.reparent(stack, MAX_VALUE, reason);
            }
            // The intermediate windowing mode to be set on the ActivityRecord later.
            // This needs to happen before the re-parenting, otherwise we will always set the
            // ActivityRecord to be fullscreen.
            final int intermediateWindowingMode = stack.getWindowingMode();
            if (stack.getParent() != taskDisplayArea) {
                // stack is nested, but pinned tasks need to be direct children of their
                // display area, so reparent.
                stack.reparent(taskDisplayArea, true /* onTop */);
            }
            // Defer the windowing mode change until after the transition to prevent the activity
            // from doing work and changing the activity visuals while animating
            // TODO(task-org): Figure-out more structured way to do this long term.
            r.setWindowingMode(intermediateWindowingMode);
            stack.setWindowingMode(WINDOWING_MODE_PINNED);

            // Reset the state that indicates it can enter PiP while pausing after we've moved it
            // to the pinned stack
            r.supportsEnterPipOnTaskSwitch = false;
        } finally {
            mService.continueWindowLayout();
        }

        ensureActivitiesVisible(null, 0, false /* preserveWindows */);
        resumeFocusedStacksTopActivities();

        mService.getTaskChangeNotificationController().notifyActivityPinned(r);
    }

一些简易接口

getTopVisibleActivities
getTopDisplayFocusedStack
getTopResumedActivity
getWindowsByName
topRunningActivity


allPausedActivitiesComplete

r.nowVisible有一个条件不满足,return false

!r.isState(PAUSED, STOPPED, STOPPING, FINISHING)有一个条件不满足,return false

    boolean allResumedActivitiesVisible() {
        boolean foundResumed = false;
        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
            final DisplayContent display = getChildAt(displayNdx);
            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
                    final ActivityRecord r = stack.getResumedActivity();
                    if (r != null) {
                        if (!r.nowVisible) {
                            return false;
                        }
                        foundResumed = true;
                    }
                }
            }
        }
        return foundResumed;
    }

    boolean allPausedActivitiesComplete() {
        boolean pausing = true;
        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
            final DisplayContent display = getChildAt(displayNdx);
            for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
                final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
                for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
                    final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
                    final ActivityRecord r = stack.mPausingActivity;
                    if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) {
                        if (DEBUG_STATES) {
                            Slog.d(TAG_STATES, "allPausedActivitiesComplete: r=" + r
                                    + " state=" + r.getState());
                            pausing = false;
                        } else {
                            return false;
                        }
                    }
                }
            }
        }
        return pausing;
    }

你可能感兴趣的:(# Android之wm-am(1))