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.
相关推荐
木头左2 小时前
【架构设计】教育类 App 服务端化改造:AI 上移、题库分层与个人题库归属
android·架构设计·系统设计·后端开发·数据库设计
墨狂之逸才3 小时前
USB 的 HOST 和 DEVICE 到底有什么区别?ADB 调试应该选哪个?
android
奶油话梅糖3 小时前
苹果的内核跑上了安卓手机:2,631 Star 的 HakiOS 让 XNU 在 Adreno GPU 上画出 118 帧
android·macos·智能手机
恋猫de小郭4 小时前
Flutter THLC 的 WebView 滚动终于从 70 FPS 提升到 120 FPS
android·前端·flutter
好的佩奇15 小时前
Dart 之扩展类型
android·flutter·dart
alexhilton17 小时前
2027 Android 开发者路线图:学习、面试与 AI
android·kotlin·android jetpack
灿飞屋18 小时前
Kotlin与Java虚拟机三:控制流
android·java·开发语言·后端·python·kotlin·安卓
疯华整猫20 小时前
我用 Trae 把 Android 内存账重算了一遍
android·性能优化·源码
TimeFine21 小时前
AI 编程工作流的设计:从人工判断到 AI裁判
android·ai编程
阿杰m21 小时前
Android源码第四章:Android 系统启动——App 的第一行代码从哪来?
android