Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f16a2810 authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Fixed NPE when trying to animate a windows whose display is gone.

In some cases it is possible for the AppToken.allAppWindows list to
get out of sync with the list of windows known to WMS if the client
doesn't call Session.remove(Window). This can lead to an NPE when
the animation threads runs and the display for the window has been
removed.

Also corrected some method names/scopes I ran across while debugging.

Bug: 19972099
Change-Id: Ib0ae7ede6c506f833bbdd66723b88e7504a61907
parent 356c628e
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -3509,7 +3509,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
        mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0));
    }

    public void handleDisplayAddedLocked(int displayId) {
    private void handleDisplayAdded(int displayId) {
        boolean newDisplay;
        synchronized (mService) {
            newDisplay = mActivityDisplays.get(displayId) == null;
@@ -3527,7 +3527,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
        }
    }

    public void handleDisplayRemovedLocked(int displayId) {
    private void handleDisplayRemoved(int displayId) {
        synchronized (mService) {
            ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
            if (activityDisplay != null) {
@@ -3541,7 +3541,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
        mWindowManager.onDisplayRemoved(displayId);
    }

    public void handleDisplayChangedLocked(int displayId) {
    private void handleDisplayChanged(int displayId) {
        synchronized (mService) {
            ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
            if (activityDisplay != null) {
@@ -3551,7 +3551,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
        mWindowManager.onDisplayChanged(displayId);
    }

    StackInfo getStackInfo(ActivityStack stack) {
    private StackInfo getStackInfoLocked(ActivityStack stack) {
        StackInfo info = new StackInfo();
        mWindowManager.getStackBounds(stack.mStackId, info.bounds);
        info.displayId = Display.DEFAULT_DISPLAY;
@@ -3577,7 +3577,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
    StackInfo getStackInfoLocked(int stackId) {
        ActivityStack stack = getStack(stackId);
        if (stack != null) {
            return getStackInfo(stack);
            return getStackInfoLocked(stack);
        }
        return null;
    }
@@ -3587,7 +3587,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
        for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
                list.add(getStackInfo(stacks.get(ndx)));
                list.add(getStackInfoLocked(stacks.get(ndx)));
            }
        }
        return list;
@@ -3707,13 +3707,13 @@ public final class ActivityStackSupervisor implements DisplayListener {
                    }
                } break;
                case HANDLE_DISPLAY_ADDED: {
                    handleDisplayAddedLocked(msg.arg1);
                    handleDisplayAdded(msg.arg1);
                } break;
                case HANDLE_DISPLAY_CHANGED: {
                    handleDisplayChangedLocked(msg.arg1);
                    handleDisplayChanged(msg.arg1);
                } break;
                case HANDLE_DISPLAY_REMOVED: {
                    handleDisplayRemovedLocked(msg.arg1);
                    handleDisplayRemoved(msg.arg1);
                } break;
                case CONTAINER_CALLBACK_VISIBILITY: {
                    final ActivityContainer container = (ActivityContainer) msg.obj;
+2 −2
Original line number Diff line number Diff line
@@ -242,7 +242,7 @@ public class AppWindowAnimator {
    }

    // This must be called while inside a transaction.
    boolean stepAnimationLocked(long currentTime) {
    boolean stepAnimationLocked(long currentTime, final int displayId) {
        if (mService.okToDisplay()) {
            // We will run animations as long as the display isn't frozen.

@@ -292,7 +292,7 @@ public class AppWindowAnimator {
        }

        mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
                "AppWindowToken");
                "AppWindowToken", displayId);

        clearAnimation();
        animating = false;
+19 −17
Original line number Diff line number Diff line
@@ -159,13 +159,13 @@ public class WindowAnimator {
                    final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
                    final boolean wasAnimating = appAnimator.animation != null
                            && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
                    if (appAnimator.stepAnimationLocked(mCurrentTime)) {
                    if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
                        mAnimating = mAppWindowAnimating = true;
                    } else if (wasAnimating) {
                        // stopped animating, do one more pass through the layout
                        setAppLayoutChanges(appAnimator,
                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
                                "appToken " + appAnimator.mAppToken + " done");
                                "appToken " + appAnimator.mAppToken + " done", displayId);
                        if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
                                "updateWindowsApps...: done animating " + appAnimator.mAppToken);
                    }
@@ -178,12 +178,12 @@ public class WindowAnimator {
                final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
                final boolean wasAnimating = appAnimator.animation != null
                        && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
                if (appAnimator.stepAnimationLocked(mCurrentTime)) {
                if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
                    mAnimating = mAppWindowAnimating = true;
                } else if (wasAnimating) {
                    // stopped animating, do one more pass through the layout
                    setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
                        "exiting appToken " + appAnimator.mAppToken + " done");
                        "exiting appToken " + appAnimator.mAppToken + " done", displayId);
                    if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
                            "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
                }
@@ -575,11 +575,11 @@ public class WindowAnimator {
                            // This will set mOrientationChangeComplete and cause a pass through layout.
                            setAppLayoutChanges(appAnimator,
                                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
                                    "testTokenMayBeDrawnLocked: freezingScreen");
                                    "testTokenMayBeDrawnLocked: freezingScreen", displayId);
                        } else {
                            setAppLayoutChanges(appAnimator,
                                    WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
                                    "testTokenMayBeDrawnLocked");
                                    "testTokenMayBeDrawnLocked", displayId);

                            // We can now show all of the drawn windows!
                            if (!mService.mOpeningApps.contains(wtoken)) {
@@ -792,28 +792,30 @@ public class WindowAnimator {
        if (displayId < 0) {
            return 0;
        }
        return mService.getDisplayContentLocked(displayId).pendingLayoutChanges;
        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
        return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
    }

    void setPendingLayoutChanges(final int displayId, final int changes) {
        if (displayId >= 0) {
            mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
        if (displayId < 0) {
            return;
        }
        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
        if (displayContent != null) {
            displayContent.pendingLayoutChanges |= changes;
        }
    }

    void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
        // Used to track which displays layout changes have been done.
        SparseIntArray displays = new SparseIntArray(2);
    void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String reason,
            final int displayId) {
        WindowList windows = appAnimator.mAppToken.allAppWindows;
        for (int i = windows.size() - 1; i >= 0; i--) {
            final int displayId = windows.get(i).getDisplayId();
            if (displayId >= 0 && displays.indexOfKey(displayId) < 0) {
            if (displayId == windows.get(i).getDisplayId()) {
                setPendingLayoutChanges(displayId, changes);
                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                    mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
                    mService.debugLayoutRepeats(reason, getPendingLayoutChanges(displayId));
                }
                // Keep from processing this display again.
                displays.put(displayId, changes);
                break;
            }
        }
    }