Android N (7.0 )SystemUI --RecentsActivity

RecentsActivity 是最近任务管理界面,通过该activity用户可以对启动的应用进行简单的管理。其配置信息如下

 
  1. frameworks/base/packages/SystemUI/AndroidManifest.xml

  2.  
  3. <activity android:name=".recents.RecentsActivity"

  4. android:label="@string/accessibility_desc_recent_apps"

  5. android:exported="false"

  6. android:launchMode="singleInstance"

  7. android:excludeFromRecents="true"

  8. android:stateNotNeeded="true"

  9. android:resumeWhilePausing="true"

  10. android:screenOrientation="behind"

  11. android:resizeableActivity="true"

  12. android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"

  13. android:theme="@style/RecentsTheme.Wallpaper">

  14. <intent-filter>

  15. <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />

  16. </intent-filter>

  17. </activity>

可以看到其launchMode为"singleInstance"。RecentsActivity 启动的入口在

 
  1. frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java

  2.  
  3. private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {

  4. public void onClick(View v) {

  5. awakenDreams();

  6. toggleRecentApps();

  7. }

  8. };

关于RecentsActivity ,这里主要讨论3个方面,task的获取、应用缩略图的获取、task移除。

getRecentTasks

在ams中,有一个mRecentTasks对象,该对象保存了近期启动的task任务信息,RecentsActivity实际上是要获取mRecentTasks对象

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2.  
  3. /**

  4. * List of intents that were used to start the most recent tasks.

  5. */

  6. final RecentTasks mRecentTasks;


 

在上面的入口中,toggleRecentApps()最终会调用到

 
  1. frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java

  2.  
  3. public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,

  4. boolean includeFrontMostExcludedTask, ArraySet<Integer> quietProfileIds) {

  5. ...

  6. int minNumTasksToQuery = 10;

  7. int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);

  8. int flags = ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |

  9. ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK |

  10. ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |

  11. ActivityManager.RECENT_IGNORE_UNAVAILABLE |

  12. ActivityManager.RECENT_INCLUDE_PROFILES;

  13. if (includeFrontMostExcludedTask) {

  14. flags |= ActivityManager.RECENT_WITH_EXCLUDED;

  15. }

  16. List<ActivityManager.RecentTaskInfo> tasks = null;

  17. try {

  18. tasks = mAm.getRecentTasksForUser(numTasksToQuery, flags, userId);

  19. } catch (Exception e) {

  20. Log.e(TAG, "Failed to get recent tasks", e);

  21. }

  22.  
  23. ...

  24. return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));

  25. }

这里设置了flag,不去获取HOME_STACK_ID、DOCKED_STACK_ID、PINNED_STACK_ID上的task,根据机器内存大小设置了最大的查询数

 
  1. frameworks/base/core/java/android/app/ActivityManager.java

  2. static public int getMaxRecentTasksStatic() {

  3. if (gMaxRecentTasks < 0) {

  4. return gMaxRecentTasks = isLowRamDeviceStatic() ? 36 : 48;

  5. }

  6. return gMaxRecentTasks;

  7. }

然后调用ActivityManager的getRecentTasksForUser方法

 
  1. frameworks/base/core/java/android/app/ActivityManager.java

  2. public List<RecentTaskInfo> getRecentTasksForUser(int maxNum, int flags, int userId)

  3. throws SecurityException {

  4. try {

  5. return ActivityManagerNative.getDefault().getRecentTasks(maxNum,

  6. flags, userId).getList();

  7. } catch (RemoteException e) {

  8. throw e.rethrowFromSystemServer();

  9. }

  10. }

通过binder通信最终会进入到ams

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2. public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,

  3. int userId) {

  4. final int callingUid = Binder.getCallingUid();

  5. userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId,

  6. false, ALLOW_FULL_ONLY, "getRecentTasks", null);

  7.  
  8. final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0;

  9. final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0;

  10. synchronized (this) {

  11. final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),

  12. callingUid);

  13. final boolean detailed = checkCallingPermission(

  14. android.Manifest.permission.GET_DETAILED_TASKS)

  15. == PackageManager.PERMISSION_GRANTED;

  16.  
  17. if (!isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {

  18. Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");

  19. return ParceledListSlice.emptyList();

  20. }

  21. mRecentTasks.loadUserRecentsLocked(userId);

  22.  
  23. final int recentsCount = mRecentTasks.size();

  24. ArrayList<ActivityManager.RecentTaskInfo> res =

  25. new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount);

  26.  
  27. final Set<Integer> includedUsers;

  28. if (includeProfiles) {

  29. includedUsers = mUserController.getProfileIds(userId);

  30. } else {

  31. includedUsers = new HashSet<>();

  32. }

  33. includedUsers.add(Integer.valueOf(userId));

  34.  
  35. for (int i = 0; i < recentsCount && maxNum > 0; i++) {

  36. TaskRecord tr = mRecentTasks.get(i);

  37. // Only add calling user or related users recent tasks

  38. if (!includedUsers.contains(Integer.valueOf(tr.userId))) {

  39. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);

  40. continue;

  41. }

  42.  
  43. if (tr.realActivitySuspended) {

  44. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);

  45. continue;

  46. }

  47.  
  48. // Return the entry if desired by the caller. We always return

  49. // the first entry, because callers always expect this to be the

  50. // foreground app. We may filter others if the caller has

  51. // not supplied RECENT_WITH_EXCLUDED and there is some reason

  52. // we should exclude the entry.

  53.  
  54. if (i == 0

  55. || withExcluded

  56. || (tr.intent == null)

  57. || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)

  58. == 0)) {

  59. if (!allowed) {

  60. // If the caller doesn't have the GET_TASKS permission, then only

  61. // allow them to see a small subset of tasks -- their own and home.

  62. if (!tr.isHomeTask() && tr.effectiveUid != callingUid) {

  63. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);

  64. continue;

  65. }

  66. }

  67. if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {

  68. if (tr.stack != null && tr.stack.isHomeStack()) {

  69. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  70. "Skipping, home stack task: " + tr);

  71. continue;

  72. }

  73. }

  74. if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {

  75. final ActivityStack stack = tr.stack;

  76. if (stack != null && stack.isDockedStack() && stack.topTask() == tr) {

  77. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  78. "Skipping, top task in docked stack: " + tr);

  79. continue;

  80. }

  81. }

  82. if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {

  83. if (tr.stack != null && tr.stack.isPinnedStack()) {

  84. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  85. "Skipping, pinned stack task: " + tr);

  86. continue;

  87. }

  88. }

  89. if (tr.autoRemoveRecents && tr.getTopActivity() == null) {

  90. // Don't include auto remove tasks that are finished or finishing.

  91. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  92. "Skipping, auto-remove without activity: " + tr);

  93. continue;

  94. }

  95. if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0

  96. && !tr.isAvailable) {

  97. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  98. "Skipping, unavail real act: " + tr);

  99. continue;

  100. }

  101.  
  102. if (!tr.mUserSetupComplete) {

  103. // Don't include task launched while user is not done setting-up.

  104. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  105. "Skipping, user setup not complete: " + tr);

  106. continue;

  107. }

  108.  
  109. ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);

  110. if (!detailed) {

  111. rti.baseIntent.replaceExtras((Bundle)null);

  112. }

  113.  
  114. res.add(rti);

  115. maxNum--;

  116. }

  117. }

  118. return new ParceledListSlice<>(res);

  119. }

  120. }

首先loadUserRecentsLocked

 
  1. frameworks/base/services/core/java/com/android/server/am/RecentTasks.java

  2.  
  3. void loadUserRecentsLocked(int userId) {

  4. if (!mUsersWithRecentsLoaded.get(userId)) {

  5. // Load the task ids if not loaded.

  6. loadPersistedTaskIdsForUserLocked(userId);

  7. Slog.i(TAG, "Loading recents for user " + userId + " into memory.");

  8. addAll(mTaskPersister.restoreTasksForUserLocked(userId));

  9. cleanupLocked(userId);

  10. mUsersWithRecentsLoaded.put(userId, true);

  11. }

  12. }


通过restoreTasksForUserLocked方法去获取task列表

 
  1. frameworks/base/services/core/java/com/android/server/am/TaskPersister.java

  2.  
  3. List<TaskRecord> restoreTasksForUserLocked(final int userId) {

  4. final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();

  5. ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();

  6.  
  7. File userTasksDir = getUserTasksDir(userId);

  8.  
  9. File[] recentFiles = userTasksDir.listFiles();

  10. if (recentFiles == null) {

  11. Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir);

  12. return tasks;

  13. }

  14.  
  15. for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {

  16. File taskFile = recentFiles[taskNdx];

  17. if (DEBUG) {

  18. Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId

  19. + ", taskFile=" + taskFile.getName());

  20. }

  21. BufferedReader reader = null;

  22. boolean deleteFile = false;

  23. try {

  24. reader = new BufferedReader(new FileReader(taskFile));

  25. final XmlPullParser in = Xml.newPullParser();

  26. in.setInput(reader);

  27.  
  28. int event;

  29. while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&

  30. event != XmlPullParser.END_TAG) {

  31. final String name = in.getName();

  32. if (event == XmlPullParser.START_TAG) {

  33. if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: START_TAG name=" + name);

  34. if (TAG_TASK.equals(name)) {

  35. final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor);

  36. if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: restored task="

  37. + task);

  38. if (task != null) {

  39. // XXX Don't add to write queue... there is no reason to write

  40. // out the stuff we just read, if we don't write it we will

  41. // read the same thing again.

  42. // mWriteQueue.add(new TaskWriteQueueItem(task));

  43.  
  44. final int taskId = task.taskId;

  45. if (mStackSupervisor.anyTaskForIdLocked(taskId,

  46. /* restoreFromRecents= */ false, 0) != null) {

  47. // Should not happen.

  48. Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");

  49. } else if (userId != task.userId) {

  50. // Should not happen.

  51. Slog.wtf(TAG, "Task with userId " + task.userId + " found in "

  52. + userTasksDir.getAbsolutePath());

  53. } else {

  54. // Looks fine.

  55. mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);

  56. task.isPersistable = true;

  57. tasks.add(task);

  58. recoveredTaskIds.add(taskId);

  59. }

  60. } else {

  61. Slog.e(TAG, "restoreTasksForUserLocked: Unable to restore taskFile="

  62. + taskFile + ": " + fileToString(taskFile));

  63. }

  64. } else {

  65. Slog.wtf(TAG, "restoreTasksForUserLocked: Unknown xml event=" + event

  66. + " name=" + name);

  67. }

  68. }

  69. XmlUtils.skipCurrentTag(in);

  70. }

  71. } catch (Exception e) {

  72. Slog.wtf(TAG, "Unable to parse " + taskFile + ". Error ", e);

  73. Slog.e(TAG, "Failing file: " + fileToString(taskFile));

  74. deleteFile = true;

  75. } finally {

  76. IoUtils.closeQuietly(reader);

  77. if (deleteFile) {

  78. if (DEBUG) Slog.d(TAG, "Deleting file=" + taskFile.getName());

  79. taskFile.delete();

  80. }

  81. }

  82. }

  83.  
  84. ...

  85. return tasks;

  86. }


主要是去解析xml文件,位于/data/system_ce/0/recent_tasks目录下

可以看到这些task信息是以文件形式保存的,这就是重启后进RecentsActivity看到task还在的原因。

解析完这些xml文件就获取到了初始的task信息。

但实际上loadUserRecentsLocked里面的语句是只会在开机初始化时执行一次,因此这里相当于什么都没有做。

然后还要回到

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2. public ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,

  3. int userId) {

  4. ...

  5. synchronized (this) {

  6. ...

  7. mRecentTasks.loadUserRecentsLocked(userId);

  8.  
  9. ...

  10.  
  11. for (int i = 0; i < recentsCount && maxNum > 0; i++) {

  12. TaskRecord tr = mRecentTasks.get(i);

  13. // Only add calling user or related users recent tasks

  14. if (!includedUsers.contains(Integer.valueOf(tr.userId))) {

  15. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);

  16. continue;

  17. }

  18.  
  19. if (tr.realActivitySuspended) {

  20. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);

  21. continue;

  22. }

  23.  
  24. // Return the entry if desired by the caller. We always return

  25. // the first entry, because callers always expect this to be the

  26. // foreground app. We may filter others if the caller has

  27. // not supplied RECENT_WITH_EXCLUDED and there is some reason

  28. // we should exclude the entry.

  29.  
  30. if (i == 0

  31. || withExcluded

  32. || (tr.intent == null)

  33. || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)

  34. == 0)) {

  35. if (!allowed) {

  36. // If the caller doesn't have the GET_TASKS permission, then only

  37. // allow them to see a small subset of tasks -- their own and home.

  38. if (!tr.isHomeTask() && tr.effectiveUid != callingUid) {

  39. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);

  40. continue;

  41. }

  42. }

  43. if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {

  44. if (tr.stack != null && tr.stack.isHomeStack()) {

  45. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  46. "Skipping, home stack task: " + tr);

  47. continue;

  48. }

  49. }

  50. if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {

  51. final ActivityStack stack = tr.stack;

  52. if (stack != null && stack.isDockedStack() && stack.topTask() == tr) {

  53. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  54. "Skipping, top task in docked stack: " + tr);

  55. continue;

  56. }

  57. }

  58. if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {

  59. if (tr.stack != null && tr.stack.isPinnedStack()) {

  60. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  61. "Skipping, pinned stack task: " + tr);

  62. continue;

  63. }

  64. }

  65. if (tr.autoRemoveRecents && tr.getTopActivity() == null) {

  66. // Don't include auto remove tasks that are finished or finishing.

  67. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  68. "Skipping, auto-remove without activity: " + tr);

  69. continue;

  70. }

  71. if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0

  72. && !tr.isAvailable) {

  73. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  74. "Skipping, unavail real act: " + tr);

  75. continue;

  76. }

  77.  
  78. if (!tr.mUserSetupComplete) {

  79. // Don't include task launched while user is not done setting-up.

  80. if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,

  81. "Skipping, user setup not complete: " + tr);

  82. continue;

  83. }

  84.  
  85. ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);

  86. if (!detailed) {

  87. rti.baseIntent.replaceExtras((Bundle)null);

  88. }

  89.  
  90. res.add(rti);

  91. maxNum--;

  92. }

  93. }

  94. return new ParceledListSlice<>(res);

  95. }

  96. }

根据之前设置的flag去排除掉不需要的task,最后调用createRecentTaskInfoFromTaskRecord()方法把TaskRecord信息转换成RecentTaskInfo的信息

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2. private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) {

  3. // Update the task description to reflect any changes in the task stack

  4. tr.updateTaskDescription();

  5.  
  6. // Compose the recent task info

  7. ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();

  8. rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId;

  9. rti.persistentId = tr.taskId;

  10. rti.baseIntent = new Intent(tr.getBaseIntent());

  11. rti.origActivity = tr.origActivity;

  12. rti.realActivity = tr.realActivity;

  13. rti.description = tr.lastDescription;

  14. rti.stackId = tr.stack != null ? tr.stack.mStackId : -1;

  15. rti.userId = tr.userId;

  16. rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);

  17. rti.firstActiveTime = tr.firstActiveTime;

  18. rti.lastActiveTime = tr.lastActiveTime;

  19. rti.affiliatedTaskId = tr.mAffiliatedTaskId;

  20. rti.affiliatedTaskColor = tr.mAffiliatedTaskColor;

  21. rti.numActivities = 0;

  22. if (tr.mBounds != null) {

  23. rti.bounds = new Rect(tr.mBounds);

  24. }

  25. rti.isDockable = tr.canGoInDockedStack();

  26. rti.resizeMode = tr.mResizeMode;

  27.  
  28. ActivityRecord base = null;

  29. ActivityRecord top = null;

  30. ActivityRecord tmp;

  31.  
  32. for (int i = tr.mActivities.size() - 1; i >= 0; --i) {

  33. tmp = tr.mActivities.get(i);

  34. if (tmp.finishing) {

  35. continue;

  36. }

  37. base = tmp;

  38. if (top == null || (top.state == ActivityState.INITIALIZING)) {

  39. top = base;

  40. }

  41. rti.numActivities++;

  42. }

  43.  
  44. rti.baseActivity = (base != null) ? base.intent.getComponent() : null;

  45. rti.topActivity = (top != null) ? top.intent.getComponent() : null;

  46.  
  47. return rti;

  48. }

从这里可以看到recenttask是以TaskReord为单位进行管理的,不是一app或者activity为单位进行管理。

到这里就获取了所需的RecentTaskInfo信息。

从这里可以看到mRecentTasks只是剔除了一些不符合要求的task做了些简单的处理就返回了,那么mRecentTasks真正是在哪里赋值的呢?

有两个地方,一是在startActivity的过程中,二是在activity 重新resume时。

先看startActivity时,这里省略了startActivity的具体过程

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

  2. final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,

  3. boolean andResume, boolean checkConfig) throws RemoteException {

  4.  
  5. ...

  6.  
  7. if (andResume) {

  8. // As part of the process of launching, ActivityThread also performs

  9. // a resume.

  10. stack.minimalResumeActivityLocked(r);

  11. }

  12. ...

  13.  
  14. return true;

  15. }

在minimalResumeActivityLocked方法中将TaskRecord对象加入到mRecentTasks对象中

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

  2. void minimalResumeActivityLocked(ActivityRecord r) {

  3. ...

  4. mRecentTasks.addLocked(r.task);

  5. ...

  6. }

这里有个疑问,ActivityStack中的mRecentTasks是怎么和ActivityManagerService的mRecentTasks联系起来的呢?

在ams初始化时创建了ActivityStackSupervisor对象,用来辅助ams管理ActivityStack

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2. public ActivityManagerService(Context systemContext) {

  3. ...

  4. mStackSupervisor = new ActivityStackSupervisor(this);

  5. mActivityStarter = new ActivityStarter(this, mStackSupervisor);

  6. mRecentTasks = new RecentTasks(this, mStackSupervisor);

  7. ...

  8. }

同时也创建了mRecentTasks对象,参数是ams和mStackSupervisor。

RecentTasks的构造函数中又把自己通过setRecentTasks的方法保存到了ActivityStackSupervisor

 
  1. frameworks/base/services/core/java/com/android/server/am/RecentTasks.java

  2. RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) {

  3. ...

  4. mStackSupervisor.setRecentTasks(this);

  5. }

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

  2.  
  3. ...

  4. private RecentTasks mRecentTasks;

  5. ...

  6. void setRecentTasks(RecentTasks recentTasks) {

  7. mRecentTasks = recentTasks;

  8. }

ActivityStackSupervisor中也保存了一个RecentTasks对象,这样实际上和ActivityManagerService的mRecentTasks指向了同一个地址。

在ActivityStackSupervisor中创建ActivityStack时,又把mRecentTasks传递到了ActivityStack中,

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

  2.  
  3. ActivityContainer(int stackId) {

  4. synchronized (mService) {

  5. ...

  6. mStack = new ActivityStack(this, mRecentTasks);

  7. ...

  8. }

  9. }

这样ActivityStack中的mRecentTasks就和ActivityManagerService的mRecentTasks保持一致了。

现在回到mRecentTasks的赋值问题,第二个时机是在activity 重新resume时。

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

  2. private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {

  3. ...

  4. mRecentTasks.addLocked(next.task);

  5. ...

  6. }

getTaskThumbnail

获取到RecentTaskInfo之后就要去获取缩略图信息了

 
  1. frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java

  2. public void getThumbnail(int taskId, ThumbnailData thumbnailDataOut) {

  3. ...

  4. ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);

  5. ...

  6. }

很简洁,就调用了ActivityManager的方法

 
  1. frameworks/base/core/java/android/app/ActivityManager.java

  2. public TaskThumbnail getTaskThumbnail(int id) throws SecurityException {

  3. try {

  4. return ActivityManagerNative.getDefault().getTaskThumbnail(id);

  5. } catch (RemoteException e) {

  6. throw e.rethrowFromSystemServer();

  7. }

  8. }

通过binder通信调用了ams的方法

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2. public ActivityManager.TaskThumbnail getTaskThumbnail(int id) {

  3. synchronized (this) {

  4. enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,

  5. "getTaskThumbnail()");

  6. final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(

  7. id, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);

  8. if (tr != null) {

  9. return tr.getTaskThumbnailLocked();

  10. }

  11. }

  12. return null;

  13. }

首先根据taskid去找到TaskRecord,然后获取Thumbnail

 
  1. public TaskThumbnail getTaskThumbnailLocked() {

  2. if (stack != null) {

  3. final ActivityRecord resumedActivity = stack.mResumedActivity;

  4. if (resumedActivity != null && resumedActivity.task == this) {

  5. final Bitmap thumbnail = stack.screenshotActivitiesLocked(resumedActivity);

  6. setLastThumbnailLocked(thumbnail);

  7. }

  8. }

  9. final TaskThumbnail taskThumbnail = new TaskThumbnail();

  10. getLastThumbnail(taskThumbnail);

  11. return taskThumbnail;

  12. }

这里除了栈顶正在显示的TaskRecord回去实时的截取屏幕图像,其他的走getLastThumbnail

 
  1. frameworks/base/services/core/java/com/android/server/am/TaskRecord.java

  2. void getLastThumbnail(TaskThumbnail thumbs) {

  3. thumbs.mainThumbnail = mLastThumbnail;

  4. thumbs.thumbnailInfo = mLastThumbnailInfo;

  5. thumbs.thumbnailFileDescriptor = null;

  6. if (mLastThumbnail == null) {

  7. thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue(

  8. mLastThumbnailFile.getAbsolutePath());

  9. }

  10. // Only load the thumbnail file if we don't have a thumbnail

  11. if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {

  12. try {

  13. thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,

  14. ParcelFileDescriptor.MODE_READ_ONLY);

  15. } catch (IOException e) {

  16. }

  17. }

  18. }

这里实际是去读取文件,这些缩略图已经保存在/data/system_ce/0/recent_images文件夹下

把这些文件读取出来就获取到了task的缩略图。

但是这里并没有看到去截屏,这些图片是什么时候截取的呢?

截图的时机是在activity onpause之后

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

  2. private void completePauseLocked(boolean resumeNext) {

  3. ...

  4. mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);

  5. }

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

  2. void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,

  3. boolean preserveWindows) {

  4. // First the front stacks. In case any are not fullscreen and are in front of home.

  5. for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {

  6. final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;

  7. final int topStackNdx = stacks.size() - 1;

  8. for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {

  9. final ActivityStack stack = stacks.get(stackNdx);

  10. stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows);

  11. }

  12. }

  13. }

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

  2. final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,

  3. boolean preserveWindows) {

  4. ...

  5. makeInvisible(r, visibleBehind);

  6.  
  7. ...

  8. }

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

  2. private void makeInvisible(ActivityRecord r, ActivityRecord visibleBehind) {

  3. ...

  4. try {

  5. setVisible(r, false);

  6. ...

  7. } catch (Exception e) {

  8. ...

  9. }

  10. }


makeInvisible又调用了setVisible

 
  1. private void setVisible(ActivityRecord r, boolean visible) {

  2. r.visible = visible;

  3. if (!visible && r.mUpdateTaskThumbnailWhenHidden) {

  4. r.updateThumbnailLocked(r.task.stack.screenshotActivitiesLocked(r), null);

  5. r.mUpdateTaskThumbnailWhenHidden = false;

  6. }

  7. ...

  8. }

就是在这里更新TaskThumbnail的,screenshotActivitiesLocked(r)是真正截图的地方

截图完成之后,最终通过saveImage方法保存到文件中,这里path为/data/system_ce/0/recent_images文件夹

 
  1. frameworks/base/services/core/java/com/android/server/am/RecentTasks.java

  2. void saveImage(Bitmap image, String path) {

  3. mTaskPersister.saveImage(image, path);

  4. }

这样需要获取缩略图时之前去读文件就可以了。

removeTask

当从RecentsActivity移除某一个应用时,实际会调用到removeTask

 
  1. frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java

  2. public void removeTask(final int taskId) {

  3. ...

  4. // Remove the task.

  5. BackgroundThread.getHandler().post(new Runnable() {

  6. @Override

  7. public void run() {

  8. mAm.removeTask(taskId);

  9. }

  10. });

  11. }

然后调用到ams的removeTask方法,参数taskId为要移除的TaskRecord的id

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2. public boolean removeTask(int taskId) {

  3. enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()");

  4. synchronized (this) {

  5. final long ident = Binder.clearCallingIdentity();

  6. try {

  7. return removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS);

  8. } finally {

  9. Binder.restoreCallingIdentity(ident);

  10. }

  11. }

  12. }

调用该方法首先会检查是否有声明android.Manifest.permission.REMOVE_TASKS的权限,这里我们是有声明这个权限的。然后调用removeTaskByIdLocked

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2. private boolean removeTaskByIdLocked(int taskId, boolean killProcess,

  3. boolean removeFromRecents) {

  4. final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(

  5. taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);

  6. if (tr != null) {

  7. tr.removeTaskActivitiesLocked();

  8. cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);

  9. if (tr.isPersistable) {

  10. notifyTaskPersisterLocked(null, true);

  11. }

  12. return true;

  13. }

  14. Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);

  15. return false;

  16. }

先看下这里的参数,taskid为要移除的task id,killProcess为true,表示要杀掉该taskrecord里所有activity所在的进程,removeFromRecents为true,表示要从mRecentTasks移除。

这里通过taskid找到该TaskRecord,然后首先调用了TaskRecord的removeTaskActivitiesLocked方法

 
  1. frameworks/base/services/core/java/com/android/server/am/TaskRecord.java

  2. public void removeTaskActivitiesLocked() {

  3. // Just remove the entire task.

  4. performClearTaskAtIndexLocked(0);

  5. }

 
  1. frameworks/base/services/core/java/com/android/server/am/TaskRecord.java

  2. final void performClearTaskAtIndexLocked(int activityNdx) {

  3. int numActivities = mActivities.size();

  4. for ( ; activityNdx < numActivities; ++activityNdx) {

  5. final ActivityRecord r = mActivities.get(activityNdx);

  6. if (r.finishing) {

  7. continue;

  8. }

  9. if (stack == null) {

  10. // Task was restored from persistent storage.

  11. r.takeFromHistory();

  12. mActivities.remove(activityNdx);

  13. --activityNdx;

  14. --numActivities;

  15. } else if (stack.finishActivityLocked(

  16. r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {

  17. --activityNdx;

  18. --numActivities;

  19. }

  20. }

  21. }

传递下来的参数activityNdx = 0,表示吧整个TaskRecord移除。这里的mActivities是该TaskRecord中保存的所有ActivityRecord对象,stack是该TaskRecord所在的ActivityStack,这里不为空,所以会调用ActivityStack的finishActivityLocked方法去移除该TaskRecord中的ActivityRecord对象。

从ActivityStack移除完TaskRecord之后回到removeTaskByIdLocked,然后又调用了cleanUpRemovedTaskLocked方法

 
  1. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  2. private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess,

  3. boolean removeFromRecents) {

  4. if (removeFromRecents) {

  5. mRecentTasks.remove(tr);

  6. tr.removedFromRecents();

  7. }

  8. ComponentName component = tr.getBaseIntent().getComponent();

  9. if (component == null) {

  10. Slog.w(TAG, "No component for base intent of task: " + tr);

  11. return;

  12. }

  13.  
  14. // Find any running services associated with this app and stop if needed.

  15. mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));

  16.  
  17. if (!killProcess) {

  18. return;

  19. }

  20.  
  21. // Determine if the process(es) for this task should be killed.

  22. final String pkg = component.getPackageName();

  23. ArrayList<ProcessRecord> procsToKill = new ArrayList<>();

  24. ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();

  25. for (int i = 0; i < pmap.size(); i++) {

  26.  
  27. SparseArray<ProcessRecord> uids = pmap.valueAt(i);

  28. for (int j = 0; j < uids.size(); j++) {

  29. ProcessRecord proc = uids.valueAt(j);

  30. if (proc.userId != tr.userId) {

  31. // Don't kill process for a different user.

  32. continue;

  33. }

  34. if (proc == mHomeProcess) {

  35. // Don't kill the home process along with tasks from the same package.

  36. continue;

  37. }

  38. if (!proc.pkgList.containsKey(pkg)) {

  39. // Don't kill process that is not associated with this task.

  40. continue;

  41. }

  42.  
  43. for (int k = 0; k < proc.activities.size(); k++) {

  44. TaskRecord otherTask = proc.activities.get(k).task;

  45. if (tr.taskId != otherTask.taskId && otherTask.inRecents) {

  46. // Don't kill process(es) that has an activity in a different task that is

  47. // also in recents.

  48. return;

  49. }

  50. }

  51.  
  52. if (proc.foregroundServices) {

  53. // Don't kill process(es) with foreground service.

  54. return;

  55. }

  56.  
  57. // Add process to kill list.

  58. procsToKill.add(proc);

  59. }

  60. }

  61.  
  62. // Kill the running processes.

  63. for (int i = 0; i < procsToKill.size(); i++) {

  64. ProcessRecord pr = procsToKill.get(i);

  65. if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND

  66. && pr.curReceiver == null) {

  67. pr.kill("remove task", true);

  68. } else {

  69. // We delay killing processes that are not in the background or running a receiver.

  70. pr.waitingToKill = "remove task";

  71. }

  72. }

  73. }

这里removeFromRecents为true,因此会先将该TaskRecord从mRecentTasks中移除,然后过滤出可以杀掉的Process的ProcessRecord信息,放到procsToKill列表中。分两种情况,如果是SCHED_GROUP_BACKGROUND类型并且没有在执行reciver,会调用kill方法立即去杀掉。否则简单将procsToKill中ProcessRecord的waitingToKill字段设置为remove task。这里涉及到Android进程管理的相关知识,可参看

Android系统中的进程管理:进程的优先级

原文地址:https://blog.csdn.net/kebelzc24/article/details/53765379

猜你喜欢

转载自blog.csdn.net/f2006116/article/details/82354780