Begin switch over to task based history.
- Introduce the task history and add to and remove from it with
verification.
Change-Id: If97e74f5a13f85acdb1521fc6d0b066a7e8584ae
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index c1b406e..f2d401f 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -471,6 +471,7 @@
void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
if (inHistory && !finishing) {
if (task != null) {
+ task.removeActivity(this);
task.numActivities--;
}
if (newTask != null) {
@@ -505,6 +506,7 @@
inHistory = false;
if (task != null && !finishing) {
task.numActivities--;
+ task = null;
}
clearOptionsLocked();
}
@@ -539,7 +541,7 @@
ActivityResult r = new ActivityResult(from, resultWho,
requestCode, resultCode, resultData);
if (results == null) {
- results = new ArrayList();
+ results = new ArrayList<ResultInfo>();
}
results.add(r);
}
@@ -950,6 +952,8 @@
StringBuilder sb = new StringBuilder(128);
sb.append("ActivityRecord{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" t");
+ sb.append(task.taskId);
sb.append(" u");
sb.append(userId);
sb.append(' ');
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index c54cdaa..a18a0d1 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -54,6 +54,7 @@
import android.graphics.Bitmap.Config;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -66,6 +67,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import java.io.FileDescriptor;
@@ -75,6 +77,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.NoSuchElementException;
/**
* State and management of a single stack of activities.
@@ -98,7 +101,8 @@
static final boolean DEBUG_APP = false;
static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
-
+ static final boolean VALIDATE_TASK_REPLACE = true;
+
// How long we wait until giving up on the last activity telling us it
// is idle.
static final int IDLE_TIMEOUT = 10*1000;
@@ -137,7 +141,10 @@
// Set to false to disable the preview that is shown while a new activity
// is being started.
static final boolean SHOW_APP_STARTING_PREVIEW = true;
-
+
+ static final boolean FORWARD_ITERATOR = false;
+ static final boolean REVERSE_ITERATOR = true;
+
enum ActivityState {
INITIALIZING,
RESUMED,
@@ -154,7 +161,7 @@
final boolean mMainStack;
final Context mContext;
-
+
/**
* The back history of all previous (and possibly still
* running) activities. It contains #ActivityRecord objects.
@@ -162,6 +169,17 @@
private final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
/**
+ * The back history of all previous (and possibly still
+ * running) activities. It contains #TaskRecord objects.
+ */
+ private ArrayList<TaskRecord> mTaskHistory = new ArrayList<TaskRecord>();
+
+ /**
+ * Mapping from taskId to TaskRecord
+ */
+ private SparseArray<TaskRecord> mTaskIdToTaskRecord = new SparseArray<TaskRecord>();
+
+ /**
* Used for validating app tokens with window manager.
*/
final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<TaskGroup>();
@@ -289,6 +307,12 @@
*/
boolean mDismissKeyguardOnNextActivity = false;
+ /** So we don't have to keep constructing a new object for utility non-nested use. */
+ final ActivityIterator mTmpActivityIterator = new ActivityIterator(FORWARD_ITERATOR, true);
+
+ /** So we don't have to keep constructing a new object for utility non-nested use. */
+ final TaskIterator mTmpTaskIterator = new TaskIterator();
+
/**
* Save the most recent screenshot for reuse. This keeps Recents from taking two identical
* screenshots, one for the Recents thumbnail and one for the pauseActivity thumbnail.
@@ -508,30 +532,69 @@
}
final ActivityRecord isInStackLocked(IBinder token) {
+ ActivityRecord newAr = newIsInStackLocked(token);
+
ActivityRecord r = ActivityRecord.forToken(token);
if (mHistory.contains(r)) {
+ if (VALIDATE_TASK_REPLACE && newAr != r) Slog.w(TAG,
+ "isInStackLocked: mismatch: newAr=" + newAr + " r=" + r);
return r;
}
+ if (VALIDATE_TASK_REPLACE && newAr != null) Slog.w(TAG,
+ "isInStackLocked: mismatch: newAr!=null");
+ return null;
+ }
+
+ final ActivityRecord newIsInStackLocked(IBinder token) {
+ final ActivityRecord r = ActivityRecord.forToken(token);
+ if (r != null) {
+ final TaskRecord task = r.task;
+ if (mTaskHistory.contains(task) && task.mActivities.contains(r)) {
+ return r;
+ }
+ }
return null;
}
int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+ int newTaskId = newGetTaskForActivityLocked(token, onlyRoot);
+
TaskRecord lastTask = null;
final int N = mHistory.size();
for (int i = 0; i < N; i++) {
ActivityRecord r = mHistory.get(i);
if (r.appToken == token) {
if (!onlyRoot || lastTask != r.task) {
+ if (VALIDATE_TASK_REPLACE && newTaskId != r.task.taskId) Slog.w(TAG,
+ "getTaskForActivityLocked: mismatch: new=" + newTaskId
+ + " taskId=" + r.task.taskId);
return r.task.taskId;
}
+ if (VALIDATE_TASK_REPLACE && newTaskId != -1) Slog.w(TAG,
+ "getTaskForActivityLocked: mismatch: newTaskId=" + newTaskId + " not -1.");
return -1;
}
lastTask = r.task;
}
+ if (VALIDATE_TASK_REPLACE && newTaskId != -1) Slog.w(TAG,
+ "getTaskForActivityLocked: mismatch at end: newTaskId=" + newTaskId + " not -1.");
return -1;
}
+ int newGetTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+ final ActivityRecord r = ActivityRecord.forToken(token);
+ if (r == null) {
+ return -1;
+ }
+ final TaskRecord task = r.task;
+ switch (task.mActivities.indexOf(r)) {
+ case -1: return -1;
+ case 0: return task.taskId;
+ default: return onlyRoot ? -1 : task.taskId;
+ }
+ }
+
private final boolean updateLRUListLocked(ActivityRecord r) {
final boolean hadit = mLRUActivities.remove(r);
mLRUActivities.add(r);
@@ -624,17 +687,29 @@
* @return whether there are any activities for the specified user.
*/
final boolean switchUserLocked(int userId, UserStartedState uss) {
+ if (VALIDATE_TOKENS) {
+ validateAppTokensLocked();
+ }
+ final boolean newResult = newSwitchUserLocked(userId, uss);
+
mCurrentUser = userId;
mStartingUsers.add(uss);
// Only one activity? Nothing to do...
- if (mHistory.size() < 2)
+ if (mHistory.size() < 2) {
+ if (VALIDATE_TASK_REPLACE && newResult) Slog.w(TAG,
+ "switchUserLocked: mismatch: " + newResult + " " + false);
return false;
+ }
boolean haveActivities = false;
// Check if the top activity is from the new user.
ActivityRecord top = mHistory.get(mHistory.size() - 1);
- if (top.userId == userId) return true;
+ if (top.userId == userId) {
+ if (VALIDATE_TASK_REPLACE && !newResult) Slog.w(TAG,
+ "switchUserLocked: mismatch: " + newResult + " " + true);
+ return true;
+ }
// Otherwise, move the user's activities to the top.
int N = mHistory.size();
int i = 0;
@@ -651,7 +726,44 @@
}
}
// Transition from the old top to the new top
+ if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+ "switchUserLocked: calling resumeTopActivity " + top);
resumeTopActivityLocked(top);
+ if (VALIDATE_TASK_REPLACE && (newResult != haveActivities)) Slog.w(TAG,
+ "switchUserLocked: mismatch: " + newResult + " " + haveActivities);
+ return haveActivities;
+ }
+
+ /*
+ * Move the activities around in the stack to bring a user to the foreground.
+ * @return whether there are any activities for the specified user.
+ */
+ final boolean newSwitchUserLocked(int userId, UserStartedState uss) {
+// mStartingUsers.add(uss);
+ if (mCurrentUser == userId) {
+ return true;
+ }
+ mCurrentUser = userId;
+
+ // Move userId's tasks to the top.
+ boolean haveActivities = false;
+ TaskRecord task = null;
+ int index = mTaskHistory.size();
+ for (int i = 0; i < index; ++i) {
+ task = mTaskHistory.get(i);
+ if (task.userId == userId) {
+ haveActivities = true;
+ mTaskHistory.remove(i);
+ mTaskHistory.add(task);
+ --index;
+ }
+ }
+
+ // task is now the original topmost TaskRecord. Transition from the old top to the new top.
+ ActivityRecord top = task != null ? task.getTopActivity() : null;
+ if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
+ "newSwitchUserLocked: would call resumeTopActivity " + top);
+// resumeTopActivityLocked(top);
return haveActivities;
}
@@ -889,6 +1001,9 @@
mGoingToSleep.release();
}
// Ensure activities are no longer sleeping.
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
for (int i=mHistory.size()-1; i>=0; i--) {
ActivityRecord r = mHistory.get(i);
r.setSleeping(false);
@@ -933,6 +1048,9 @@
// Make sure any stopped but visible activities are now sleeping.
// This ensures that the activity's onStop() is called.
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
for (int i=mHistory.size()-1; i>=0; i--) {
ActivityRecord r = mHistory.get(i);
if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
@@ -1077,6 +1195,9 @@
ActivityRecord r = null;
synchronized (mService) {
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
int index = indexOfTokenLocked(token);
if (index >= 0) {
r = mHistory.get(index);
@@ -1094,6 +1215,9 @@
ActivityRecord r = null;
synchronized (mService) {
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
int index = indexOfTokenLocked(token);
if (index >= 0) {
r = mHistory.get(index);
@@ -1306,6 +1430,9 @@
// If the top activity is not fullscreen, then we need to
// make sure any activities under it are now visible.
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
final int count = mHistory.size();
int i = count-1;
while (mHistory.get(i) != top) {
@@ -1868,6 +1995,7 @@
Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
here);
}
+ r.task.addActivityToTop(r);
mHistory.add(addPos, r);
r.putInHistory();
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
@@ -1907,6 +2035,7 @@
here.fillInStackTrace();
Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
}
+ r.task.addActivityToTop(r);
mHistory.add(addPos, r);
r.putInHistory();
r.frontOfTask = newTask;
@@ -1986,6 +2115,9 @@
if (doResume) {
resumeTopActivityLocked(null);
}
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
}
final void validateAppTokensLocked() {
@@ -2107,8 +2239,8 @@
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
- target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
- null, false);
+ target.setTask(createTaskRecord(mService.mCurTask, target.info, null,
+ false), null, false);
target.task.affinityIntent = target.intent;
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ " out to new task " + target.task);
@@ -2172,8 +2304,7 @@
// like these are all in the reply chain.
replyChainEnd = targetI+1;
while (replyChainEnd < mHistory.size() &&
- (mHistory.get(
- replyChainEnd)).task == task) {
+ (mHistory.get(replyChainEnd)).task == task) {
replyChainEnd++;
}
replyChainEnd--;
@@ -2346,6 +2477,9 @@
}
}
+ if (VALIDATE_TASK_REPLACE) {
+ verifyActivityRecords();
+ }
return taskTop;
}
@@ -3011,7 +3145,7 @@
if (mService.mCurTask <= 0) {
mService.mCurTask = 1;
}
- r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
+ r.setTask(createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new task " + r.task);
} else {
@@ -3075,7 +3209,7 @@
N > 0 ? mHistory.get(N-1) : null;
r.setTask(prev != null
? prev.task
- : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
+ : createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new guessed " + r.task);
}
@@ -4160,6 +4294,9 @@
here.fillInStackTrace();
Slog.i(TAG, "Removing activity " + r + " from stack");
}
+ if (r.task != null) {
+ r.task.removeActivity(r);
+ }
mHistory.remove(r);
r.takeFromHistory();
removeTimeoutsForActivityLocked(r);
@@ -5169,4 +5306,185 @@
return starting;
}
+
+ void verifyActivityRecords() {
+ /* Until we have activity movement implemented for tasks just do the simple test
+ ActivityIterator iterator = new ActivityIterator();
+ int i;
+ int N = mHistory.size();
+ for (i = 0; i < N && iterator.hasNext(); ++i) {
+ ActivityRecord r1 = mHistory.get(i);
+ ActivityRecord r2 = iterator.next();
+ if (r1 != r2) {
+ break;
+ }
+ }
+ if (i != N || iterator.hasNext()) {
+ Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
+ + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
+ } */
+ // Simple test
+ ActivityIterator iterator = new ActivityIterator();
+ while (iterator.hasNext()) {
+ ActivityRecord r = iterator.next();
+ if (!mHistory.contains(r)) {
+ break;
+ }
+ }
+ if (iterator.size() != mHistory.size() || iterator.hasNext()) {
+ Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
+ + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
+ }
+ }
+
+ private TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+ boolean toTop) {
+ TaskRecord oldTask = mTaskIdToTaskRecord.get(taskId);
+ if (oldTask != null) {
+ Slog.w(TAG, "createTaskRecord: Reusing taskId=" + taskId + " without removing");
+ mTaskHistory.remove(oldTask);
+ }
+ TaskRecord task = new TaskRecord(taskId, info, intent);
+ mTaskIdToTaskRecord.put(taskId, task);
+ if (toTop) {
+ mTaskHistory.add(task);
+ } else {
+ mTaskHistory.add(0, task);
+ }
+ return task;
+ }
+
+ class TaskIterator implements Iterator<TaskRecord> {
+ private int mCur;
+ private boolean mReverse;
+
+ TaskIterator() {
+ this(FORWARD_ITERATOR);
+ }
+
+ TaskIterator(boolean reverse) {
+ reset(reverse);
+ }
+
+ public void reset(boolean reverse) {
+ mReverse = reverse;
+ mCur = reverse ? mTaskHistory.size() - 1 : 0;
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (mReverse) {
+ return mCur >= 0;
+ }
+ return mCur < mTaskHistory.size();
+ }
+
+ @Override
+ public TaskRecord next() {
+ if (hasNext()) {
+ TaskRecord task = mTaskHistory.get(mCur);
+ mCur += (mReverse ? -1 : 1);
+ return task;
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ class ActivityIterator implements Iterator<ActivityRecord> {
+ final TaskIterator mIterator;
+ boolean mReverse;
+ int mCur;
+ TaskRecord mTaskRecord;
+ final boolean mSkipFinishing;
+
+ public ActivityIterator() {
+ this(FORWARD_ITERATOR);
+ }
+
+ public ActivityIterator(boolean reverse) {
+ this(reverse, false);
+ }
+
+ public ActivityIterator(boolean reverse, boolean skipFinishing) {
+ mSkipFinishing = skipFinishing;
+ mIterator = new TaskIterator();
+ reset(reverse);
+ }
+
+ public void reset(boolean reverse) {
+ mReverse = reverse;
+ mIterator.reset(reverse);
+ getNextTaskRecord();
+ }
+
+ private void getNextTaskRecord() {
+ if (mIterator.hasNext()) {
+ mTaskRecord = mIterator.next();
+ mCur = mReverse ? mTaskRecord.mActivities.size() - 1 : 0;
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (mTaskRecord == null) {
+ return false;
+ }
+ if (mReverse) {
+ return mCur >= 0;
+ }
+ return mCur < mTaskRecord.mActivities.size();
+ }
+
+ @Override
+ public ActivityRecord next() {
+ while (hasNext()) {
+ ActivityRecord r = mTaskRecord.mActivities.get(mCur);
+ mCur += mReverse ? -1 : 1;
+ if (!hasNext()) {
+ getNextTaskRecord();
+ }
+ if (mSkipFinishing && r.finishing) {
+ continue;
+ }
+ return r;
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ int size() {
+ int size = 0;
+ final TaskIterator iterator = new TaskIterator();
+ while (iterator.hasNext()) {
+ size += iterator.next().mActivities.size();
+ }
+ return size;
+ }
+
+ ActivityRecord peek() {
+ if (mTaskRecord != null && mCur >= 0 && mCur < mTaskRecord.mActivities.size()) {
+ return mTaskRecord.mActivities.get(mCur);
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < mTaskHistory.size(); ++i) {
+ final TaskRecord task = mTaskHistory.get(i);
+ sb.append("task_").append(i).append("-").append(task.mActivities).append(" ");
+ }
+ return sb.toString();
+ }
+ }
}
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 1bae9ca..347aa7d 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -23,6 +23,7 @@
import android.util.Slog;
import java.io.PrintWriter;
+import java.util.ArrayList;
class TaskRecord extends ThumbnailHolder {
final int taskId; // Unique identifier for this task.
@@ -39,7 +40,11 @@
String stringName; // caching of toString() result.
int userId; // user for which this task was created
-
+
+ int numFullscreen; // Number of fullscreen activities.
+
+ final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
+
TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
taskId = _taskId;
affinity = info.taskAffinity;
@@ -104,12 +109,49 @@
userId = UserHandle.getUserId(info.applicationInfo.uid);
}
}
-
+
+ ActivityRecord getTopActivity() {
+ for (int i = mActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.finishing) {
+ continue;
+ }
+ return r;
+ }
+ return null;
+ }
+
+ void addActivityAtBottom(ActivityRecord r) {
+ if (!mActivities.remove(r) && r.fullscreen) {
+ // Was not previously in list.
+ numFullscreen++;
+ }
+ mActivities.add(0, r);
+ }
+
+ void addActivityToTop(ActivityRecord r) {
+ if (!mActivities.remove(r) && r.fullscreen) {
+ // Was not previously in list.
+ numFullscreen++;
+ }
+ mActivities.add(r);
+ }
+
+ /** @return true if this was the last activity in the task */
+ boolean removeActivity(ActivityRecord r) {
+ if (mActivities.remove(r) && r.fullscreen) {
+ // Was previously in list.
+ numFullscreen--;
+ }
+ return mActivities.size() == 0;
+ }
+
void dump(PrintWriter pw, String prefix) {
if (numActivities != 0 || rootWasReset || userId != 0) {
pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
pw.print(" rootWasReset="); pw.print(rootWasReset);
- pw.print(" userId="); pw.println(userId);
+ pw.print(" userId="); pw.print(userId);
+ pw.print(" numFullscreen="); pw.println(numFullscreen);
}
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);
@@ -136,6 +178,7 @@
pw.print(prefix); pw.print("realActivity=");
pw.println(realActivity.flattenToShortString());
}
+ pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
if (!askedCompatMode) {
pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
}
@@ -146,6 +189,7 @@
pw.print((getInactiveDuration()/1000)); pw.println("s)");
}
+ @Override
public String toString() {
if (stringName != null) {
return stringName;
@@ -156,19 +200,21 @@
sb.append(" #");
sb.append(taskId);
if (affinity != null) {
- sb.append(" A ");
+ sb.append(" A=");
sb.append(affinity);
} else if (intent != null) {
- sb.append(" I ");
+ sb.append(" I=");
sb.append(intent.getComponent().flattenToShortString());
} else if (affinityIntent != null) {
- sb.append(" aI ");
+ sb.append(" aI=");
sb.append(affinityIntent.getComponent().flattenToShortString());
} else {
sb.append(" ??");
}
- sb.append(" U ");
+ sb.append(" U=");
sb.append(userId);
+ sb.append(" sz=");
+ sb.append(mActivities.size());
sb.append('}');
return stringName = sb.toString();
}
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index cc7c8b0..938fa5c 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -228,6 +228,10 @@
public void remove() {
throw new IllegalArgumentException();
}
+
+ @Override public String toString() {
+ return mTaskLists.toString();
+ }
}
class AppTokenIterator implements Iterator<AppWindowToken> {
@@ -294,6 +298,10 @@
}
return size;
}
+
+ @Override public String toString() {
+ return mIterator.toString();
+ }
}
public void dump(String prefix, PrintWriter pw) {
diff --git a/services/java/com/android/server/wm/TaskGroup.java b/services/java/com/android/server/wm/TaskGroup.java
index 5e82af2..1f1dd58 100644
--- a/services/java/com/android/server/wm/TaskGroup.java
+++ b/services/java/com/android/server/wm/TaskGroup.java
@@ -23,4 +23,9 @@
public class TaskGroup {
public int taskId = -1;
public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>();
+
+ @Override
+ public String toString() {
+ return "id=" + taskId + " tokens=" + tokens;
+ }
}
diff --git a/services/java/com/android/server/wm/TaskList.java b/services/java/com/android/server/wm/TaskList.java
index 88791f2..67dfa4f 100644
--- a/services/java/com/android/server/wm/TaskList.java
+++ b/services/java/com/android/server/wm/TaskList.java
@@ -27,4 +27,9 @@
mAppTokens.add(wtoken);
mDisplayContent = displayContent;
}
+
+ @Override
+ public String toString() {
+ return "id=" + taskId + " appTokens=" + mAppTokens;
+ }
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b7637b9..8cbacdc 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3124,8 +3124,9 @@
return;
}
+ boolean mismatch = false;
AppTokenIterator iterator = displayContent.getTmpAppIterator(REVERSE_ITERATOR);
- for ( ; t >= 0; --t) {
+ for ( ; t >= 0 && !mismatch; --t) {
task = tasks.get(t);
List<IApplicationToken> tokens = task.tokens;
int v = task.tokens.size() - 1;
@@ -3137,28 +3138,22 @@
return;
}
- while (v >= 0 && iterator.hasNext()) {
+ while (v >= 0) {
AppWindowToken atoken = iterator.next();
if (atoken.removed) {
continue;
}
if (tokens.get(v) != atoken.token) {
- Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
- + " @ " + v + ", internal is " + atoken.token);
+ mismatch = true;
+ break;
}
v--;
}
- while (v >= 0) {
- Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
- v--;
- }
}
- while (iterator.hasNext()) {
- AppWindowToken atoken = iterator.next();
- if (!atoken.removed) {
- Slog.w(TAG, "Invalid internal atoken: " + atoken.token);
- }
+ if (mismatch || iterator.hasNext()) {
+ Slog.w(TAG, "validateAppTokens: Mismatch! ActivityManager=" + tasks
+ + " WindowManager=" + iterator);
}
}
}