Remove starting window when activity is preempted.
Activities launch starting windows before they are resumed. If another
activity is started after a first activity has launched its starting
window then it was possible that the starting window will never be
removed. An earlier fix, ag/368411, solved this by posting a delayed
message that would remove orphaned starting windows after 10 seconds.
This fix immediately removes starting windows that have been orphaned
through the above sequence.
A few code cleanups are also included in this CL.
Fixes bug 11029212.
Change-Id: I7a9befca92888aefe4000b90716c57c2aa572634
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 49f29fe..5776181 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -143,6 +143,7 @@
private boolean inHistory; // are we in the history stack?
final ActivityStackSupervisor mStackSupervisor;
+ boolean mStartingWindowShown = false;
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 2e5dedf..f879971 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -61,7 +61,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -121,8 +120,7 @@
// convertToTranslucent().
static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000;
- static final boolean SCREENSHOT_FORCE_565 = ActivityManager
- .isLowRamDeviceStatic() ? true : false;
+ static final boolean SCREENSHOT_FORCE_565 = ActivityManager.isLowRamDeviceStatic();
enum ActivityState {
INITIALIZING,
@@ -398,8 +396,9 @@
// be simplified once we stop storing tasks with empty mActivities lists.
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- return activities.get(activityNdx);
+ final int topActivityNdx = activities.size() - 1;
+ if (topActivityNdx >= 0) {
+ return activities.get(topActivityNdx);
}
}
return null;
@@ -436,25 +435,6 @@
return null;
}
- boolean containsApp(ProcessRecord app) {
- if (app == null) {
- return false;
- }
- for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
- final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.finishing) {
- continue;
- }
- if (r.app == app) {
- return true;
- }
- }
- }
- return false;
- }
-
final boolean updateLRUListLocked(ActivityRecord r) {
final boolean hadit = mLRUActivities.remove(r);
mLRUActivities.add(r);
@@ -1231,6 +1211,32 @@
}
}
+ /** If any activities below the top running one are in the INITIALIZING state and they have a
+ * starting window displayed then remove that starting window. It is possible that the activity
+ * in this state will never resumed in which case that starting window will be orphaned. */
+ void cancelInitializingActivities() {
+ final ActivityRecord topActivity = topRunningActivityLocked(null);
+ boolean aboveTop = true;
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+ for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ActivityRecord r = activities.get(activityNdx);
+ if (aboveTop) {
+ if (r == topActivity) {
+ aboveTop = false;
+ }
+ continue;
+ }
+
+ if (r.state == ActivityState.INITIALIZING && r.mStartingWindowShown) {
+ if (DEBUG_VISBILITY) Slog.w(TAG, "Found orphaned starting window " + r);
+ r.mStartingWindowShown = false;
+ mWindowManager.removeAppStartingWindow(r.appToken);
+ }
+ }
+ }
+ }
+
/**
* Ensure that the top activity in the stack is resumed.
*
@@ -1247,6 +1253,8 @@
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+ cancelInitializingActivities();
+
// Find the first activity that is not finishing.
ActivityRecord next = topRunningActivityLocked(null);
@@ -1811,6 +1819,7 @@
r.info.applicationInfo), r.nonLocalizedLabel,
r.labelRes, r.icon, r.logo, r.windowFlags,
prev != null ? prev.appToken : null, showStartingIcon);
+ r.mStartingWindowShown = true;
}
} else {
// If this is the first activity, don't do any fancy animations,
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 22be807..fbd610c 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -256,9 +256,6 @@
/** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
- /** Amount of time (in milliseconds) to delay before declaring a starting window leaked. */
- static final int STARTING_WINDOW_TIMEOUT_DURATION = 10000;
-
/**
* If true, the window manager will do its own custom freezing and general
* management of the screen during rotation.
@@ -2268,8 +2265,6 @@
token.appWindowToken.startingWindow = win;
if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken
+ " startingWindow=" + win);
- Message m = mH.obtainMessage(H.REMOVE_STARTING_TIMEOUT, token.appWindowToken);
- mH.sendMessageDelayed(m, STARTING_WINDOW_TIMEOUT_DURATION);
}
boolean imMayMove = true;
@@ -2372,7 +2367,6 @@
public void removeWindowLocked(Session session, WindowState win) {
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Starting window removed " + win);
- removeStartingWindowTimeout(win.mAppToken);
}
if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v(
@@ -2516,7 +2510,6 @@
if (atoken != null) {
if (atoken.startingWindow == win) {
if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Nulling startingWindow " + win);
- removeStartingWindowTimeout(atoken);
atoken.startingWindow = null;
} else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
// If this is the last window and we had requested a starting
@@ -3983,7 +3976,6 @@
if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) {
Slog.v(TAG, "Removing starting window: " + startingWindow);
}
- removeStartingWindowTimeout(ttoken);
startingWindow.getWindowList().remove(startingWindow);
mWindowsChanged = true;
if (DEBUG_ADD_REMOVE) Slog.v(TAG,
@@ -4130,6 +4122,15 @@
}
}
+ public void removeAppStartingWindow(IBinder token) {
+ synchronized (mWindowMap) {
+ AppWindowToken wtoken = mTokenMap.get(token).appWindowToken;
+ if (wtoken.startingWindow != null) {
+ scheduleRemoveStartingWindow(wtoken);
+ }
+ }
+ }
+
@Override
public void setAppWillBeHidden(IBinder token) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4551,21 +4552,11 @@
scheduleRemoveStartingWindow(startingToken);
}
- void removeStartingWindowTimeout(AppWindowToken wtoken) {
- if (wtoken != null) {
- if (DEBUG_STARTING_WINDOW) Slog.v(TAG, Debug.getCallers(1) +
- ": Remove starting window timeout " + wtoken + (wtoken != null ?
- " startingWindow=" + wtoken.startingWindow : ""));
- mH.removeMessages(H.REMOVE_STARTING_TIMEOUT, wtoken);
- }
- }
-
void scheduleRemoveStartingWindow(AppWindowToken wtoken) {
if (wtoken != null && wtoken.startingWindow != null) {
if (DEBUG_STARTING_WINDOW) Slog.v(TAG, Debug.getCallers(1) +
": Schedule remove starting " + wtoken + (wtoken != null ?
" startingWindow=" + wtoken.startingWindow : ""));
- removeStartingWindowTimeout(wtoken);
Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken);
mH.sendMessage(m);
}
@@ -7072,8 +7063,6 @@
public static final int TAP_OUTSIDE_STACK = 31;
public static final int NOTIFY_ACTIVITY_DRAWN = 32;
- public static final int REMOVE_STARTING_TIMEOUT = 33;
-
@Override
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
@@ -7172,7 +7161,6 @@
"Aborted starting " + wtoken
+ ": removed=" + wtoken.removed
+ " startingData=" + wtoken.startingData);
- removeStartingWindowTimeout(wtoken);
wtoken.startingWindow = null;
wtoken.startingData = null;
abort = true;
@@ -7197,11 +7185,6 @@
}
} break;
- case REMOVE_STARTING_TIMEOUT: {
- final AppWindowToken wtoken = (AppWindowToken)msg.obj;
- Slog.e(TAG, "Starting window " + wtoken + " timed out");
- // Fall through.
- }
case REMOVE_STARTING: {
final AppWindowToken wtoken = (AppWindowToken)msg.obj;
IBinder token = null;