diff options
| -rwxr-xr-x | services/core/java/com/android/server/am/ActivityManagerService.java | 128 |
1 files changed, 83 insertions, 45 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a9a47327ead6..2fd1142b3185 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -412,7 +412,7 @@ public final class ActivityManagerService extends ActivityManagerNative * List of intents that were used to start the most recent tasks. */ ArrayList<TaskRecord> mRecentTasks; - ArraySet<TaskRecord> mTmpRecents = new ArraySet<TaskRecord>(); + ArrayList<TaskRecord> mTmpRecents = new ArrayList<TaskRecord>(); /** * For addAppTask: cached of the last activity component that was added. @@ -3841,6 +3841,86 @@ public final class ActivityManagerService extends ActivityManagerNative mTaskPersister.wakeup(null, true); } + // Sort by taskId + private Comparator<TaskRecord> mTaskRecordComparator = new Comparator<TaskRecord>() { + @Override + public int compare(TaskRecord lhs, TaskRecord rhs) { + return rhs.taskId - lhs.taskId; + } + }; + + // Extract the affiliates of the chain containing mRecentTasks[start]. + private int processNextAffiliateChain(int start) { + final TaskRecord startTask = mRecentTasks.get(start); + final int affiliateId = startTask.mAffiliatedTaskId; + + // Quick identification of isolated tasks. I.e. those not launched behind. + if (startTask.taskId == affiliateId && startTask.mPrevAffiliate == null && + startTask.mNextAffiliate == null) { + // There is still a slim chance that there are other tasks that point to this task + // and that the chain is so messed up that this task no longer points to them but + // the gain of this optimization outweighs the risk. + startTask.inRecents = true; + return start + 1; + } + + // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents. + mTmpRecents.clear(); + for (int i = mRecentTasks.size() - 1; i >= start; --i) { + final TaskRecord task = mRecentTasks.get(i); + if (task.mAffiliatedTaskId == affiliateId) { + mRecentTasks.remove(i); + mTmpRecents.add(task); + } + } + + // Sort them all by taskId. That is the order they were create in and that order will + // always be correct. + Collections.sort(mTmpRecents, mTaskRecordComparator); + + // Go through and fix up the linked list. + // The first one is the end of the chain and has no next. + final TaskRecord first = mTmpRecents.get(0); + first.inRecents = true; + if (first.mNextAffiliate != null) { + Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate); + first.setNextAffiliate(null); + mTaskPersister.wakeup(first, false); + } + // Everything in the middle is doubly linked from next to prev. + final int tmpSize = mTmpRecents.size(); + for (int i = 0; i < tmpSize - 1; ++i) { + final TaskRecord next = mTmpRecents.get(i); + final TaskRecord prev = mTmpRecents.get(i + 1); + if (next.mPrevAffiliate != prev) { + Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate + + " setting prev=" + prev); + next.setPrevAffiliate(prev); + mTaskPersister.wakeup(next, false); + } + if (prev.mNextAffiliate != next) { + Slog.w(TAG, "Link error 3 prev=" + prev + " next=" + prev.mNextAffiliate + + " setting next=" + next); + prev.setNextAffiliate(next); + mTaskPersister.wakeup(prev, false); + } + prev.inRecents = true; + } + // The last one is the beginning of the list and has no prev. + final TaskRecord last = mTmpRecents.get(tmpSize - 1); + if (last.mPrevAffiliate != null) { + Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate); + last.setPrevAffiliate(null); + mTaskPersister.wakeup(last, false); + } + + // Insert the group back into mRecentTasks at start. + mRecentTasks.addAll(start, mTmpRecents); + + // Let the caller know where we left off. + return start + tmpSize; + } + /** * Update the recent tasks lists: make sure tasks should still be here (their * applications / activities still exist), update their availability, fixup ordering @@ -3953,51 +4033,9 @@ public final class ActivityManagerService extends ActivityManagerNative } // Verify the affiliate chain for each task. - for (int i = 0; i < N; ) { - TaskRecord task = mRecentTasks.remove(i); - if (mTmpRecents.contains(task)) { - continue; - } - int affiliatedTaskId = task.mAffiliatedTaskId; - while (true) { - TaskRecord next = task.mNextAffiliate; - if (next == null) { - break; - } - if (next.mAffiliatedTaskId != affiliatedTaskId) { - Slog.e(TAG, "Error in Recents: next.affiliatedTaskId=" + - next.mAffiliatedTaskId + " affiliatedTaskId=" + affiliatedTaskId); - task.setNextAffiliate(null); - if (next.mPrevAffiliate == task) { - next.setPrevAffiliate(null); - } - break; - } - if (next.mPrevAffiliate != task) { - Slog.e(TAG, "Error in Recents chain prev.mNextAffiliate=" + - next.mPrevAffiliate + " task=" + task); - next.setPrevAffiliate(null); - task.setNextAffiliate(null); - break; - } - if (!mRecentTasks.contains(next)) { - Slog.e(TAG, "Error in Recents: next=" + next + " not in mRecentTasks"); - task.setNextAffiliate(null); - // We know that next.mPrevAffiliate is always task, from above, so clear - // its previous affiliate. - next.setPrevAffiliate(null); - break; - } - task = next; - } - // task is now the end of the list - do { - mRecentTasks.remove(task); - mRecentTasks.add(i++, task); - mTmpRecents.add(task); - task.inRecents = true; - } while ((task = task.mPrevAffiliate) != null); + for (int i = 0; i < N; i = processNextAffiliateChain(i)) { } + mTmpRecents.clear(); // mRecentTasks is now in sorted, affiliated order. } |