Copy exiting app token list while stepping animation.

Stepping the animation can lead to WindowStateAnimator#finishExit,
which can lead to WindowManagerService#removeWindowInnerLocked, which
can immediately call WindowSurfacePlacer.performSurfacePlacement. From
here we will directly modify mExitingAppTokens for each stack and remove
tokens where exiting is complete. I think removeWindowInnerLocked making
a direct call to performSurfacePlacement is questionable...but changing
semantics there is very risky. For now, simply avoid processing tokens
in the animator if the surface placer has removed them. It seems all we
would want to do is trigger a layout pass, which has just occured anyway.

Bug: 30813094
Change-Id: Iaff77d227e09839f7e6edda6b8f188d164e6da74
This commit is contained in:
Robert Carr
2016-08-12 13:50:38 -07:00
parent 1ee928a62a
commit 46831fa9ff

View File

@@ -119,6 +119,8 @@ public class WindowAnimator {
// check if some got replaced and can be removed.
private boolean mRemoveReplacedWindows = false;
private final AppTokenList mTmpExitingAppTokens = new AppTokenList();
private String forceHidingToString() {
switch (mForceHiding) {
case KEYGUARD_NOT_SHOWN: return "KEYGUARD_NOT_SHOWN";
@@ -189,10 +191,19 @@ public class WindowAnimator {
}
}
final AppTokenList exitingAppTokens = stack.mExitingAppTokens;
final int exitingCount = exitingAppTokens.size();
mTmpExitingAppTokens.clear();
mTmpExitingAppTokens.addAll(stack.mExitingAppTokens);
final int exitingCount = mTmpExitingAppTokens.size();
for (int i = 0; i < exitingCount; i++) {
final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
final AppWindowAnimator appAnimator = mTmpExitingAppTokens.get(i).mAppAnimator;
// stepAnimation can trigger finishExit->removeWindowInnerLocked
// ->performSurfacePlacement
// performSurfacePlacement will directly manipulate the mExitingAppTokens list
// so we need to iterate over a copy and check for modifications.
if (!stack.mExitingAppTokens.contains(appAnimator)) {
continue;
}
appAnimator.wasAnimating = appAnimator.animating;
if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
setAnimating(true);