diff options
| author | Riddle Hsu <riddlehsu@google.com> | 2019-04-29 19:22:38 +0800 |
|---|---|---|
| committer | Riddle Hsu <riddlehsu@google.com> | 2019-05-15 15:18:26 +0800 |
| commit | 5828b413b0720cdcb9d51b5ebb90cbf7d9eb7249 (patch) | |
| tree | 2797a8cb44d6738c7d4c8337c842b761964e7850 /core/java/android/view/WindowManagerGlobal.java | |
| parent | c3c30eefb2bb2c0cd1342583191db0d8c87bb17d (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.java | 20 |
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) { |
