summaryrefslogtreecommitdiff
path: root/core/java/android/view/WindowManagerGlobal.java
diff options
context:
space:
mode:
authorRiddle Hsu <riddlehsu@google.com>2019-04-29 19:22:38 +0800
committerRiddle Hsu <riddlehsu@google.com>2019-05-15 15:18:26 +0800
commit5828b413b0720cdcb9d51b5ebb90cbf7d9eb7249 (patch)
tree2797a8cb44d6738c7d4c8337c842b761964e7850 /core/java/android/view/WindowManagerGlobal.java
parentc3c30eefb2bb2c0cd1342583191db0d8c87bb17d (diff)
Invoke setWindowStopped on the thread that created the view
The windows belong to a activity will be set to stopped state when the activity is stopped. But the associated thread of view root could be different from activity, that results the inconsistent calling thread of surface callback, and maybe some potential races. Since the surface could be destroyed during traversal, also add a check for callback notifySurfaceDestroyed to prevent duplicated calls if the surface is released. Bug: 130553315 Test: atest ViewRootSurfaceCallbackTest Change-Id: Iea2cf8ff51118c0fa8c00a35c1d3e53c959ea754
Diffstat (limited to 'core/java/android/view/WindowManagerGlobal.java')
-rw-r--r--core/java/android/view/WindowManagerGlobal.java20
1 files changed, 19 insertions, 1 deletions
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 8a111cf86658..379acbecb613 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -636,13 +636,21 @@ public final class WindowManagerGlobal {
}
public void setStoppedState(IBinder token, boolean stopped) {
+ ArrayList<ViewRootImpl> nonCurrentThreadRoots = null;
synchronized (mLock) {
int count = mViews.size();
for (int i = count - 1; i >= 0; i--) {
if (token == null || mParams.get(i).token == token) {
ViewRootImpl root = mRoots.get(i);
// Client might remove the view by "stopped" event.
- root.setWindowStopped(stopped);
+ if (root.mThread == Thread.currentThread()) {
+ root.setWindowStopped(stopped);
+ } else {
+ if (nonCurrentThreadRoots == null) {
+ nonCurrentThreadRoots = new ArrayList<>();
+ }
+ nonCurrentThreadRoots.add(root);
+ }
// Recursively forward stopped state to View's attached
// to this Window rather than the root application token,
// e.g. PopupWindow's.
@@ -650,6 +658,16 @@ public final class WindowManagerGlobal {
}
}
}
+
+ // Update the stopped state synchronously to ensure the surface won't be used after server
+ // side has destroyed it. This operation should be outside the lock to avoid any potential
+ // paths from setWindowStopped to WindowManagerGlobal which may cause deadlocks.
+ if (nonCurrentThreadRoots != null) {
+ for (int i = nonCurrentThreadRoots.size() - 1; i >= 0; i--) {
+ ViewRootImpl root = nonCurrentThreadRoots.get(i);
+ root.mHandler.runWithScissors(() -> root.setWindowStopped(stopped), 0);
+ }
+ }
}
public void reportNewConfiguration(Configuration config) {