Copy child window list when destroying surface
When removing a child window, we may trigger a layout pass via:
WindowState.removeImmediately calls
WMS.postWindowRemoveCleanupLocked calls
WindowPlacer.performSurfacePlacement
Then, under certain conditions, we either remove a window from
mService.mForceRemoves or mService.mPendingRemove. If a child
is in any of these two lists, it will lead to a crash.
Test: go/wm-smoke
Change-Id: I4eac6a6ec9092521542590fad1aa9643818b2fe6
Fixes: 71499373
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 44d7948..32b7221 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -645,8 +645,7 @@
boolean destroyedSomething = false;
// Copying to a different list as multiple children can be removed.
- // TODO: Not sure why this is needed.
- final LinkedList<WindowState> children = new LinkedList<>(mChildren);
+ final ArrayList<WindowState> children = new ArrayList<>(mChildren);
for (int i = children.size() - 1; i >= 0; i--) {
final WindowState win = children.get(i);
destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0e025dc..f541752 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2642,8 +2642,11 @@
boolean destroySurface(boolean cleanupOnResume, boolean appStopped) {
boolean destroyedSomething = false;
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
+
+ // Copying to a different list as multiple children can be removed.
+ final ArrayList<WindowState> childWindows = new ArrayList<>(mChildren);
+ for (int i = childWindows.size() - 1; i >= 0; --i) {
+ final WindowState c = childWindows.get(i);
destroyedSomething |= c.destroySurface(cleanupOnResume, appStopped);
}
@@ -3873,8 +3876,7 @@
if (!mChildren.isEmpty()) {
// Copying to a different list as multiple children can be removed.
- // TODO: Not sure if we really need to copy this into a different list.
- final LinkedList<WindowState> childWindows = new LinkedList(mChildren);
+ final ArrayList<WindowState> childWindows = new ArrayList<>(mChildren);
for (int i = childWindows.size() - 1; i >= 0; i--) {
childWindows.get(i).onExitAnimationDone();
}