diff options
| author | 2016-05-11 15:50:24 -0700 | |
|---|---|---|
| committer | 2016-05-12 13:37:05 -0700 | |
| commit | eac0ea5cdfade6bfd2a1e40e67c2a45d4c37ab9e (patch) | |
| tree | b0cab48e4f202751d040c793bea270ffb75a4573 | |
| parent | 2d36b0c2384a8b28fed7a5a7503f315bc3a43a20 (diff) | |
Close leaked windows when trying to preserve main one
When app has several windows and activity is relaunched + we try to preserve
main window - other windows just stayed around until removed by timeout or
replaced by app. There was a problem when one of the windows registered
broadcast receiver and set its own timer to remove it. In this case all
receivers were removed by framework because windows were considered leaked
and apps' timer caused crash when trying to remove registered receiver.
This CL removes all windows expect the main one, which we're trying to
preserve in this case.
Bug: 28337135
Change-Id: Ib8790cc8c61801f11d871ba3803bb0ebc3d3be01
| -rw-r--r-- | core/java/android/app/ActivityThread.java | 17 | ||||
| -rw-r--r-- | core/java/android/view/WindowManagerGlobal.java | 27 |
2 files changed, 33 insertions, 11 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index e54edf2a574b..8a3306eb8748 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4183,12 +4183,10 @@ public final class ActivityThread { // window is being added. r.mPendingRemoveWindow = r.window; r.mPendingRemoveWindowManager = wm; - if (r.mPreserveWindow) { - // We can only keep the part of the view hierarchy that we control, - // everything else must be removed, because it might not be able to - // behave properly when activity is relaunching. - r.window.clearContentView(); - } + // We can only keep the part of the view hierarchy that we control, + // everything else must be removed, because it might not be able to + // behave properly when activity is relaunching. + r.window.clearContentView(); } else { wm.removeViewImmediate(v); } @@ -4196,6 +4194,13 @@ public final class ActivityThread { if (wtoken != null && r.mPendingRemoveWindow == null) { WindowManagerGlobal.getInstance().closeAll(wtoken, r.activity.getClass().getName(), "Activity"); + } else if (r.mPendingRemoveWindow != null) { + // We're preserving only one window, others should be closed so app views + // will be detached before the final tear down. It should be done now because + // some components (e.g. WebView) rely on detach callbacks to perform receiver + // unregister and other cleanup. + WindowManagerGlobal.getInstance().closeAllExceptView(token, v, + r.activity.getClass().getName(), "Activity"); } r.activity.mDecor = null; } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 887cc3acb64a..11734d31388e 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -391,17 +391,34 @@ public final class WindowManagerGlobal { } } + /** + * Remove all roots with specified token. + * + * @param token app or window token. + * @param who name of caller, used in logs. + * @param what type of caller, used in logs. + */ public void closeAll(IBinder token, String who, String what) { + closeAllExceptView(token, null /* view */, who, what); + } + + /** + * Remove all roots with specified token, except maybe one view. + * + * @param token app or window token. + * @param view view that should be should be preserved along with it's root. + * Pass null if everything should be removed. + * @param who name of caller, used in logs. + * @param what type of caller, used in logs. + */ + public void closeAllExceptView(IBinder token, View view, String who, String what) { synchronized (mLock) { int count = mViews.size(); - //Log.i("foo", "Closing all windows of " + token); for (int i = 0; i < count; i++) { - //Log.i("foo", "@ " + i + " token " + mParams[i].token - // + " view " + mRoots[i].getView()); - if (token == null || mParams.get(i).token == token) { + if ((view == null || mViews.get(i) != view) + && (token == null || mParams.get(i).token == token)) { ViewRootImpl root = mRoots.get(i); - //Log.i("foo", "Force closing " + root); if (who != null) { WindowLeaked leak = new WindowLeaked( what + " " + who + " has leaked window " |