android 13重启清除任务快照

摘要:客户认为重启设备后点击recent虚拟按键出现的任务快照代表程序正在运行,所以需要清除来表示重启后没有启动过任何应用。本文首先明确任务快照的定义,同时给出正在运行和没有运行的解释说明,最后给出方案。

一、任务快照

Android 系统的最近任务(Recent Apps)列表中的图标只是历史访问记录,不等同于正在后台运行的进程。

设备重启后,在最近任务界面依然能看到您应用的图标,这是系统保存的历史任务快照,并不是 App 还在后台存活、占用内存 / CPU。

原理:Android 会把用户之前打开过的 Activity 任务记录保存在系统任务栈快照里,用于快速恢复页面。这个任务记录是静态元数据 + 页面缩略图 ,独立于 App 进程。

当设备重启后,所有 App 进程都会被系统全部销毁;但部分 Android 版本 / 定制 ROM 会保留历史任务列表记录,重启后依然展示。点击图标才会触发 App 重新启动,不点击则 App 进程不存在,不会后台运行、耗电。

二、原理及说明

1. Recent Task 本质区分两个概念

  1. 任务记录(Task Record) :系统维护的任务快照,包含应用包名、图标、页面缩略图,只是一条记录,不是进程。
  2. App 进程(Process):App 真正运行时,在 Linux 内核创建的进程,占用内存、CPU。

✅ 重启手机动作:杀死所有 App 进程 ;但不一定清除系统里保存的 Task 记录 (取决于 ROM 厂商配置、Android 版本)。

所以重启后列表还能看到图标 = 任务快照还在,进程已经不存在。

2. 点击和不点击的行为差异

  • 不点击:App 进程不存在,不会执行任何代码、不耗电、不联网。
  • 点击该图标:系统根据这个历史任务记录,重新拉起 App 进程,恢复上次页面。

3. 为什么重启后还保留任务列表(Android 原生 + 厂商 ROM 差异)

  • 原生 Android:一般重启会清空 Recent 任务;
  • 很多厂商定制 ROM(MTK、高通平台)做了优化:持久化最近任务列表,重启后恢复历史任务快照,提升用户体验,属于 ROM 定制行为,并非 App 驻留后台。

👉 重点:这个行为是系统 / ROM 层控制,不是 App 代码主动保活造成。App 本身没有能力在设备重启之后继续保持进程运行。

4. 举证方法

可以演示验证:

  1. 重启设备,打开最近任务,看到 App 图标;
  2. 使用 adb shell ps | grep [包名] 查看进程:找不到 App 进程;
  3. 点击最近任务里的 App 图标,再次执行 adb 命令,此时才能看到 App 进程启动。

三、清除方案

java 复制代码
Index: frameworks/base/services/core/java/com/android/server/wm/RecentTasks.java
===================================================================
--- frameworks/base/services/core/java/com/android/server/wm/RecentTasks.java	(revision 4780)
+++ frameworks/base/services/core/java/com/android/server/wm/RecentTasks.java	(revision 4781)
@@ -491,6 +491,10 @@
         List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
         mTasks.addAll(tasks);
         cleanupLocked(userId);
+
+        // for clear historical tasks as needed
+        clearBootLoadedRecentsIfNeededLocked(userId);
+
         mUsersWithRecentsLoaded.put(userId, true);
 
         // If we have tasks added before loading recents, we need to update persistent task IDs.
@@ -499,6 +503,53 @@
         }
     }
 
+    /**
+     * Only called when loading the history recent task from the disk for the first time after booting up;
+     * Clear the legacy tasks from the previous shutdown, and the newly generated tasks after this shutdown will not be affected;
+     * persist.system.recent.clear_on_boot - Control the main switch;
+     * persist.system.recent.clear_pkg - Specify the package name to be cleared; If left blank, clear all app history tasks.
+     */
+    private void clearBootLoadedRecentsIfNeededLocked(int userId) {
+        final boolean enableClear = SystemProperties.getBoolean("persist.system.recent.clear_on_boot", true);
+        if (!enableClear) {
+            Slog.i(TAG, "clearBootLoadedRecents: feature disabled by prop");
+            return;
+        }
+        final String targetClearPkg = SystemProperties.get("persist.system.recent.clear_pkg", "");
+        Slog.i(TAG, "clearBootLoadedRecentsIfNeededLocked userId=" + userId + ", targetPkg=[" + targetClearPkg + "]");
+
+        // Reverse traversal and deletion to avoid List index confusion
+        for (int i = mTasks.size() - 1; i >= 0; i--) {
+            final Task task = mTasks.get(i);
+            if (task.mUserId != userId) {
+                continue;
+            }
+            String taskPkg = null;
+            if (task.realActivity != null) {
+                taskPkg = task.realActivity.getPackageName();
+            } else if (task.getBaseIntent() != null && task.getBaseIntent().getComponent() != null) {
+                taskPkg = task.getBaseIntent().getComponent().getPackageName();
+            }
+
+            boolean needRemove;
+            if (TextUtils.isEmpty(targetClearPkg)) {
+                // Prop does not set package name: Clear all historical tasks recovered from disk this time
+                needRemove = true;
+            } else {
+                // Only clear the specified package name
+                needRemove = targetClearPkg.equals(taskPkg);
+            }
+
+            if (needRemove) {
+                Slog.i(TAG, "clearBootLoadedRecents remove boot-restored taskId=" + task.mTaskId + " pkg=" + taskPkg);
+                // 1.Remove the task from the recent list and notify WMS to delete the corresponding task snapshot thumbnail file
+                mSupervisor.removeTask(task, false /*killProcess*/, REMOVE_FROM_RECENTS, "clear-boot-history");
+                // 2.Notify persister not to persist this cleared task again
+                notifyTaskPersisterLocked(task, false);
+            }
+        }
+    }
+
     private void loadPersistedTaskIdsForUserLocked(int userId) {
         // An empty instead of a null set here means that no persistent taskIds were present
         // on file when we loaded them.
相关推荐
小铁-Android2 小时前
CompletableDeferred:Kotlin 协程中用于一次性挂起通信的工具
android·kotlin
恋猫de小郭2 小时前
Flutter 的文字为什么比 SwiftUI 更细?问题主要在 Skia 的 256 项查找表里
android·前端·flutter
ii_best2 小时前
安卓手机开发、iOS 手机开发都能用:按键精灵远程调试,设备在千里外也能改脚本
android·ios·智能手机·自动化·按键精灵
stevenzqzq5 小时前
Android Jetpack Compose 列表开发指南:为什么你不需要再为底部 Item 写额外间距
android·android jetpack
撩得Android一次心动13 小时前
Jetpack Compose 知识点整理2【个人用】
android·笔记·学习·kotlin·compose
是真的小外套14 小时前
2024年软考中级信息安全工程师|选择题考点+案例分析真题解析(含答案)
android·网络
用户20187928316716 小时前
一文讲透 Android Native Heap 监控原理:一间"只进不出"的仓库,和总部派来的侦探
android
YB137517 小时前
Jetpack Compose 动画animate*AsState
android
高晶17 小时前
Android 通讯录应用开发实战:从零搭建 SQLite 数据持久化完整项目
android·设计模式·前端框架