Android 7.1.2(Android N) SystemUI--Recents Task 加载显示流程

高清原文

(一)Recent Task 加载流程 和 RecentsActivity启动流程

RecentsActivity.java启动流程:

RecentsActivity.png

RecentsActivity是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 之启动和状态栏和导航栏简介

更多相关文章

  1. Android(安卓)JNI入门实例(Windows+Cygwin+Eclipse)
  2. android之JSON解析(三)
  3. Android(安卓)Context getSystemService分析
  4. SettingActivity学习笔记
  5. Android(安卓)获取控件高度宽度三种方法
  6. Android实现WebView删除缓存的方法
  7. android 镜像制作方法
  8. Android(安卓)Vold和SDIO冲突问题解决方法
  9. 【Android(安卓)开发教程】使用Intent-Filter

随机推荐

  1. Android UDP广播包抓取
  2. 阅读《Android 从入门到精通》(13)——日期
  3. DecimalFormat 实现保留小数点位数及四舍
  4. Android(安卓)认识EventBus到原理解析
  5. linux下如何为刚安装好的Eclipse在桌面建
  6. android 选择图片(从手机照相机或手机图
  7. Android游戏引擎AndEngine使用注意事项
  8. Android 笔记.代码段
  9. Android(安卓)JVM的运行过程
  10. Android上传图片裁剪功能