Android T TaskSnapshot创建和移除流程

数据结构

  • WindowManagerService
    窗口管理服务,TaskSnapshoController是它的成员之一
  • TaskSnapshotController
    是TaskSnapShot对外的接口,管理TaskSnapshot的创建,获取与销毁
  • TaskSnapshotLoader
    从磁盘中加载TaskSnapshot,TaskSnapshot不仅会缓存在内存里,还会写在磁盘中。TaskSnapshotLoader负责从磁盘中恢复应用快照。(示例场景:启动数个应用->重启系统->进入多任务。在这种场景下,系统重启之后,多任务的显示需要页面快照,系统进程此时没有TaskSnapshot的缓存,这个时候便会从磁盘中加载快照。)
  • TaskSnapshotPersister
    负责TaskSnapshot在磁盘中的创建、读取与销毁
  • TaskSnapshotCache
    负责TaskSnaphshot在内存中的创建,读取与销毁。当应用从前台退到后台时,TaskSnapShot就会被缓存在TaskSnapshotCache中。并且ActivityRecord与TaskId存在映射,TaskId与TaskSnapshot存在映射。这样一来,在应用从后台回到前台时,通过taskId便能获取TaskSnapshot;在应用退出时,能通过ActivityRecord获取TaskSnapshot,将TaskSnapshot移除。
  • TaskSnapshot
    应用的快照,存储着应用快照的数据,如Task的Id、Size、TopActivity的ComponentName和最关键的GraphicBuffer。TaskSnapshot实现了Parcelable,因为其他应用页需要快照例如Launcher的多任务。
    Android T TaskSnapshot创建和移除流程_第1张图片

主流程

Android T TaskSnapshot创建和移除流程_第2张图片
应用切换至后台
因为应用从后台切换到前台需要使用快照填充启动窗口,所以需要在它进入后台时保存快照。应用的切换场会填充过度动画,task的快照流程的起点被设计在过渡动画的起点。
Android T TaskSnapshot创建和移除流程_第3张图片
Back键退出应用
使用back键退出应用时Activity会被销毁,因此再次启动过应用时不属于热启动,不需要应用快照。但是多任务页面仍需要应用快照,所以只是移除应用快照的缓存。

Android T TaskSnapshot创建和移除流程_第4张图片
从多任务退出应用
从多任务页面中移除应用时进程会被销毁,因此再次启动应用属于冷启动。此时没有任何场景需要再使用应用快照,所以将它的缓存和磁盘存储全部移除。

TashSnapshot的创建

过渡动画

TaskSnapshot的创建在过渡动画开始时执行,大致流程为:准备过渡动画->执行过渡动画
当应用启动时和应用退到后台时,系统进程都会为应用准备过渡动画。
执行过渡动画的时机位于WMS的布局流程中,只有在窗口完成绘制之后,才能执行过渡动画。
以RootWindowContainer.java#performSurfacePlacementNoTrace()为起点,分析TaskSnapshot创建流程

 void performSurfacePlacementNoTrace() {
 	......
 	final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
 	......
 	checkAppTransitionReady(surfacePlacer);
 	......
 }

布局循环开始之时,先检查过渡动画是否准备好了

    private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) {
        // Trace all displays app transition by Z-order for pending layout change.
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final DisplayContent curDisplay = mChildren.get(i);

            // If we are ready to perform an app transition, check through all of the app tokens
            // to be shown and see if they are ready to go.
            if (curDisplay.mAppTransition.isReady()) {
                // handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
                curDisplay.mAppTransitionController.handleAppTransitionReady();
				......
            }

            ......
        }
    }

启动应用时prepare过渡动画,应用完成onresume时,execute过渡动画,所以此时可以handle过渡动画。即prepare-execute-handle
DisplayContent.java
mAppTransitionController = new AppTransitionController(mWmService, this);
AppTransitionController.java

void handleAppTransitionReady() {
    ......
    mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
}

此时动画已经配置到了窗口,通知TaskSnapshotController过渡动画正在开始。

获取ClosingTasks

紧接着上述代码流程
TaskSnapshotController.java

    void onTransitionStarting(DisplayContent displayContent) {
        handleClosingApps(displayContent.mClosingApps);
    }

acitvityRecord设置可见性时,如果activityrecord即将不可见,那么会将activityRecord添加到displayContent.mClosingApps

    private void handleClosingApps(ArraySet<ActivityRecord> closingApps) {
        if (shouldDisableSnapshots()) {
            return;
        }
        // We need to take a snapshot of the task if and only if all activities of the task are
        // either closing or hidden.
        getClosingTasks(closingApps, mTmpTasks);
        snapshotTasks(mTmpTasks);
        mSkipClosingAppSnapshotTasks.clear();
    }
   /**
     * Retrieves all closing tasks based on the list of closing apps during an app transition.
     */
    @VisibleForTesting
    void getClosingTasks(ArraySet<ActivityRecord> closingApps, ArraySet<Task> outClosingTasks) {
        outClosingTasks.clear();
        for (int i = closingApps.size() - 1; i >= 0; i--) {
            final ActivityRecord activity = closingApps.valueAt(i);
            final Task task = activity.getTask();
            if (task == null) continue;

            // Since RecentsAnimation will handle task snapshot while switching apps with the
            // best capture timing (e.g. IME window capture),
            // No need additional task capture while task is controlled by RecentsAnimation.
            if (isAnimatingByRecents(task)) {
                mSkipClosingAppSnapshotTasks.add(task);
            }
            // If the task of the app is not visible anymore, it means no other app in that task
            // is opening. Thus, the task is closing.
            if (!task.isVisible() && !mSkipClosingAppSnapshotTasks.contains(task)) {
                outClosingTasks.add(task);
            }
        }
    }

并不是所有的closingApps都需要进行截图。从getClosingTasks(closingApps, mTmpTasks)的实现可以看出,截图是针对task的,只有即将不可见的task才需要截图。
snapshotTasks(mTmpTasks)对过滤之后的closingApps进行缓存和持久化存储操作
从snapshotTasks()走到了recordTaskSnapshot()

    void snapshotTasks(ArraySet<Task> tasks) {
        snapshotTasks(tasks, false /* allowSnapshotHome */);
    }
    private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
        for (int i = tasks.size() - 1; i >= 0; i--) {
            recordTaskSnapshot(tasks.valueAt(i), allowSnapshotHome);
        }
    }

recordTaskSnapshot

    void recordTaskSnapshot(Task task, boolean allowSnapshotHome) {
        final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
        final TaskSnapshot snapshot = captureTaskSnapshot(task, snapshotHome);
        
        final HardwareBuffer buffer = snapshot.getHardwareBuffer();
        if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
            buffer.close();
            Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
                    + buffer.getHeight());
        } else {
        	//缓存snapshot
            mCache.putSnapshot(task, snapshot);
            // Don't persist or notify the change for the temporal snapshot.
            if (!snapshotHome) {
            	//如果不是home类型的task,持久化存储snapshot
                mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
                task.onSnapshotChanged(snapshot);
            }
        }
    }

1、根据不同的条件获取TaskSnapshot
2、缓存snapshot
3、持久化存储snapshot

获取TaskSnapshot

   /**
    * This is different than {@link #recordTaskSnapshot(Task, boolean)} because it doesn't store
    * the snapshot to the cache and returns the TaskSnapshot immediately.
    *
    * This is only used for testing so the snapshot content can be verified.
    */
   @VisibleForTesting
   TaskSnapshot captureTaskSnapshot(Task task, boolean snapshotHome) {
       final TaskSnapshot snapshot;
       if (snapshotHome) {
       	//allowSnapshotHome在本流程中为false,所以不会进入该分支。
       	//如果锁屏被设置了密码,那么在息屏流程中就会设置allowSnapshotHome为true,会进入该分支。
           snapshot = snapshotTask(task);
       } else {
           switch (getSnapshotMode(task)) {
               case SNAPSHOT_MODE_NONE:
                   return null;
               case SNAPSHOT_MODE_APP_THEME:
               	//SNAPSHOT_MODE_APP_THEME模式表示不希望使用窗口的内容构建snapshot,只使用App的theme。
               	//例如被标记了WindowManager。LayoutParams.FLAG_SECURE的安全窗口;
               	//像PipMenuActivity设置了ATMS.setDisablePreviewScreenshots()
                   snapshot = drawAppThemeSnapshot(task);
                   break;
               case SNAPSHOT_MODE_REAL:
               	//SNAPSHOT_MODE_REAL模式使用task的页面的内容构建snapshot
                   snapshot = snapshotTask(task);
                   break;
               default:
                   snapshot = null;
                   break;
           }
       }
       return snapshot;
   }
   @VisibleForTesting
   int getSnapshotMode(Task task) {
       final ActivityRecord topChild = task.getTopMostActivity();
       if (!task.isActivityTypeStandardOrUndefined() && !task.isActivityTypeAssistant()) {
       //如果ActivityType不是ACTIVITY_TYPE_UNDEFINED、ACTIVITY_TYPE_STANDARD、
       //ACTIVITY_TYPE_ASSISTANT中的一种,那么就不会为其创建snapshot。
       //从前面final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
       //可以看出ACTIVITY_TYPE_HOME(即launcher)也是被排除在外的
           return SNAPSHOT_MODE_NONE;
       } else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
           return SNAPSHOT_MODE_APP_THEME;
       } else {
           return SNAPSHOT_MODE_REAL;
       }
   }

我们分别来看看captureTaskSnapshot中的snapshot = drawAppThemeSnapshot(task);snapshot = snapshotTask(task);

drawAppThemeSnapshot
    /**
     * If we are not allowed to take a real screenshot, this attempts to represent the app as best
     * as possible by using the theme's window background.
     */
    private TaskSnapshot drawAppThemeSnapshot(Task task) {
    	......
        final int color = ColorUtils.setAlphaComponent(
                task.getTaskDescription().getBackgroundColor(), 255);
        ......
        final RenderNode node = RenderNode.create("TaskSnapshotController", null);
        node.setLeftTopRightBottom(0, 0, width, height);
        node.setClipToBounds(false);
        final RecordingCanvas c = node.start(width, height);
        c.drawColor(color);//设置页面颜色,color值从task背景色获取,alpha值255不透明
		......
        final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
		......

        // Note, the app theme snapshot is never translucent because we enforce a non-translucent
        // color above
        return new TaskSnapshot(
                System.currentTimeMillis() /* id */,
                topChild.mActivityComponent, hwBitmap.getHardwareBuffer(),
                hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation,
                mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight),
                contentInsets, letterboxInsets, false /* isLowResolution */,
                false /* isRealSnapshot */, task.getWindowingMode(),
                getAppearance(task), false /* isTranslucent */, false /* hasImeSurface */);
    }

从Bitmap获取GraphicBuffer,作为TaskSnapshot的内容,所以drawAppThemeSnapshot()就是使用task背景色构建snapshot。

snapshotTask
    @Nullable
    TaskSnapshot snapshotTask(Task task) {
        return snapshotTask(task, PixelFormat.UNKNOWN);
    }

    @Nullable
    TaskSnapshot snapshotTask(Task task, int pixelFormat) {
        TaskSnapshot.Builder builder = new TaskSnapshot.Builder();
        ......
		//构建TaskSnapshot的核心还是在于GraphicBuffer的获取
        final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                createTaskSnapshot(task, builder);
		......
        return builder.build();
    }
    
    @Nullable
    SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
            TaskSnapshot.Builder builder) {
        Point taskSize = new Point();
        final SurfaceControl.ScreenshotHardwareBuffer taskSnapshot = createTaskSnapshot(task,
                mHighResTaskSnapshotScale, builder.getPixelFormat(), taskSize, builder);
        builder.setTaskSize(taskSize);
        return taskSnapshot;
    }

    @Nullable
    SurfaceControl.ScreenshotHardwareBuffer createTaskSnapshot(@NonNull Task task,
            float scaleFraction, int pixelFormat, Point outTaskSize, TaskSnapshot.Builder builder) {
        ......
        //使用Task的SurfaceControl获取GraphicBuffer,窗口的buffer本就是SurfaceControl提供的
        final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
                SurfaceControl.captureLayersExcluding(
                        task.getSurfaceControl(), mTmpRect, scaleFraction,
                        pixelFormat, excludeLayers);
        ......
        return screenshotBuffer;
    }
    

缓存Tasksnapshot

继续看recordTaskSnapshot方法中的mCache.putSnapshot(task, snapshot)
mCache是TaskSnapshotCache的对象
TaskSnapshotCache.java

    void putSnapshot(Task task, TaskSnapshot snapshot) {
        final CacheEntry entry = mRunningCache.get(task.mTaskId);
        if (entry != null) {
        	//更新操作,为了将新的ActivityRecord的task绑定在一起
            mAppTaskMap.remove(entry.topApp);
        }
        final ActivityRecord top = task.getTopMostActivity();
        mAppTaskMap.put(top, task.mTaskId);
        mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, top));
    }

mAppTaskMap.put(top, task.mTaskId);表示ActivityRecord和taskId建立映射关系
为什么不直接使用RunningCache,非要用两个map呢?这是为了监听通过ActivityRecord的remove来更新RunningCache。

mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, top));表示taskId和CacheEntry建立映射关系
为什么需要使用CacheEntry呢?这是应用需要通过taskId找到ActivityRecord,这样taskId和ActivityRecord完成了双向绑定。在ActivityRecord被移除时,可以顺着两个map移除snapshot;添加新的snapshot时,将旧的ActivityRecord移除,CacheEntry会直接被新的覆盖

持久化存储TaskSnapshot

Android的持久化存储基本都是使用Persister线程+Item队列的模式。
考虑到耗时和多线程的原因,创建一个线程用于处理各个场景创建的文件操作任务
把文件操作任务抽象成一个Item,这里WriteQueueItem。然后派生不同Item描述不同类型的操作

继续看recordTaskSnapshot方法中的mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);其中mPersister为TaskSnapshotPersister对象
TaskSnapshotPersister.java

    /**
     * Persists a snapshot of a task to disk.
     *
     * @param taskId The id of the task that needs to be persisted.
     * @param userId The id of the user this tasks belongs to.
     * @param snapshot The snapshot to persist.
     */
    void persistSnapshot(int taskId, int userId, TaskSnapshot snapshot) {
        synchronized (mLock) {
            mPersistedTaskIdsSinceLastRemoveObsolete.add(taskId);
            sendToQueueLocked(new StoreWriteQueueItem(taskId, userId, snapshot));
        }
    }

将TaskSnapshot持久化到磁盘

StoreWriteQueueItem
    private class StoreWriteQueueItem extends WriteQueueItem { 
		......
        @Override
        void write() {
            if (!createDirectory(mUserId)) {
                Slog.e(TAG, "Unable to create snapshot directory for user dir="
                        + getDirectory(mUserId));
            }
            boolean failed = false;
            if (!writeProto()) {
                failed = true;
            }
            if (!writeBuffer()) {
                failed = true;
            }
            if (failed) {
                deleteSnapshot(mTaskId, mUserId);
            }
        }
		......
    }

StoreWriteQueueItem描述了存储磁盘的任务,在重写的write方法中,会创建文件存储snapshot的task信息,buffer信息

sendToQueueLocked
    @GuardedBy("mLock")
    private void sendToQueueLocked(WriteQueueItem item) {
        mWriteQueue.offer(item); //入队操作
        item.onQueuedLocked();
        ensureStoreQueueDepthLocked();
        if (!mPaused) {
            mLock.notifyAll();//唤醒Persist线程
        }
    }
mPersister线程
    private Thread mPersister = new Thread("TaskSnapshotPersister") {
        public void run() {
            android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            while (true) {
                WriteQueueItem next;
                boolean isReadyToWrite = false;
                synchronized (mLock) {
                    if (mPaused) {
                        next = null;
                    } else {
                        next = mWriteQueue.poll();
                        if (next != null) {
                            if (next.isReady()) {
                                isReadyToWrite = true;
                                next.onDequeuedLocked();
                            } else {
                                mWriteQueue.addLast(next);
                            }
                        }
                    }
                }
                if (next != null) {
                    if (isReadyToWrite) {
                        next.write();//取出Item任务后执行
                    }
                    SystemClock.sleep(DELAY_MS);
                }
                synchronized (mLock) {
                    final boolean writeQueueEmpty = mWriteQueue.isEmpty();
                    if (!writeQueueEmpty && !mPaused) {
                        continue;
                    }
                    try {
                        mQueueIdling = writeQueueEmpty;
                        mLock.wait();//执行完队列的所有任务进入等待状态,等待另一个线程来唤醒
                        mQueueIdling = false;
                    } catch (InterruptedException e) {
                    }
                }
            }
        }
    };

TaskSnapshot的移除

在什么时候需要移除TaskSnapshot?是在task被销毁的时候,两个移除场景
从back键退出应用和从多任务移除应用

从back键退出应用

一般来说,Activity对back事件的处理是移除Activity。TaskSnapshotController对Activity的移除比较感兴趣,所以在Activity被移除时TaskSnapshotController会尝试异常TaskSnapshot的缓存

移除的起点

ActivityClientController#activityDestroyed

class ActivityClientController extends IActivityClientController.Stub {
@Override
    public void activityDestroyed(IBinder token) {
        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token);
        final long origId = Binder.clearCallingIdentity();
        synchronized (mGlobalLock) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityDestroyed");
            try {
                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
                if (r != null) {
                    r.destroyed("activityDestroyed");
                }
            } finally {
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                Binder.restoreCallingIdentity(origId);
            }
        }
    }
}

这里调用r.destroyed("activityDestroyed");其中r为ActivityRecord对象

ActivityRecord.java

 /**
     * This method is to only be called from the client via binder when the activity is destroyed
     * AND finished.
     */
    void destroyed(String reason) {
        removeDestroyTimeout();

        ProtoLog.d(WM_DEBUG_CONTAINERS, "activityDestroyedLocked: r=%s", this);

        if (!isState(DESTROYING, DESTROYED)) {
            throw new IllegalStateException(
                    "Reported destroyed for activity that is not destroying: r=" + this);
        }

        if (isInRootTaskLocked()) {
            cleanUp(true /* cleanServices */, false /* setState */);
            removeFromHistory(reason);
        }

        mRootWindowContainer.resumeFocusedTasksTopActivities();
    }

调用removeFromHistory(reason);

 /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */
    void removeFromHistory(String reason) {
        finishActivityResults(Activity.RESULT_CANCELED,
                null /* resultData */, null /* resultGrants */);
        makeFinishingLocked();

        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing activity %s, reason= %s "
                        + "callers=%s", this, reason, Debug.getCallers(5));

        takeFromHistory();
        removeTimeouts();
        ProtoLog.v(WM_DEBUG_STATES, "Moving to DESTROYED: %s (removed from history)",
                this);
        setState(DESTROYED, "removeFromHistory");
        if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
        detachFromProcess();
        // Resume key dispatching if it is currently paused before we remove the container.
        resumeKeyDispatchingLocked();
        mDisplayContent.removeAppToken(token);

        cleanUpActivityServices();
        removeUriPermissionsLocked();
    }

调用mDisplayContent.removeAppToken(token);为DisplayContent对象

DisplayContent.java

    void removeAppToken(IBinder binder) {
        final WindowToken token = removeWindowToken(binder, true /* animateExit */);
        if (token == null) {
            Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder);
            return;
        }

        final ActivityRecord activity = token.asActivityRecord();

        if (activity == null) {
            Slog.w(TAG_WM, "Attempted to remove non-App token: " + binder + " token=" + token);
            return;
        }

        activity.onRemovedFromDisplay();
        if (activity == mFixedRotationLaunchingApp) {
            // Make sure the states of associated tokens are also cleared.
            activity.finishFixedRotationTransform();
            setFixedRotationLaunchingAppUnchecked(null);
        }
    }

调用activity.onRemovedFromDisplay(),activity为ActivityRecord对象

ActivityRecord.java

   void onRemovedFromDisplay() {
        ......
		mWmService.mTaskSnapshotController.onAppRemoved(this);
		......
    }

最终调用到了TaskSnapshotController的onAppRemoved

移除缓存

TaskSnapshotController.java

/**
     * Called when an {@link ActivityRecord} has been removed.
     */
    void onAppRemoved(ActivityRecord activity) {
        mCache.onAppRemoved(activity);
    }

调用mCache.onAppRemoved(activity);mCache为TaskSnapshotCache对象

TaskSnapshotCache.java

    /**
     * Called when an app token has been removed
     */
    void onAppRemoved(ActivityRecord activity) {
        final Integer taskId = mAppTaskMap.get(activity);
        if (taskId != null) {
        	//断开ActivityRecord、taskId与TaskSnapshot之间的映射关系
            removeRunningEntry(taskId);
        }
    }
    void removeRunningEntry(int taskId) {
        final CacheEntry entry = mRunningCache.get(taskId);
        if (entry != null) {
            mAppTaskMap.remove(entry.topApp);
            mRunningCache.remove(taskId);
        }
    }

taskSnapshot的创建流程中,最后一次可见的ActivityRecord与taskId建立映射,所以当且仅当之前建立映射的ActivityRecord被移除时,才会移除缓存。

从多任务移除应用

从多任务移除应用往往意味着这个task被移除了。即也不需要从热启动恢复这个task,不需要从多任务恢复这个task,那么TaskSnapshot的缓存和持久化存储都需要被移除

移除的起点

ActivityTaskManagerService#removeTask

public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
	@Override
    public boolean removeTask(int taskId) {
        mAmInternal.enforceCallingPermission(REMOVE_TASKS, "removeTask()");
        synchronized (mGlobalLock) {
            final long ident = Binder.clearCallingIdentity();
            try {
                final Task task = mRootWindowContainer.anyTaskForId(taskId,
                        MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
                if (task == null) {
                    Slog.w(TAG, "removeTask: No task remove with id=" + taskId);
                    return false;
                }

                if (task.isLeafTask()) {
                    mTaskSupervisor.removeTask(task, true, REMOVE_FROM_RECENTS, "remove-task");
                } else {
                    mTaskSupervisor.removeRootTask(task);
                }
                return true;
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }
}

调用mTaskSupervisor.removeTask(task, true, REMOVE_FROM_RECENTS, "remove-task");mTaskSupervisor为ActivityTaskSupervisor对象

ActivityTaskSupervisor.java

    void removeTask(Task task, boolean killProcess, boolean removeFromRecents, String reason) {
        if (task.mInRemoveTask) {
            // Prevent recursion.
            return;
        }
        task.mTransitionController.requestCloseTransitionIfNeeded(task);
        task.mInRemoveTask = true;
        try {
            task.removeActivities(reason, false /* excludingTaskOverlay */);
            cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
            mService.getLockTaskController().clearLockedTask(task);
            mService.getTaskChangeNotificationController().notifyTaskStackChanged();
            if (task.isPersistable) {
                mService.notifyTaskPersisterLocked(null, true);
            }
        } finally {
            task.mInRemoveTask = false;
        }
    }

调用了cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);

    void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
        if (removeFromRecents) {
            mRecentTasks.remove(task);
        }
		......
    }

调用mRecentTasks.remove(task);mRecentTasks为RecentTasks对象

RecentTasks.java

    /**
     * Remove a task from the recent tasks list.
     */
    void remove(Task task) {
        mTasks.remove(task);
        notifyTaskRemoved(task, false /* wasTrimmed */, false /* killProcess */);
    }
    private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
        for (int i = 0; i < mCallbacks.size(); i++) {
            mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
        }
        mTaskNotificationController.notifyTaskListUpdated();
    }
    interface Callbacks {
        /**
         * Called when a task is added to the recent tasks list.
         */
        void onRecentTaskAdded(Task task);

        /**
         * Called when a task is removed from the recent tasks list.
         */
        void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess);
    }

调用了mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);mCallbacks为Callbacks接口对象,该接口由ActivityTaskSupervisor实现
public class ActivityTaskSupervisor implements RecentTasks.Callbacks
因此onRecentTaskRemoved方法的实现在ActivityTaskSupervisor中

ActivityTaskSupervisor.java

    @Override
    public void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
        if (wasTrimmed) {
            // Task was trimmed from the recent tasks list -- remove the active task record as well
            // since the user won't really be able to go back to it
            removeTaskById(task.mTaskId, killProcess, false /* removeFromRecents */,
                    "recent-task-trimmed");
        }
        task.removedFromRecents();
    }

这里调用了task.removedFromRecents();task为Task对象

Task.java

    void removedFromRecents() {
		......
		mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
                mTaskId, mUserId);
    }

最终调用到TaskSnapshotController的notifyTaskRemovedFromRecents()

TaskSnapshotController.java

    void notifyTaskRemovedFromRecents(int taskId, int userId) {
        mCache.onTaskRemoved(taskId);
        mPersister.onTaskRemovedFromRecents(taskId, userId);
    }

该方法做了两件事:移除缓存和移除持久化存储

移除缓存

TaskSnapshotCache.java

    void onTaskRemoved(int taskId) {
        removeRunningEntry(taskId);//移除两个map中的映射关系

    }

    void removeRunningEntry(int taskId) {
        final CacheEntry entry = mRunningCache.get(taskId);
        if (entry != null) {
            mAppTaskMap.remove(entry.topApp);
            mRunningCache.remove(taskId);
        }
    }

当task在最近任务被移除时,移除缓存

移除持久化存储

TaskSnapshotPersister.java

    /**
     * Callend when a task has been removed.
     *
     * @param taskId The id of task that has been removed.
     * @param userId The id of the user the task belonged to.
     */
    void onTaskRemovedFromRecents(int taskId, int userId) {
        synchronized (mLock) {
        	//在之前的TaskSnapshot的持久化存储流程中有解锁Item队列会被Persist线程按序处理
            mPersistedTaskIdsSinceLastRemoveObsolete.remove(taskId);
            sendToQueueLocked(new DeleteWriteQueueItem(taskId, userId));
        }
    }
    
DeleteWriteQueueItem
    private class DeleteWriteQueueItem extends WriteQueueItem {
        private final int mTaskId;
        private final int mUserId;

        DeleteWriteQueueItem(int taskId, int userId) {
            mTaskId = taskId;
            mUserId = userId;
        }

        @Override
        void write() {
        	//通过taskId和userId找到TaskSnapshot文件存储的位置,并将其删除
            deleteSnapshot(mTaskId, mUserId);
        }
    }
deleteSnapshot
    private void deleteSnapshot(int taskId, int userId) {
        final File protoFile = getProtoFile(taskId, userId);
        final File bitmapLowResFile = getLowResolutionBitmapFile(taskId, userId);
        protoFile.delete();
        if (bitmapLowResFile.exists()) {
            bitmapLowResFile.delete();
        }
        final File bitmapFile = getHighResolutionBitmapFile(taskId, userId);
        if (bitmapFile.exists()) {
            bitmapFile.delete();
        }
    }

你可能感兴趣的:(Android,Android,Framework从入门到入土,android,ui)