Android(安卓)7.1.2(Android(安卓)N) SystemUI--Recents Task 加载显示流程
Android 7.1.2(Android N) SystemUI--Recents Task 加载显示流程
高清原文
(一)Recent Task 加载流程 和 RecentsActivity启动流程
RecentsActivity.java启动流程:
RecentsActivity.pngRecentsActivity是SystemUI用于显示最近使用的应用列表,当用户点击Switch按键时会启动RecentsActivity。先分析启动的过程。首先是用户点击SWITCH按键,PhoneWindowManager会在事件分发前先拦截该事件:
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
@Overridepublic long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {...... else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { if (!keyguardOn) { if (down && repeatCount == 0) { //when down app_switch_longpress = false; } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { //when long press app_switch_longpress = true; triggerVirtualKeypress(KeyEvent.KEYCODE_MENU); } else if (!down && !app_switch_longpress) { //when up preloadRecentApps(); toggleRecentApps(); } } return -1;......}
(1)preloadRecentApps();//预加载最近使用应用
private void preloadRecentApps() { mPreloadedRecentApps = true; StatusBarManagerInternal statusbar = getStatusBarManagerInternal(); if (statusbar != null) { statusbar.preloadRecentApps(); }}
(2)toggleRecentApps();
private void toggleRecentApps() { mPreloadedRecentApps = false; // preloading no longer needs to be canceled StatusBarManagerInternal statusbar = getStatusBarManagerInternal(); if (statusbar != null) { statusbar.toggleRecentApps(); }}
这两种情况都获取了StatusBarManagerInternal的对象statusbar,并由该对象调用preloadRecentApps()和toggleRecentApps()方法。StatusBarManagerInternal是一个接口,具体实现是由StatusBarManagerService这个类内部来实现的。并通过LocalServices.addService(StatusBarManagerInternal.class, mInternalService)启动。
frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
public class StatusBarManagerService extends IStatusBarService.Stub {......private volatile IStatusBar mBar;......public StatusBarManagerService(Context context, WindowManagerService windowManager) { mContext = context; mWindowManager = windowManager; LocalServices.addService(StatusBarManagerInternal.class, mInternalService);}....../** * Private API used by NotificationManagerService. */private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() { @Override public void preloadRecentApps() { if (mBar != null) { try { mBar.preloadRecentApps(); } catch (RemoteException ex) {} } } @Override public void toggleRecentApps() { if (mBar != null) { try { mBar.toggleRecentApps(); } catch (RemoteException ex) {} } } }}
mBar是IStatusBar的对象,IStatusBar.aidl接口中的内部抽象类Stub是由CommandQueue这个类实现的。
/frameworks/base/core/java/com/android/internal/statusbar/IStatusBar.aidl
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
public class CommandQueue extends IStatusBar.Stub {/** * These methods are called back on the main thread. */public interface Callbacks { public void toggleRecentApps(); public void preloadRecentApps(); }/*这是IStatusBar.aidl文件定义的抽象方法的实现,通过mHandler将消息传递给主线程*/public void toggleRecentApps() { synchronized (mList) { mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS); mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget(); }} /*这是IStatusBar.aidl文件定义的抽象方法的实现*/public void preloadRecentApps() { synchronized (mList) { mHandler.removeMessages(MSG_PRELOAD_RECENT_APPS); mHandler.obtainMessage(MSG_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); }}public CommandQueue(Callbacks callbacks, StatusBarIconList list) { //这个类持有实现了自己的内部接口类的对象(BaseStatusBar)。BaseStatusBar中创建了CommandQueue对象,调用了这个构造方法。 mCallbacks = callbacks; mList = list;}private final class H extends Handler { public void handleMessage(Message msg) { final int what = msg.what & MSG_MASK; switch (what) { case MSG_TOGGLE_RECENT_APPS: //在主线程中回调toggleRecentApps()方法,即调用BaseStatusBar类中实现的CommandQueue.Calbacks接口的抽象方法。 mCallbacks.toggleRecentApps(); break; case MSG_PRELOAD_RECENT_APPS: mCallbacks.preloadRecentApps(); break; } } }}
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
public abstract class BaseStatusBar extends SystemUI implements CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener, RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment { private RecentsComponent mRecents; @Overridepublic void toggleRecentApps() { toggleRecents();}@Overridepublic void preloadRecentApps() { int msg = MSG_PRELOAD_RECENT_APPS; mHandler.removeMessages(msg); mHandler.sendEmptyMessage(msg);}protected class H extends Handler { public void handleMessage(Message m) { switch (m.what) { ...... case MSG_TOGGLE_RECENTS_APPS: toggleRecents(); break; case MSG_PRELOAD_RECENT_APPS: preloadRecents(); break; ...... } }}protected void toggleRecents() { if (mRecents != null) { mRecents.toggleRecents(mDisplay); }}protected void preloadRecents() { if (mRecents != null) { mRecents.preloadRecents(); }}
通过一系列的追踪,发现最终是由CommandQueue回调BaseStatusBar中的toggleRecentApps()方法,接着继续调用toggleRecents()方法,最后调用Recents类中的preloadRecents()和toggleRecents()方法。
上面有分析到BaseStatusBar类中通过调用registerStatusBar方法将CommandQueue注册到了StatusBarManagerService中。接下来分析Recents类。
/frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java
/frameworks/base/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
RecentsComponent.java是一个接口类
public interface RecentsComponent {void toggleRecents(Display display);void preloadRecents();}
Recents.java这个类实现了RecentsComponent这个接口
public class Recents extends SystemUI implements RecentsComponent {/** * Preloads info for the Recents activity. */@Overridepublic void preloadRecents() { int currentUser = sSystemServicesProxy.getCurrentUser(); if (sSystemServicesProxy.isSystemUser(currentUser)) { mImpl.preloadRecents(); } }/** * Toggles the Recents activity. */@Overridepublic void toggleRecents(Display display) { int currentUser = sSystemServicesProxy.getCurrentUser(); if (sSystemServicesProxy.isSystemUser(currentUser)) { mImpl.toggleRecents(growTarget); } }}
/frameworks/base/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener {public void toggleRecents(int growTarget) { try { if (ssp.isRecentsActivityVisible(isHomeStackVisible)) { return; } else { // Otherwise, start the recents activity ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask(); startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */, growTarget); } } catch (ActivityNotFoundException e) { Log.e(TAG, "Failed to launch RecentsActivity", e); } }public void preloadRecents() { // Preload only the raw task list into a new load plan (which will be consumed by the // RecentsActivity) only if there is a task to animate to. SystemServicesProxy ssp = Recents.getSystemServices(); MutableBoolean isHomeStackVisible = new MutableBoolean(true); if (!ssp.isRecentsActivityVisible(isHomeStackVisible)) { ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask(); RecentsTaskLoader loader = Recents.getTaskLoader(); sInstanceLoadPlan = loader.createLoadPlan(mContext); sInstanceLoadPlan.preloadRawTasks(!isHomeStackVisible.value); loader.preloadTasks(sInstanceLoadPlan, runningTask.id, !isHomeStackVisible.value); TaskStack stack = sInstanceLoadPlan.getTaskStack(); if (stack.getTaskCount() > 0) { // Only preload the icon (but not the thumbnail since it may not have been taken for // the pausing activity) preloadIcon(runningTask.id); // At this point, we don't know anything about the stack state. So only calculate // the dimensions of the thumbnail that we need for the transition into Recents, but // do not draw it until we construct the activity options when we start Recents updateHeaderBarLayout(stack, null /* window rect override*/); } } }}
总结:整个过程大概就是用户触发SWITCH按键后由PhoneWindowMananger拦截事件,通过StatusBarManagerService调用toggleRecentApps()方法,通过mBar(SystemUI注册到StatusBarManagerService的Binder对象)通知SystemUI启动RecentsActivity显示最近使用的应用列表。
(二)关于RecentsActivity,Task的获取、应用缩略图的获取、task移除。
RecentsActivity的启动之前有一个Task数据的预加载过程,包括task的获取、应用缩略图的获取,具体实现就在preloadRecents()中实现。
//task的获取sInstanceLoadPlan.preloadRawTasks(!isHomeStackVisible.value);//应用缩略图的获取loader.preloadTasks(sInstanceLoadPlan, runningTask.id, !isHomeStackVisible.value);
Task的获取、应用缩略图的获取流程图
Recent-Task.png(1)task的获取
**/frameworks/base/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java # **
/** * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent * to most-recent order. */public synchronized void preloadRawTasks(boolean includeFrontMostExcludedTask) { int currentUserId = UserHandle.USER_CURRENT; updateCurrentQuietProfilesCache(currentUserId); SystemServicesProxy ssp = Recents.getSystemServices(); mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles); // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it Collections.reverse(mRawTasks);}
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
/** * Returns a list of the recents tasks. * * @param includeFrontMostExcludedTask if set, will ensure that the front most excluded task * will be visible, otherwise no excluded tasks will be * visible. */public List getRecentTasks(int numLatestTasks, int userId, boolean includeFrontMostExcludedTask, ArraySet quietProfileIds) { ...... // Remove home/recents/excluded tasks int minNumTasksToQuery = 10; int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks); int flags = ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS | ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK | ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS | ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES; if (includeFrontMostExcludedTask) { flags |= ActivityManager.RECENT_WITH_EXCLUDED; } List tasks = null; try { tasks = mAm.getRecentTasksForUser(numTasksToQuery, flags, userId); } catch (Exception e) { Log.e(TAG, "Failed to get recent tasks", e); } ...... return tasks.subList(0, Math.min(tasks.size(), numLatestTasks)); }
这里设置了flag,不去获取HOME_STACK_ID、DOCKED_STACK_ID、PINNED_STACK_ID上的task,根据机器内存大小设置了最大的查询数
然后调用ActivityManager的getRecentTasksForUser方法
frameworks/base/core/java/android/app/ActivityManager.java
public List getRecentTasksForUser(int maxNum, int flags, int userId) throws SecurityException { try { return ActivityManagerNative.getDefault().getRecentTasks(maxNum, flags, userId).getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); }}
通过binder通信最终会进入到ams
在ams中,有一个mRecentTasks对象,该对象保存了近期启动的task任务信息,RecentsActivity实际上是要获取mRecentTasks对象
**frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java **
/** * List of intents that were used to start the most recent tasks. */final RecentTasks mRecentTasks; @Overridepublic ParceledListSlice getRecentTasks(int maxNum, int flags, int userId) { ...... mRecentTasks.loadUserRecentsLocked(userId); final int recentsCount = mRecentTasks.size(); ArrayList res = new ArrayList<>(maxNum < recentsCount ? maxNum : recentsCount); ...... for (int i = 0; i < recentsCount && maxNum > 0; i++) { TaskRecord tr = mRecentTasks.get(i); ...... ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr); if (!detailed) { rti.baseIntent.replaceExtras((Bundle)null); } res.add(rti); maxNum--; } } return new ParceledListSlice<>(res); }}
首先loadUserRecentsLocked
frameworks/base/services/core/java/com/android/server/am/RecentTasks.java
/** * Loads the persistent recentTasks for {@code userId} into this list from persistent storage. * Does nothing if they are already loaded. * * @param userId the user Id */void loadUserRecentsLocked(int userId) { if (!mUsersWithRecentsLoaded.get(userId)) { // Load the task ids if not loaded. loadPersistedTaskIdsForUserLocked(userId); Slog.i(TAG, "Loading recents for user " + userId + " into memory."); addAll(mTaskPersister.restoreTasksForUserLocked(userId)); cleanupLocked(userId); mUsersWithRecentsLoaded.put(userId, true); }}
通过restoreTasksForUserLocked方法去获取task列表
frameworks/base/services/core/java/com/android/server/am/TaskPersister.java
List restoreTasksForUserLocked(final int userId) { final ArrayList tasks = new ArrayList(); ArraySet recoveredTaskIds = new ArraySet(); File userTasksDir = getUserTasksDir(userId); File[] recentFiles = userTasksDir.listFiles(); if (recentFiles == null) { Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir); return tasks; } for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) { File taskFile = recentFiles[taskNdx]; if (DEBUG) { Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId + ", taskFile=" + taskFile.getName()); } BufferedReader reader = null; boolean deleteFile = false; try { reader = new BufferedReader(new FileReader(taskFile)); final XmlPullParser in = Xml.newPullParser(); in.setInput(reader); int event; while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && event != XmlPullParser.END_TAG) { final String name = in.getName(); if (event == XmlPullParser.START_TAG) { if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: START_TAG name=" + name); if (TAG_TASK.equals(name)) { final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor); ...... return tasks;}
主要是去解析xml文件,位于/data/system_ce/0/recent_tasks目录下
image.png可以看到这些task信息是以文件形式保存的,这就是重启后进RecentsActivity看到task还在的原因。
解析完这些xml文件就获取到了初始的task信息。
但实际上loadUserRecentsLocked里面的语句是只会在开机初始化时执行一次,因此这里相当于什么都没有做。
然后还要回到ActivityManagerService中,根据之前设置的flag去排除掉不需要的task,最后调用createRecentTaskInfoFromTaskRecord()方法把TaskRecord信息转换成RecentTaskInfo的信息。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
/** * Creates a new RecentTaskInfo from a TaskRecord. */private ActivityManager.RecentTaskInfo createRecentTaskInfoFromTaskRecord(TaskRecord tr) { // Update the task description to reflect any changes in the task stack tr.updateTaskDescription(); // Compose the recent task info ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); rti.id = tr.getTopActivity() == null ? INVALID_TASK_ID : tr.taskId; rti.persistentId = tr.taskId; rti.baseIntent = new Intent(tr.getBaseIntent()); rti.origActivity = tr.origActivity; rti.realActivity = tr.realActivity; rti.description = tr.lastDescription; rti.stackId = tr.stack != null ? tr.stack.mStackId : -1; rti.userId = tr.userId; rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription); rti.firstActiveTime = tr.firstActiveTime; rti.lastActiveTime = tr.lastActiveTime; rti.affiliatedTaskId = tr.mAffiliatedTaskId; rti.affiliatedTaskColor = tr.mAffiliatedTaskColor; rti.numActivities = 0; if (tr.mBounds != null) { rti.bounds = new Rect(tr.mBounds); } rti.isDockable = tr.canGoInDockedStack(); rti.resizeMode = tr.mResizeMode; ActivityRecord base = null; ActivityRecord top = null; ActivityRecord tmp; for (int i = tr.mActivities.size() - 1; i >= 0; --i) { tmp = tr.mActivities.get(i); if (tmp.finishing) { continue; } base = tmp; if (top == null || (top.state == ActivityState.INITIALIZING)) { top = base; } rti.numActivities++; } rti.baseActivity = (base != null) ? base.intent.getComponent() : null; rti.topActivity = (top != null) ? top.intent.getComponent() : null; return rti;}
从这里可以看到recenttask是以TaskReord为单位进行管理的,不是一app或者activity为单位进行管理。
到这里就获取了所需的RecentTaskInfo信息。
从这里可以看到mRecentTasks只是剔除了一些不符合要求的task做了些简单的处理就返回了,那么mRecentTasks真正是在哪里赋值的呢?
有两个地方,一是在startActivity的过程中,二是在activity 重新resume时。
先看startActivity时,这里省略了startActivity的具体过程
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { ...... if (andResume) { // As part of the process of launching, ActivityThread also performs // a resume. stack.minimalResumeActivityLocked(r); } ...... return true; }
在minimalResumeActivityLocked方法中将TaskRecord对象加入到mRecentTasks对象中
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java void minimalResumeActivityLocked(ActivityRecord r) { ...... mRecentTasks.addLocked(r.task); ......}
这里有个疑问,ActivityStack中的mRecentTasks是怎么和ActivityManagerService的mRecentTasks联系起来的呢?
在ams初始化时创建了ActivityStackSupervisor对象,用来辅助ams管理ActivityStack
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public ActivityManagerService(Context systemContext) { ...... mStackSupervisor = new ActivityStackSupervisor(this); mActivityStarter = new ActivityStarter(this, mStackSupervisor); mRecentTasks = new RecentTasks(this, mStackSupervisor); ......}
同时也创建了mRecentTasks对象,参数是ams和mStackSupervisor。
RecentTasks的构造函数中又把自己通过setRecentTasks的方法保存到了ActivityStackSupervisor
frameworks/base/services/core/java/com/android/server/am/RecentTasks.java RecentTasks(ActivityManagerService service, ActivityStackSupervisor mStackSupervisor) { ...... mStackSupervisor.setRecentTasks(this); } frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java ...... private RecentTasks mRecentTasks; ...... void setRecentTasks(RecentTasks recentTasks) { mRecentTasks = recentTasks; }
ActivityStackSupervisor中也保存了一个RecentTasks对象,这样实际上和ActivityManagerService的mRecentTasks指向了同一个地址。
在ActivityStackSupervisor中创建ActivityStack时,又把mRecentTasks传递到了ActivityStack中,
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java ActivityContainer(int stackId) { synchronized (mService) { ...... mStack = new ActivityStack(this, mRecentTasks); ...... } }
这样ActivityStack中的mRecentTasks就和ActivityManagerService的mRecentTasks保持一致了。
现在回到mRecentTasks的赋值问题,第二个时机是在activity 重新resume时。
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { ......mRecentTasks.addLocked(next.task); ...... }
(2)Apps缩略图的获取
preloadRecents()调用RecentsTaskLoader的preloadPlan方法,之后调用getAndUpdateThumbnail获取缩略图。
/frameworks/base/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java /** Preloads recents tasks using the specified plan to store the output. */public void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId, boolean includeFrontMostExcludedTask) { plan.preloadPlan(this, runningTaskId, includeFrontMostExcludedTask);}/** * Returns the cached thumbnail if the task key is not expired, updating the cache if it is. */Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) { SystemServicesProxy ssp = Recents.getSystemServices(); // Return the cached thumbnail if it exists ThumbnailData thumbnailData = mThumbnailCache.getAndInvalidateIfModified(taskKey); if (thumbnailData != null) { return thumbnailData.thumbnail; } if (loadIfNotCached) { RecentsConfiguration config = Recents.getConfiguration(); if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) { // Load the thumbnail from the system thumbnailData = ssp.getTaskThumbnail(taskKey.id); if (thumbnailData.thumbnail != null) { mThumbnailCache.put(taskKey, thumbnailData); return thumbnailData.thumbnail; } } } // We couldn't load any thumbnail return null;}
之前获取到RecentTaskInfo之后就要去获取缩略图信息了
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.javapublic void getThumbnail(int taskId, ThumbnailData thumbnailDataOut) { ... ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId); ... }
很简洁,就调用了ActivityManager的方法
frameworks/base/core/java/android/app/ActivityManager.java public TaskThumbnail getTaskThumbnail(int id) throws SecurityException { try { return ActivityManagerNative.getDefault().getTaskThumbnail(id); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
通过binder通信调用了ams的方法
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public ActivityManager.TaskThumbnail getTaskThumbnail(int id) { synchronized (this) { enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, "getTaskThumbnail()"); final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked( id, !RESTORE_FROM_RECENTS, INVALID_STACK_ID); if (tr != null) { return tr.getTaskThumbnailLocked(); } } return null; }
首先根据taskid去找到TaskRecord,然后获取Thumbnail
public TaskThumbnail getTaskThumbnailLocked() { if (stack != null) { final ActivityRecord resumedActivity = stack.mResumedActivity; if (resumedActivity != null && resumedActivity.task == this) { final Bitmap thumbnail = stack.screenshotActivitiesLocked(resumedActivity); setLastThumbnailLocked(thumbnail); } } final TaskThumbnail taskThumbnail = new TaskThumbnail(); getLastThumbnail(taskThumbnail); return taskThumbnail; }
这里除了栈顶正在显示的TaskRecord回去实时的截取屏幕图像,其他的走getLastThumbnail
frameworks/base/services/core/java/com/android/server/am/TaskRecord.java void getLastThumbnail(TaskThumbnail thumbs) { thumbs.mainThumbnail = mLastThumbnail; thumbs.thumbnailInfo = mLastThumbnailInfo; thumbs.thumbnailFileDescriptor = null; if (mLastThumbnail == null) { thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue( mLastThumbnailFile.getAbsolutePath()); } // Only load the thumbnail file if we don't have a thumbnail if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) { try { thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile, ParcelFileDescriptor.MODE_READ_ONLY); } catch (IOException e) { } } }
这里实际是去读取文件,这些缩略图已经保存在/data/system_ce/0/recent_images文件夹下
image.png把这些文件读取出来就获取到了task的缩略图。
但是这里并没有看到去截屏,这些图片是什么时候截取的呢?
截图的时机是在activity onpause之后。
frameworks/base/services/core/java/com/android/server/am/ActivityStack.javaprivate void completePauseLocked(boolean resumeNext) { ... mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.javavoid ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, boolean preserveWindows) { // First the front stacks. In case any are not fullscreen and are in front of home. for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks; final int topStackNdx = stacks.size() - 1; for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { final ActivityStack stack = stacks.get(stackNdx); stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows); } } } frameworks/base/services/core/java/com/android/server/am/ActivityStack.java final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, boolean preserveWindows) { ... makeInvisible(r, visibleBehind); ... } frameworks/base/services/core/java/com/android/server/am/ActivityStack.java private void makeInvisible(ActivityRecord r, ActivityRecord visibleBehind) { ... try { setVisible(r, false); ... } catch (Exception e) { ... } }
makeInvisible又调用了setVisible
private void setVisible(ActivityRecord r, boolean visible) { r.visible = visible; if (!visible && r.mUpdateTaskThumbnailWhenHidden) { r.updateThumbnailLocked(r.task.stack.screenshotActivitiesLocked(r), null); r.mUpdateTaskThumbnailWhenHidden = false; } ... }
就是在这里更新TaskThumbnail的,screenshotActivitiesLocked(r)是真正截图的地方
截图完成之后,最终通过saveImage方法保存到文件中,这里path为/data/system_ce/0/recent_images文件夹
frameworks/base/services/core/java/com/android/server/am/RecentTasks.java void saveImage(Bitmap image, String path) { mTaskPersister.saveImage(image, path); }
这样需要获取缩略图时之前去读文件就可以了。
(3)removeTask
当从RecentsActivity移除某一个应用时,实际会调用到removeTask
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java public void removeTask(final int taskId) { ... // Remove the task. BackgroundThread.getHandler().post(new Runnable() { @Override public void run() { mAm.removeTask(taskId); } }); }
然后调用到ams的removeTask方法,参数taskId为要移除的TaskRecord的id
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public boolean removeTask(int taskId) { enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()"); synchronized (this) { final long ident = Binder.clearCallingIdentity(); try { return removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS); } finally { Binder.restoreCallingIdentity(ident); } } }
调用该方法首先会检查是否有声明android.Manifest.permission.REMOVE_TASKS的权限,这里我们是有声明这个权限的。然后调用removeTaskByIdLocked
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java private boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents) { final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked( taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID); if (tr != null) { tr.removeTaskActivitiesLocked(); cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents); if (tr.isPersistable) { notifyTaskPersisterLocked(null, true); } return true; } Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId); return false; }
先看下这里的参数,taskid为要移除的task id,killProcess为true,表示要杀掉该taskrecord里所有activity所在的进程,removeFromRecents为true,表示要从mRecentTasks移除。
这里通过taskid找到该TaskRecord,然后首先调用了TaskRecord的removeTaskActivitiesLocked方法
frameworks/base/services/core/java/com/android/server/am/TaskRecord.java public void removeTaskActivitiesLocked() { // Just remove the entire task. performClearTaskAtIndexLocked(0); } frameworks/base/services/core/java/com/android/server/am/TaskRecord.java final void performClearTaskAtIndexLocked(int activityNdx) { int numActivities = mActivities.size(); for ( ; activityNdx < numActivities; ++activityNdx) { final ActivityRecord r = mActivities.get(activityNdx); if (r.finishing) { continue; } if (stack == null) { // Task was restored from persistent storage. r.takeFromHistory(); mActivities.remove(activityNdx); --activityNdx; --numActivities; } else if (stack.finishActivityLocked( r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) { --activityNdx; --numActivities; } } }
传递下来的参数activityNdx = 0,表示吧整个TaskRecord移除。这里的mActivities是该TaskRecord中保存的所有ActivityRecord对象,stack是该TaskRecord所在的ActivityStack,这里不为空,所以会调用ActivityStack的finishActivityLocked方法去移除该TaskRecord中的ActivityRecord对象。
从ActivityStack移除完TaskRecord之后回到removeTaskByIdLocked,然后又调用了cleanUpRemovedTaskLocked方法
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) { if (removeFromRecents) { mRecentTasks.remove(tr); tr.removedFromRecents(); } ComponentName component = tr.getBaseIntent().getComponent(); if (component == null) { Slog.w(TAG, "No component for base intent of task: " + tr); return; } // Find any running services associated with this app and stop if needed. mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent())); if (!killProcess) { return; } // Determine if the process(es) for this task should be killed. final String pkg = component.getPackageName(); ArrayList procsToKill = new ArrayList<>(); ArrayMap> pmap = mProcessNames.getMap(); for (int i = 0; i < pmap.size(); i++) { SparseArray uids = pmap.valueAt(i); for (int j = 0; j < uids.size(); j++) { ProcessRecord proc = uids.valueAt(j); if (proc.userId != tr.userId) { // Don't kill process for a different user. continue; } if (proc == mHomeProcess) { // Don't kill the home process along with tasks from the same package. continue; } if (!proc.pkgList.containsKey(pkg)) { // Don't kill process that is not associated with this task. continue; } for (int k = 0; k < proc.activities.size(); k++) { TaskRecord otherTask = proc.activities.get(k).task; if (tr.taskId != otherTask.taskId && otherTask.inRecents) { // Don't kill process(es) that has an activity in a different task that is // also in recents. return; } } if (proc.foregroundServices) { // Don't kill process(es) with foreground service. return; } // Add process to kill list. procsToKill.add(proc); } } // Kill the running processes. for (int i = 0; i < procsToKill.size(); i++) { ProcessRecord pr = procsToKill.get(i); if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND && pr.curReceiver == null) { pr.kill("remove task", true); } else { // We delay killing processes that are not in the background or running a receiver. pr.waitingToKill = "remove task"; } } }
这里removeFromRecents为true,因此会先将该TaskRecord从mRecentTasks中移除,然后过滤出可以杀掉的Process的ProcessRecord信息,放到procsToKill列表中。分两种情况,如果是SCHED_GROUP_BACKGROUND类型并且没有在执行reciver,会调用kill方法立即去杀掉。否则简单将procsToKill中ProcessRecord的waitingToKill字段设置为remove task。这里涉及到Android进程管理的相关知识,可参看
Android系统中的进程管理:进程的优先级
参考文档:
RecentsActivity启动分析一
RecentsActivity启动分析二
Android 7.0 SystemUI(3)--RecentsActivity
android 6.0 SystemUI源码分析(3)-Recent Panel加载显示流程
Android 7.0 SystemUI 之启动和状态栏和导航栏简介
更多相关文章
- Android(安卓)JNI入门实例(Windows+Cygwin+Eclipse)
- android之JSON解析(三)
- Android(安卓)Context getSystemService分析
- SettingActivity学习笔记
- Android(安卓)获取控件高度宽度三种方法
- Android实现WebView删除缓存的方法
- android 镜像制作方法
- Android(安卓)Vold和SDIO冲突问题解决方法
- 【Android(安卓)开发教程】使用Intent-Filter