Loading services/java/com/android/server/am/ActivityRecord.java +5 −1 Original line number Diff line number Diff line Loading @@ -471,6 +471,7 @@ final class ActivityRecord { void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) { if (inHistory && !finishing) { if (task != null) { task.removeActivity(this); task.numActivities--; } if (newTask != null) { Loading Loading @@ -505,6 +506,7 @@ final class ActivityRecord { inHistory = false; if (task != null && !finishing) { task.numActivities--; task = null; } clearOptionsLocked(); } Loading Loading @@ -539,7 +541,7 @@ final class ActivityRecord { ActivityResult r = new ActivityResult(from, resultWho, requestCode, resultCode, resultData); if (results == null) { results = new ArrayList(); results = new ArrayList<ResultInfo>(); } results.add(r); } Loading Loading @@ -950,6 +952,8 @@ final class ActivityRecord { 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(' '); Loading services/java/com/android/server/am/ActivityStack.java +329 −11 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import android.graphics.Bitmap; 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; Loading @@ -66,6 +67,7 @@ import android.os.UserHandle; import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.view.Display; import java.io.FileDescriptor; Loading @@ -75,6 +77,7 @@ import java.lang.ref.WeakReference; 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. Loading @@ -98,6 +101,7 @@ final class ActivityStack { 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. Loading Loading @@ -138,6 +142,9 @@ final class ActivityStack { // 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, Loading @@ -161,6 +168,17 @@ final class ActivityStack { */ 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. */ Loading Loading @@ -289,6 +307,12 @@ final class ActivityStack { */ 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. Loading Loading @@ -508,29 +532,68 @@ final class ActivityStack { } 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); Loading Loading @@ -624,17 +687,29 @@ final class ActivityStack { * @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; Loading @@ -651,7 +726,44 @@ final class ActivityStack { } } // 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; } Loading Loading @@ -889,6 +1001,9 @@ final class ActivityStack { 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); Loading Loading @@ -933,6 +1048,9 @@ final class ActivityStack { // 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) { Loading Loading @@ -1077,6 +1195,9 @@ final class ActivityStack { ActivityRecord r = null; synchronized (mService) { if (VALIDATE_TASK_REPLACE) { verifyActivityRecords(); } int index = indexOfTokenLocked(token); if (index >= 0) { r = mHistory.get(index); Loading @@ -1094,6 +1215,9 @@ final class ActivityStack { ActivityRecord r = null; synchronized (mService) { if (VALIDATE_TASK_REPLACE) { verifyActivityRecords(); } int index = indexOfTokenLocked(token); if (index >= 0) { r = mHistory.get(index); Loading Loading @@ -1306,6 +1430,9 @@ final class ActivityStack { // 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) { Loading Loading @@ -1868,6 +1995,7 @@ final class ActivityStack { 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, Loading Loading @@ -1907,6 +2035,7 @@ final class ActivityStack { 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; Loading Loading @@ -1986,6 +2115,9 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } if (VALIDATE_TASK_REPLACE) { verifyActivityRecords(); } } final void validateAppTokensLocked() { Loading Loading @@ -2107,8 +2239,8 @@ final class ActivityStack { 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); Loading Loading @@ -2172,8 +2304,7 @@ final class ActivityStack { // 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--; Loading Loading @@ -2346,6 +2477,9 @@ final class ActivityStack { } } if (VALIDATE_TASK_REPLACE) { verifyActivityRecords(); } return taskTop; } Loading Loading @@ -3011,7 +3145,7 @@ final class ActivityStack { 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 { Loading Loading @@ -3075,7 +3209,7 @@ final class ActivityStack { 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); } Loading Loading @@ -4160,6 +4294,9 @@ final class ActivityStack { 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); Loading Loading @@ -5169,4 +5306,185 @@ final class ActivityStack { 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(); } } } services/java/com/android/server/am/TaskRecord.java +53 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.UserHandle; import android.util.Slog; import java.io.PrintWriter; import java.util.ArrayList; class TaskRecord extends ThumbnailHolder { final int taskId; // Unique identifier for this task. Loading @@ -40,6 +41,10 @@ class TaskRecord extends ThumbnailHolder { 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; Loading Loading @@ -105,11 +110,48 @@ class TaskRecord extends ThumbnailHolder { } } 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); Loading @@ -136,6 +178,7 @@ class TaskRecord extends ThumbnailHolder { 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); } Loading @@ -146,6 +189,7 @@ class TaskRecord extends ThumbnailHolder { pw.print((getInactiveDuration()/1000)); pw.println("s)"); } @Override public String toString() { if (stringName != null) { return stringName; Loading @@ -156,19 +200,21 @@ class TaskRecord extends ThumbnailHolder { 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(); } Loading services/java/com/android/server/wm/DisplayContent.java +8 −0 Original line number Diff line number Diff line Loading @@ -228,6 +228,10 @@ class DisplayContent { public void remove() { throw new IllegalArgumentException(); } @Override public String toString() { return mTaskLists.toString(); } } class AppTokenIterator implements Iterator<AppWindowToken> { Loading Loading @@ -294,6 +298,10 @@ class DisplayContent { } return size; } @Override public String toString() { return mIterator.toString(); } } public void dump(String prefix, PrintWriter pw) { Loading services/java/com/android/server/wm/TaskGroup.java +5 −0 Original line number Diff line number Diff line Loading @@ -23,4 +23,9 @@ import java.util.ArrayList; public class TaskGroup { public int taskId = -1; public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>(); @Override public String toString() { return "id=" + taskId + " tokens=" + tokens; } } Loading
services/java/com/android/server/am/ActivityRecord.java +5 −1 Original line number Diff line number Diff line Loading @@ -471,6 +471,7 @@ final class ActivityRecord { void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) { if (inHistory && !finishing) { if (task != null) { task.removeActivity(this); task.numActivities--; } if (newTask != null) { Loading Loading @@ -505,6 +506,7 @@ final class ActivityRecord { inHistory = false; if (task != null && !finishing) { task.numActivities--; task = null; } clearOptionsLocked(); } Loading Loading @@ -539,7 +541,7 @@ final class ActivityRecord { ActivityResult r = new ActivityResult(from, resultWho, requestCode, resultCode, resultData); if (results == null) { results = new ArrayList(); results = new ArrayList<ResultInfo>(); } results.add(r); } Loading Loading @@ -950,6 +952,8 @@ final class ActivityRecord { 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(' '); Loading
services/java/com/android/server/am/ActivityStack.java +329 −11 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ import android.graphics.Bitmap; 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; Loading @@ -66,6 +67,7 @@ import android.os.UserHandle; import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.view.Display; import java.io.FileDescriptor; Loading @@ -75,6 +77,7 @@ import java.lang.ref.WeakReference; 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. Loading @@ -98,6 +101,7 @@ final class ActivityStack { 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. Loading Loading @@ -138,6 +142,9 @@ final class ActivityStack { // 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, Loading @@ -161,6 +168,17 @@ final class ActivityStack { */ 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. */ Loading Loading @@ -289,6 +307,12 @@ final class ActivityStack { */ 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. Loading Loading @@ -508,29 +532,68 @@ final class ActivityStack { } 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); Loading Loading @@ -624,17 +687,29 @@ final class ActivityStack { * @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; Loading @@ -651,7 +726,44 @@ final class ActivityStack { } } // 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; } Loading Loading @@ -889,6 +1001,9 @@ final class ActivityStack { 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); Loading Loading @@ -933,6 +1048,9 @@ final class ActivityStack { // 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) { Loading Loading @@ -1077,6 +1195,9 @@ final class ActivityStack { ActivityRecord r = null; synchronized (mService) { if (VALIDATE_TASK_REPLACE) { verifyActivityRecords(); } int index = indexOfTokenLocked(token); if (index >= 0) { r = mHistory.get(index); Loading @@ -1094,6 +1215,9 @@ final class ActivityStack { ActivityRecord r = null; synchronized (mService) { if (VALIDATE_TASK_REPLACE) { verifyActivityRecords(); } int index = indexOfTokenLocked(token); if (index >= 0) { r = mHistory.get(index); Loading Loading @@ -1306,6 +1430,9 @@ final class ActivityStack { // 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) { Loading Loading @@ -1868,6 +1995,7 @@ final class ActivityStack { 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, Loading Loading @@ -1907,6 +2035,7 @@ final class ActivityStack { 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; Loading Loading @@ -1986,6 +2115,9 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } if (VALIDATE_TASK_REPLACE) { verifyActivityRecords(); } } final void validateAppTokensLocked() { Loading Loading @@ -2107,8 +2239,8 @@ final class ActivityStack { 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); Loading Loading @@ -2172,8 +2304,7 @@ final class ActivityStack { // 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--; Loading Loading @@ -2346,6 +2477,9 @@ final class ActivityStack { } } if (VALIDATE_TASK_REPLACE) { verifyActivityRecords(); } return taskTop; } Loading Loading @@ -3011,7 +3145,7 @@ final class ActivityStack { 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 { Loading Loading @@ -3075,7 +3209,7 @@ final class ActivityStack { 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); } Loading Loading @@ -4160,6 +4294,9 @@ final class ActivityStack { 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); Loading Loading @@ -5169,4 +5306,185 @@ final class ActivityStack { 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(); } } }
services/java/com/android/server/am/TaskRecord.java +53 −7 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.UserHandle; import android.util.Slog; import java.io.PrintWriter; import java.util.ArrayList; class TaskRecord extends ThumbnailHolder { final int taskId; // Unique identifier for this task. Loading @@ -40,6 +41,10 @@ class TaskRecord extends ThumbnailHolder { 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; Loading Loading @@ -105,11 +110,48 @@ class TaskRecord extends ThumbnailHolder { } } 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); Loading @@ -136,6 +178,7 @@ class TaskRecord extends ThumbnailHolder { 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); } Loading @@ -146,6 +189,7 @@ class TaskRecord extends ThumbnailHolder { pw.print((getInactiveDuration()/1000)); pw.println("s)"); } @Override public String toString() { if (stringName != null) { return stringName; Loading @@ -156,19 +200,21 @@ class TaskRecord extends ThumbnailHolder { 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(); } Loading
services/java/com/android/server/wm/DisplayContent.java +8 −0 Original line number Diff line number Diff line Loading @@ -228,6 +228,10 @@ class DisplayContent { public void remove() { throw new IllegalArgumentException(); } @Override public String toString() { return mTaskLists.toString(); } } class AppTokenIterator implements Iterator<AppWindowToken> { Loading Loading @@ -294,6 +298,10 @@ class DisplayContent { } return size; } @Override public String toString() { return mIterator.toString(); } } public void dump(String prefix, PrintWriter pw) { Loading
services/java/com/android/server/wm/TaskGroup.java +5 −0 Original line number Diff line number Diff line Loading @@ -23,4 +23,9 @@ import java.util.ArrayList; public class TaskGroup { public int taskId = -1; public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>(); @Override public String toString() { return "id=" + taskId + " tokens=" + tokens; } }