欢迎光临
我们一直在努力

Android 7 一键清理近期任务并保留白名单实现记录

需求背景

根据客户需求,需要提供一个一键结束所有应用并排除白名单的功能,效果类似 Android SystemUI 里「近期任务」界面的清理/结束任务按钮:
点击后清空近期任务,但对于指定的白名单应用,需要继续保持运行,不被杀掉。

在网上搜索后,并没有找到现成可用的实现方案,只能基于源码自行实现。

实现原理

既然 SystemUI 自身已经有「清理近期任务」的功能,就说明系统内部一定已经提供了相关接口,只是没有对外暴露。
通过调试 frameworks/base/packages/SystemUI 源码,可以看到:当按下近期任务按钮、执行清理操作时,会调用:

  • SystemServicesProxy#getRecentTasks(…):获取近期任务列表
  • 最终通过 ActivityManager.removeTask(int taskId) 来真正清理任务

思路就很明确了:

  • 复用 SystemServicesProxy#getRecentTasks(…) 拿到当前所有近期任务列表;
  • 根据白名单列表,将需要保留的应用从任务列表中移除;
  • 对剩余任务逐个调用 ActivityManager.removeTask(…),完成清理。
  • 为方便在系统中统一调用,这里通过自定义广播的方式来触发清理逻辑。


    新增广播 KillProcessesReceiver

    在 frameworks/base/packages/SystemUI/src/com/android/systemui/receiver/ 下新增文件:

    • KillProcessesReceiver.java

    示例代码如下(去掉了多余的高亮标签,保留核心逻辑):

    package com.android.systemui.receiver;

    import android.app.ActivityManager;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.ApplicationInfo;
    import android.content.pm.PackageManager;
    import android.os.UserHandle;
    import android.util.ArraySet;
    import android.util.Log;

    import com.android.systemui.recents.Recents;
    import com.android.systemui.recents.misc.SystemServicesProxy;

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    /**
    * 结束指定进程(清理近期任务,支持白名单)
    */

    public class KillProcessesReceiver extends BroadcastReceiver {

    public static final String ACTION = "con.yt.kill.processes";
    private static final String TAG = "recent";

    @Override
    public void onReceive(Context context, Intent intent) {
    if (!ACTION.equals(intent.getAction())) {
    return;
    }

    PackageManager pm = context.getPackageManager();
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

    try {
    SystemServicesProxy ssp = Recents.getSystemServices();
    int currentUserId = UserHandle.USER_CURRENT;

    // 获取近期任务列表
    List<ActivityManager.RecentTaskInfo> tasks =
    ssp.getRecentTasks(
    ActivityManager.getMaxRecentTasksStatic(),
    currentUserId,
    false,
    new ArraySet<>()
    );

    if (tasks == null || tasks.size() == 0) {
    Log.e(TAG, "tasks Empty");
    return;
    }

    // 读取白名单(包名或类名)
    ArrayList<String> whiteApp =
    intent.getStringArrayListExtra("whiteApp"); // 过滤白名单

    if (whiteApp != null && !whiteApp.isEmpty()) {
    Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
    while (iter.hasNext()) {
    ActivityManager.RecentTaskInfo t = iter.next();
    for (String s : whiteApp) {
    if (s.equals(t.realActivity.getClassName())
    || s.equals(t.realActivity.getPackageName())) {
    iter.remove();
    Log.i(TAG, "package is in white list, id=" + t.id
    + ", package=" + s);
    break;
    }
    }
    }
    }

    if (tasks.size() == 0) {
    Log.e(TAG, "tasks Empty");
    return;
    }

    // 逐个清理剩余任务
    Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
    while (iter.hasNext()) {
    ActivityManager.RecentTaskInfo t = iter.next();
    Log.i(TAG, "RecentTaskInfo stackId: " + t.stackId
    + ", baseActivity: " + t.baseActivity);

    // 注意:这里使用 persistentId
    am.removeTask(t.persistentId);
    }
    } catch (Exception e) {
    Log.e(TAG, "Failed to get recent tasks", e);
    }
    }
    }

    核心逻辑说明:

    • 通过 Recents.getSystemServices() 拿到 SystemServicesProxy;
    • 调用 getRecentTasks(…) 获取当前用户的所有近期任务;
    • 从 Intent 中取出白名单列表 whiteApp,按包名 / 类名过滤;
    • 对过滤后的任务使用 ActivityManager#removeTask(persistentId) 逐个移除。

    注册广播(SystemUI AndroidManifest.xml)

    文件位置:

    • frameworks/base/packages/SystemUI/AndroidManifest.xml

    在 application 节点中增加广播注册(示例):

    <receiver
    android:name=".receiver.KillProcessesReceiver"
    android:exported="false">

    <intent-filter>
    <action android:name="con.yt.kill.processes" />
    </intent-filter>
    </receiver>


    保护广播(系统 AndroidManifest.xml)

    文件位置:

    • frameworks/base/core/res/AndroidManifest.xml

    为防止普通应用随意发送该广播,需要将其声明为受保护广播:

    <protected-broadcast android:name="con.yt.kill.processes" />

    这样,只有具有系统权限的组件才能正常发送此广播。


    调用方式示例

    上层只需要构造相应的 Intent,并携带白名单列表即可。例如:

    public static final String ACTION_KILL_PROCESSES = "con.yt.kill.processes";

    @Override
    public void killBackgroundProcesses(Context context, ArrayList<String> whiteApp) {
    Intent intent = new Intent(ACTION_KILL_PROCESSES);
    intent.putStringArrayListExtra("whiteApp", whiteApp);
    context.sendBroadcast(intent);
    }

    其中:

    • whiteApp:白名单列表,可填入包名或具体 Activity 类名;
    • 不在白名单中的近期任务,会被统一通过 removeTask(…) 清理掉。

    至此,就实现了在 Android 7 平台上,一键清理近期任务且保留白名单应用的系统级方案。

    赞(0)
    未经允许不得转载:171主机测评 » Android 7 一键清理近期任务并保留白名单实现记录
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址