diff options
9 files changed, 493 insertions, 129 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 586e7d4..2eeacae 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -67,6 +67,8 @@ public class ActivityManager { private static String TAG = "ActivityManager"; private static boolean localLOGV = false; + private static int gMaxRecentTasks = -1; + private final Context mContext; private final Handler mHandler; @@ -449,7 +451,7 @@ public class ActivityManager { // Really brain dead right now -- just take this from the configured // vm heap size, and assume it is in megabytes and thus ends with "m". String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m"); - return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1)); + return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length() - 1)); } /** @@ -480,6 +482,33 @@ public class ActivityManager { } /** + * Return the maximum number of recents entries that we will maintain and show. + * @hide + */ + static public int getMaxRecentTasksStatic() { + if (gMaxRecentTasks < 0) { + return gMaxRecentTasks = isLowRamDeviceStatic() ? 50 : 100; + } + return gMaxRecentTasks; + } + + /** + * Return the default limit on the number of recents that an app can make. + * @hide + */ + static public int getDefaultAppRecentsLimitStatic() { + return getMaxRecentTasksStatic() / 6; + } + + /** + * Return the maximum limit on the number of recents that an app can make. + * @hide + */ + static public int getMaxAppRecentsLimitStatic() { + return getMaxRecentTasksStatic() / 2; + } + + /** * Information you can set and retrieve about the current activity within the recent task list. */ public static class TaskDescription implements Parcelable { @@ -1191,13 +1220,13 @@ public class ActivityManager { public void writeToParcel(Parcel dest, int flags) { if (mainThumbnail != null) { dest.writeInt(1); - mainThumbnail.writeToParcel(dest, 0); + mainThumbnail.writeToParcel(dest, flags); } else { dest.writeInt(0); } if (thumbnailFileDescriptor != null) { dest.writeInt(1); - thumbnailFileDescriptor.writeToParcel(dest, 0); + thumbnailFileDescriptor.writeToParcel(dest, flags); } else { dest.writeInt(0); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index b09d3ac..6d40dcf 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -25,6 +25,7 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; +import android.app.ActivityManager; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; @@ -3077,7 +3078,7 @@ public class PackageParser { ActivityInfo.DOCUMENT_LAUNCH_NONE); a.info.maxRecents = sa.getInt( com.android.internal.R.styleable.AndroidManifestActivity_maxRecents, - 15); + ActivityManager.getDefaultAppRecentsLimitStatic()); a.info.screenOrientation = sa.getInt( com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index fa00ebf..e940b18 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -145,8 +145,6 @@ <integer name="recents_animate_task_view_remove_duration">250</integer> <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. --> <integer name="recents_max_task_stack_view_dim">96</integer> - <!-- The number of tasks that RecentsTaskLoader should load. --> - <integer name="recents_max_num_tasks_to_load">50</integer> <!-- The delay to enforce between each alt-tab key press. --> <integer name="recents_alt_tab_key_delay">200</integer> <!-- Transposes the recents layout in landscape. --> diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index b7f6451..9803687 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -16,6 +16,7 @@ package com.android.systemui.recents; +import android.app.ActivityManager; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; @@ -187,7 +188,7 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_filter_animate_new_views_duration); // Loading - maxNumTasksToLoad = res.getInteger(R.integer.recents_max_num_tasks_to_load); + maxNumTasksToLoad = ActivityManager.getMaxRecentTasksStatic(); // Search Bar searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e2a6534..eff420f 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -283,9 +283,6 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); - // Maximum number of recent tasks that we can remember. - static final int MAX_RECENT_TASKS = ActivityManager.isLowRamDeviceStatic() ? 100 : 200; - // Maximum number recent bitmaps to keep in memory. static final int MAX_RECENT_BITMAPS = 5; @@ -3808,8 +3805,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (tr.userId == userId) { if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr + " when finishing user" + userId); - tr.disposeThumbnail(); mRecentTasks.remove(i); + tr.removedFromRecents(mTaskPersister); } } @@ -3817,25 +3814,385 @@ public final class ActivityManagerService extends ActivityManagerNative mTaskPersister.wakeup(null, true); } + /** + * Update the recent tasks lists: make sure tasks should still be here (their + * applications / activities still exist), update their availability, fixup ordering + * of affiliations. + */ + void cleanupRecentTasksLocked(int userId) { + final HashMap<ComponentName, ActivityInfo> availActCache = new HashMap<>(); + final HashMap<String, ApplicationInfo> availAppCache = new HashMap<>(); + final IPackageManager pm = AppGlobals.getPackageManager(); + final ActivityInfo dummyAct = new ActivityInfo(); + final ApplicationInfo dummyApp = new ApplicationInfo(); + + int N = mRecentTasks.size(); + + int[] users = userId == UserHandle.USER_ALL + ? getUsersLocked() : new int[] { userId }; + for (int user : users) { + for (int i = 0; i < N; i++) { + TaskRecord task = mRecentTasks.get(i); + if (task.userId != user) { + // Only look at tasks for the user ID of interest. + continue; + } + if (task.autoRemoveRecents && task.getTopActivity() == null) { + // This situation is broken, and we should just get rid of it now. + mRecentTasks.remove(i); + task.removedFromRecents(mTaskPersister); + i--; + N--; + Slog.w(TAG, "Removing auto-remove without activity: " + task); + continue; + } + // Check whether this activity is currently available. + if (task.realActivity != null) { + ActivityInfo ai = availActCache.get(task.realActivity); + if (ai == null) { + try { + ai = pm.getActivityInfo(task.realActivity, + PackageManager.GET_UNINSTALLED_PACKAGES + | PackageManager.GET_DISABLED_COMPONENTS, user); + } catch (RemoteException e) { + // Will never happen. + continue; + } + if (ai == null) { + ai = dummyAct; + } + availActCache.put(task.realActivity, ai); + } + if (ai == dummyAct) { + // This could be either because the activity no longer exists, or the + // app is temporarily gone. For the former we want to remove the recents + // entry; for the latter we want to mark it as unavailable. + ApplicationInfo app = availAppCache.get(task.realActivity.getPackageName()); + if (app == null) { + try { + app = pm.getApplicationInfo(task.realActivity.getPackageName(), + PackageManager.GET_UNINSTALLED_PACKAGES + | PackageManager.GET_DISABLED_COMPONENTS, user); + } catch (RemoteException e) { + // Will never happen. + continue; + } + if (app == null) { + app = dummyApp; + } + availAppCache.put(task.realActivity.getPackageName(), app); + } + if (app == dummyApp || (app.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { + // Doesn't exist any more! Good-bye. + mRecentTasks.remove(i); + task.removedFromRecents(mTaskPersister); + i--; + N--; + Slog.w(TAG, "Removing no longer valid recent: " + task); + continue; + } else { + // Otherwise just not available for now. + if (task.isAvailable) { + if (DEBUG_RECENTS) Slog.d(TAG, "Making recent unavailable: " + + task); + } + task.isAvailable = false; + } + } else { + if (!ai.enabled || !ai.applicationInfo.enabled + || (ai.applicationInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { + if (task.isAvailable) { + if (DEBUG_RECENTS) Slog.d(TAG, "Making recent unavailable: " + + task + " (enabled=" + ai.enabled + "/" + + ai.applicationInfo.enabled + " flags=" + + Integer.toHexString(ai.applicationInfo.flags) + ")"); + } + task.isAvailable = false; + } else { + if (!task.isAvailable) { + if (DEBUG_RECENTS) Slog.d(TAG, "Making recent available: " + + task); + } + task.isAvailable = true; + } + } + } + } + } + + // 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); + } + mTmpRecents.clear(); + // mRecentTasks is now in sorted, affiliated order. + } + + private final boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) { + int N = mRecentTasks.size(); + TaskRecord top = task; + int topIndex = taskIndex; + while (top.mNextAffiliate != null && topIndex > 0) { + top = top.mNextAffiliate; + topIndex--; + } + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding affilliates starting at " + + topIndex + " from intial " + taskIndex); + // Find the end of the chain, doing a sanity check along the way. + boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId; + int endIndex = topIndex; + TaskRecord prev = top; + while (endIndex < N) { + TaskRecord cur = mRecentTasks.get(endIndex); + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: looking at next chain @" + + endIndex + " " + cur); + if (cur == top) { + // Verify start of the chain. + if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != -1) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": first task has next affiliate: " + prev); + sane = false; + break; + } + } else { + // Verify middle of the chain's next points back to the one before. + if (cur.mNextAffiliate != prev + || cur.mNextAffiliateTaskId != prev.taskId) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": middle task " + cur + " @" + endIndex + + " has bad next affiliate " + + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId + + ", expected " + prev); + sane = false; + break; + } + } + if (cur.mPrevAffiliateTaskId == -1) { + // Chain ends here. + if (cur.mPrevAffiliate != null) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": last task " + cur + " has previous affiliate " + + cur.mPrevAffiliate); + sane = false; + } + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: end of chain @" + endIndex); + break; + } else { + // Verify middle of the chain's prev points to a valid item. + if (cur.mPrevAffiliate == null) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": task " + cur + " has previous affiliate " + + cur.mPrevAffiliate + " but should be id " + + cur.mPrevAffiliate); + sane = false; + break; + } + } + if (cur.mAffiliatedTaskId != task.mAffiliatedTaskId) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": task " + cur + " has affiliated id " + + cur.mAffiliatedTaskId + " but should be " + + task.mAffiliatedTaskId); + sane = false; + break; + } + prev = cur; + endIndex++; + if (endIndex >= N) { + Slog.wtf(TAG, "Bad chain ran off index " + endIndex + + ": last task " + prev); + sane = false; + break; + } + } + if (sane) { + if (endIndex < taskIndex) { + Slog.wtf(TAG, "Bad chain @" + endIndex + + ": did not extend to task " + task + " @" + taskIndex); + sane = false; + } + } + if (sane) { + // All looks good, we can just move all of the affiliated tasks + // to the top. + for (int i=topIndex; i<=endIndex; i++) { + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving affiliated " + task + + " from " + i + " to " + (i-topIndex)); + TaskRecord cur = mRecentTasks.remove(i); + mRecentTasks.add(i-topIndex, cur); + } + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: done moving tasks " + topIndex + + " to " + endIndex); + return true; + } + + // Whoops, couldn't do it. + return false; + } + final void addRecentTaskLocked(TaskRecord task) { - final int N = mRecentTasks.size(); + final boolean isAffiliated = task.mAffiliatedTaskId != task.taskId + || task.mNextAffiliateTaskId != -1 || task.mPrevAffiliateTaskId != -1; + + int N = mRecentTasks.size(); // Quick case: check if the top-most recent task is the same. - if (N > 0 && mRecentTasks.get(0) == task) { + if (!isAffiliated && N > 0 && mRecentTasks.get(0) == task) { + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: already at top: " + task); + return; + } + // Another quick case: check if this is part of a set of affiliated + // tasks that are at the top. + if (isAffiliated && N > 0 && task.inRecents + && task.mAffiliatedTaskId == mRecentTasks.get(0).mAffiliatedTaskId) { + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: affiliated " + mRecentTasks.get(0) + + " at top when adding " + task); return; } // Another quick case: never add voice sessions. if (task.voiceSession != null) { + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: not adding voice interaction " + task); return; } + boolean needAffiliationFix = false; + + // Slightly less quick case: the task is already in recents, so all we need + // to do is move it. + if (task.inRecents) { + int taskIndex = mRecentTasks.indexOf(task); + if (taskIndex >= 0) { + if (!isAffiliated) { + // Simple case: this is not an affiliated task, so we just move it to the front. + mRecentTasks.remove(taskIndex); + mRecentTasks.add(0, task); + notifyTaskPersisterLocked(task, false); + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving to top " + task + + " from " + taskIndex); + return; + } else { + // More complicated: need to keep all affiliated tasks together. + if (moveAffiliatedTasksToFront(task, taskIndex)) { + // All went well. + return; + } + + // Uh oh... something bad in the affiliation chain, try to rebuild + // everything and then go through our general path of adding a new task. + needAffiliationFix = true; + } + } else { + Slog.wtf(TAG, "Task with inRecent not in recents: " + task); + needAffiliationFix = true; + } + } + + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: trimming tasks for " + task); trimRecentsForTask(task, true); - if (N >= MAX_RECENT_TASKS) { + N = mRecentTasks.size(); + while (N >= ActivityManager.getMaxRecentTasksStatic()) { final TaskRecord tr = mRecentTasks.remove(N - 1); - tr.disposeThumbnail(); - tr.closeRecentsChain(); + tr.removedFromRecents(mTaskPersister); + N--; + } + task.inRecents = true; + if (!isAffiliated || needAffiliationFix) { + // If this is a simple non-affiliated task, or we had some failure trying to + // handle it as part of an affilated task, then just place it at the top. + mRecentTasks.add(0, task); + } else if (isAffiliated) { + // If this is a new affiliated task, then move all of the affiliated tasks + // to the front and insert this new one. + TaskRecord other = task.mNextAffiliate; + if (other == null) { + other = task.mPrevAffiliate; + } + if (other != null) { + int otherIndex = mRecentTasks.indexOf(other); + if (otherIndex >= 0) { + // Insert new task at appropriate location. + int taskIndex; + if (other == task.mNextAffiliate) { + // We found the index of our next affiliation, which is who is + // before us in the list, so add after that point. + taskIndex = otherIndex+1; + } else { + // We found the index of our previous affiliation, which is who is + // after us in the list, so add at their position. + taskIndex = otherIndex; + } + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: new affiliated task added at " + + taskIndex + ": " + task); + mRecentTasks.add(taskIndex, task); + + // Now move everything to the front. + if (moveAffiliatedTasksToFront(task, taskIndex)) { + // All went well. + return; + } + + // Uh oh... something bad in the affiliation chain, try to rebuild + // everything and then go through our general path of adding a new task. + needAffiliationFix = true; + } else { + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: couldn't find other affiliation " + + other); + needAffiliationFix = true; + } + } else { + if (DEBUG_RECENTS) Slog.d(TAG, + "addRecent: adding affiliated task without next/prev:" + task); + needAffiliationFix = true; + } + } + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding " + task); + + if (needAffiliationFix) { + if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: regrouping affiliations"); + cleanupRecentTasksLocked(task.userId); } - mRecentTasks.add(0, task); } /** @@ -3889,7 +4246,7 @@ public final class ActivityManagerService extends ActivityManagerNative tr.disposeThumbnail(); mRecentTasks.remove(i); if (task != tr) { - tr.closeRecentsChain(); + tr.removedFromRecents(mTaskPersister); } i--; N--; @@ -7689,8 +8046,6 @@ public final class ActivityManagerService extends ActivityManagerNative android.Manifest.permission.GET_DETAILED_TASKS) == PackageManager.PERMISSION_GRANTED; - IPackageManager pm = AppGlobals.getPackageManager(); - final int N = mRecentTasks.size(); ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<ActivityManager.RecentTaskInfo>( @@ -7704,53 +8059,6 @@ public final class ActivityManagerService extends ActivityManagerNative } includedUsers.add(Integer.valueOf(userId)); - // Regroup affiliated tasks together. - 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); - break; - } - if (!mRecentTasks.contains(next)) { - Slog.e(TAG, "Error in Recents: next=" + next + " not in mRecentTasks"); - task.setNextAffiliate(null); - if (next.mPrevAffiliate == task) { - 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); - } while ((task = task.mPrevAffiliate) != null); - } - mTmpRecents.clear(); - // mRecentTasks is now in sorted, affiliated order. - for (int i=0; i<N && maxNum > 0; i++) { TaskRecord tr = mRecentTasks.get(i); // Only add calling user or related users recent tasks @@ -7790,35 +8098,17 @@ public final class ActivityManagerService extends ActivityManagerNative + tr); continue; } + if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0 + && !tr.isAvailable) { + if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, unavail real act: " + tr); + continue; + } ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr); if (!detailed) { rti.baseIntent.replaceExtras((Bundle)null); } - if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0) { - // Check whether this activity is currently available. - try { - if (rti.origActivity != null) { - if (pm.getActivityInfo(rti.origActivity, 0, userId) - == null) { - if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, unavail orig act: " - + tr); - continue; - } - } else if (rti.baseIntent != null) { - if (pm.queryIntentActivities(rti.baseIntent, - null, 0, userId) == null) { - if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, unavail intent: " - + tr); - continue; - } - } - } catch (RemoteException e) { - // Will never happen. - } - } - res.add(rti); maxNum--; } @@ -7916,12 +8206,12 @@ public final class ActivityManagerService extends ActivityManagerNative } final int N = mRecentTasks.size(); - if (N >= (MAX_RECENT_TASKS-1)) { + if (N >= (ActivityManager.getMaxRecentTasksStatic()-1)) { final TaskRecord tr = mRecentTasks.remove(N - 1); - tr.disposeThumbnail(); - tr.closeRecentsChain(); + tr.removedFromRecents(mTaskPersister); } + task.inRecents = true; mRecentTasks.add(task); r.task.stack.addTask(task, false, false); @@ -7954,9 +8244,8 @@ public final class ActivityManagerService extends ActivityManagerNative } private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) { - tr.disposeThumbnail(); mRecentTasks.remove(tr); - tr.closeRecentsChain(); + tr.removedFromRecents(mTaskPersister); final boolean killProcesses = (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0; Intent baseIntent = new Intent( tr.intent != null ? tr.intent : tr.affinityIntent); @@ -10566,6 +10855,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (!mRecentTasks.isEmpty()) { mStackSupervisor.createStackForRestoredTaskHistory(mRecentTasks); } + cleanupRecentTasksLocked(UserHandle.USER_ALL); mTaskPersister.startPersisting(); } @@ -14799,6 +15089,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) || Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction()) + || Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction()) || uidRemoved) { if (checkComponentPermission( android.Manifest.permission.BROADCAST_PACKAGE_REMOVED, @@ -14825,9 +15116,13 @@ public final class ActivityManagerService extends ActivityManagerNative forceStopPackageLocked(pkg, -1, false, true, true, false, false, userId, "storage unmount"); } + cleanupRecentTasksLocked(UserHandle.USER_ALL); sendPackageBroadcastLocked( IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list, userId); } + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals( + intent.getAction())) { + cleanupRecentTasksLocked(UserHandle.USER_ALL); } else { Uri data = intent.getData(); String ssp; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index fd1474f..be0afbb 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -4040,7 +4040,7 @@ final class ActivityStack { // Task creator asked to remove this when done, or this task was a voice // interaction, so it should not remain on the recent tasks list. mService.mRecentTasks.remove(task); - task.closeRecentsChain(); + task.removedFromRecents(mService.mTaskPersister); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index a9898ee..9d7af03 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1688,7 +1688,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // If the caller is not coming from another activity, but has given us an // explicit task into which they would like us to launch the new activity, // then let's see about doing that. - if (sourceRecord == null && inTask != null && inTask.stack != null) { + if (sourceRecord == null && inTask != null && inTask.stack != null && inTask.inRecents) { // If this task is empty, then we are adding the first activity -- it // determines the root, and must be launching as a NEW_TASK. if (inTask.getRootActivity() == null) { diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index 0180db3..3cc406b 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -273,11 +273,14 @@ public class TaskPersister { if (TAG_TASK.equals(name)) { final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor); - if (true || DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" + + if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" + task); if (task != null) { task.isPersistable = true; - mWriteQueue.add(new TaskWriteQueueItem(task)); + // XXX Don't add to write queue... there is no reason to write + // out the stuff we just read, if we don't write it we will + // read the same thing again. + //mWriteQueue.add(new TaskWriteQueueItem(task)); tasks.add(task); final int taskId = task.taskId; recoveredTaskIds.add(taskId); @@ -486,24 +489,24 @@ public class TaskPersister { } catch (XmlPullParserException e) { } } - if (stringWriter != null) { - // Write out xml file while not holding mService lock. - FileOutputStream file = null; - AtomicFile atomicFile = null; - try { - atomicFile = new AtomicFile(new File(sTasksDir, String.valueOf( - task.taskId) + RECENTS_FILENAME + TASK_EXTENSION)); - file = atomicFile.startWrite(); - file.write(stringWriter.toString().getBytes()); - file.write('\n'); - atomicFile.finishWrite(file); - } catch (IOException e) { - if (file != null) { - atomicFile.failWrite(file); - } - Slog.e(TAG, "Unable to open " + atomicFile + " for persisting. " + - e); + } + if (stringWriter != null) { + // Write out xml file while not holding mService lock. + FileOutputStream file = null; + AtomicFile atomicFile = null; + try { + atomicFile = new AtomicFile(new File(sTasksDir, String.valueOf( + task.taskId) + RECENTS_FILENAME + TASK_EXTENSION)); + file = atomicFile.startWrite(); + file.write(stringWriter.toString().getBytes()); + file.write('\n'); + atomicFile.finishWrite(file); + } catch (IOException e) { + if (file != null) { + atomicFile.failWrite(file); } + Slog.e(TAG, "Unable to open " + atomicFile + " for persisting. " + + e); } } } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 7e42232..071db97 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -94,6 +94,8 @@ final class TaskRecord { ComponentName realActivity; // The actual activity component that started the task. long firstActiveTime; // First time this task was active. long lastActiveTime; // Last time this task was active, including sleep. + boolean inRecents; // Actually in the recents list? + boolean isAvailable; // Is the activity available to be launched? boolean rootWasReset; // True if the intent at the root of the task had // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. boolean autoRemoveRecents; // If true, we should automatically remove the task from @@ -170,6 +172,7 @@ final class TaskRecord { mAffiliatedTaskId = _taskId; voiceSession = _voiceSession; voiceInteractor = _voiceInteractor; + isAvailable = true; mActivities = new ArrayList<ActivityRecord>(); setIntent(_intent, info); } @@ -184,6 +187,7 @@ final class TaskRecord { mAffiliatedTaskId = _taskId; voiceSession = null; voiceInteractor = null; + isAvailable = true; mActivities = new ArrayList<ActivityRecord>(); setIntent(_intent, info); @@ -191,8 +195,9 @@ final class TaskRecord { isPersistable = true; mCallingUid = info.applicationInfo.uid; mCallingPackage = info.packageName; - // Clamp to [1, 100]. - maxRecents = Math.min(Math.max(info.maxRecents, 1), 100); + // Clamp to [1, max]. + maxRecents = Math.min(Math.max(info.maxRecents, 1), + ActivityManager.getMaxAppRecentsLimitStatic()); taskType = APPLICATION_ACTIVITY_TYPE; mTaskToReturnTo = HOME_ACTIVITY_TYPE; @@ -224,6 +229,7 @@ final class TaskRecord { realActivity = _realActivity; origActivity = _origActivity; rootWasReset = _rootWasReset; + isAvailable = true; autoRemoveRecents = _autoRemoveRecents; askedCompatMode = _askedCompatMode; taskType = _taskType; @@ -371,6 +377,15 @@ final class TaskRecord { setNextAffiliate(null); } + void removedFromRecents(TaskPersister persister) { + disposeThumbnail(); + closeRecentsChain(); + if (inRecents) { + inRecents = false; + persister.wakeup(this, false); + } + } + void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) { closeRecentsChain(); mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId; @@ -531,8 +546,9 @@ final class TaskRecord { isPersistable = r.isPersistable(); mCallingUid = r.launchedFromUid; mCallingPackage = r.launchedFromPackage; - // Clamp to [1, 100]. - maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 100); + // Clamp to [1, max]. + maxRecents = Math.min(Math.max(r.info.maxRecents, 1), + ActivityManager.getMaxAppRecentsLimitStatic()); } else { // Otherwise make all added activities match this one. r.mActivityType = taskType; @@ -1062,8 +1078,10 @@ final class TaskRecord { pw.print(prefix); pw.print("realActivity="); pw.println(realActivity.flattenToShortString()); } - if (autoRemoveRecents || taskType != 0 || mTaskToReturnTo != 0 || numFullscreen != 0) { + if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0 + || numFullscreen != 0) { pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); + pw.print(" isPersistable="); pw.print(isPersistable); pw.print(" numFullscreen="); pw.print(numFullscreen); pw.print(" taskType="); pw.print(taskType); pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo); @@ -1073,22 +1091,41 @@ final class TaskRecord { pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); pw.print(" mReuseTask="); pw.println(mReuseTask); } + if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != -1 || mPrevAffiliate != null + || mNextAffiliateTaskId != -1 || mNextAffiliate != null) { + pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); + pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); + pw.print(" ("); + if (mPrevAffiliate == null) { + pw.print("null"); + } else { + pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); + } + pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); + pw.print(" ("); + if (mNextAffiliate == null) { + pw.print("null"); + } else { + pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); + } + pw.println(")"); + } pw.print(prefix); pw.print("Activities="); pw.println(mActivities); - if (!askedCompatMode) { - pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode); + if (!askedCompatMode || !inRecents || !isAvailable) { + pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); + pw.print(" inRecents="); pw.print(inRecents); + pw.print(" isAvailable="); pw.println(isAvailable); } pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail); - pw.print(" lastThumbnailFile="); pw.print(mLastThumbnailFile); - pw.print(" lastDescription="); pw.println(lastDescription); + pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile); + if (lastDescription != null) { + pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); + } pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible); pw.print(" firstActiveTime="); pw.print(lastActiveTime); pw.print(" lastActiveTime="); pw.print(lastActiveTime); pw.print(" (inactive for "); pw.print((getInactiveDuration()/1000)); pw.println("s)"); - pw.print(prefix); pw.print("isPersistable="); pw.print(isPersistable); - pw.print(" affiliation="); pw.print(mAffiliatedTaskId); - pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); - pw.print(" nextAffiliation="); pw.println(mNextAffiliateTaskId); } @Override |