summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andrii Kulian <akulian@google.com> 2016-05-11 15:50:24 -0700
committer Andrii Kulian <akulian@google.com> 2016-05-12 13:37:05 -0700
commiteac0ea5cdfade6bfd2a1e40e67c2a45d4c37ab9e (patch)
treeb0cab48e4f202751d040c793bea270ffb75a4573
parent2d36b0c2384a8b28fed7a5a7503f315bc3a43a20 (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.java17
-rw-r--r--core/java/android/view/WindowManagerGlobal.java27
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 "