当前位置: 首页 > news >正文

Android killPackageProcessesLSP 源码分析

该方法用于终止指定包名/用户ID/应用ID下符合条件的应用进程,涉及多进程管理、资源冻结、进程清理及优先级更新等操作。核心流程分为进程筛选、资源冻结、进程终止与资源恢复三个阶段。

    /*** 从已排序的进程列表中,提取从指定起始索引 startIdx 开始的连续同一 UID 的进程子列表*/private static List<Pair<ProcessRecord, Boolean>> getUIDSublist(List<Pair<ProcessRecord, Boolean>> procs, int startIdx) {final int uid = procs.get(startIdx).first.uid;int endIdx = startIdx + 1;while (endIdx < procs.size() && procs.get(endIdx).first.uid == uid) ++endIdx;return procs.subList(startIdx, endIdx);}// 方法声明:需持有mService和mProcLock锁保证线程安全@GuardedBy({"mService", "mProcLock"})boolean killPackageProcessesLSP(String packageName, int appId,int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,boolean doit, boolean evenPersistent, boolean setRemoved, boolean uninstalling,int reasonCode, int subReason, String reason) {// 获取包管理服务接口final PackageManagerInternal pm = mService.getPackageManagerInternal();// 存储待终止的进程列表,Pair<进程记录, 是否允许重启>final ArrayList<Pair<ProcessRecord, Boolean>> procs = new ArrayList<>();// Remove all processes this package may have touched: all with the// same UID (except for the system or root user), and all whose name// matches the package name.// 移除此软件包可能涉及的所有进程:// 所有具有相同 UID 的进程(除了 system 或 root 用户),以及名称与软件包名称匹配的所有进程。final int NP = mProcessNames.getMap().size();// 此循环的目的就是想找到所有符合条件的进程,将它们添加到procsfor (int ip = 0; ip < NP; ip++) {SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);final int NA = apps.size();for (int ia = 0; ia < NA; ia++) {// 获取所有的进程的ProcessRecord,把符合条件的加入到procs中准备查杀ProcessRecord app = apps.valueAt(ia);// 如果进程标记为持久化且未显式允许终止,跳过处理if (app.isPersistent() && !evenPersistent) {// we don't kill persistent processescontinue;}// 已标记移除// 是否应终止此进程并将其从进程列表中删除。当程序包被强制停止或进程崩溃次数过多时,将设置此参数// mRemoved 标记为trueif (app.isRemoved()) {// 如果需执行终止操作if (doit) {// 检查是否允许重启boolean shouldAllowRestart = false;// 非卸载场景下,检查包依赖关系if (!uninstalling && packageName != null) {// 此包依赖于正在停止的给定包,当它未被冻结或卸载时,允许重新启动它。// This package has a dependency on the given package being stopped,// while it's not being frozen nor uninstalled, allow to restart it.shouldAllowRestart = !app.getPkgList().containsKey(packageName) //该进程不在正在停止的给定包中&& app.getPkgDeps() != null&& app.getPkgDeps().contains(packageName) //该进程依赖正在停止的给定包&& app.info != null&& !pm.isPackageFrozen(app.info.packageName, app.uid, //该进程所在包未被冻结app.userId);}//将进程需要从进程列表中删除,并且需要执行终止操作,那么就记录该进程信息以及该进程是否应该重启procs.add(new Pair<>(app, shouldAllowRestart));}// 如果不需要执行终止就跳过continue;}// 如果它不符合我们的 oom adj 要求,请跳过进程。// Skip process if it doesn't meet our oom adj requirement.if (app.mState.getSetAdj() < minOomAdj) {// 没理解,以后再说// 请注意,在被终止的进程中仍有可能有一个 oom adj 0 的进程,但这并不意味着误判。// 例如,绑定服务进程及其客户端活动进程都在后台,因此它们被收集以被终止。// 如果客户端活动先被终止,则可能会安排服务取消绑定并成为正在执行的服务 (oom adj 0)。// Note it is still possible to have a process with oom adj 0 in the killed// processes, but it does not mean misjudgment. E.g. a bound service process// and its client activity process are both in the background, so they are// collected to be killed. If the client activity is killed first, the service// may be scheduled to unbind and become an executing service (oom adj 0).continue;}// 如果mRemoved标记为false,且adj大于最小adj,那么就检查是否允许重启boolean shouldAllowRestart = false;// 如果未指定 package,则调用给定用户 ID 下的所有进程。// If no package is specified, we call all processes under the// given user id.if (packageName == null) {// 用户ID过滤(USER_ALL表示所有用户)不是指定用户ID,则跳过if (userId != UserHandle.USER_ALL && app.userId != userId) {continue;}// 应用ID过滤(-1表示不限制)不是指定appId,则跳过if (appId >= 0 && UserHandle.getAppId(app.uid) != appId) {continue;}// Package has been specified, we want to hit all processes// that match it.  We need to qualify this by the processes// that are running under the specified app and user ID.// package,我们希望命中与它匹配的所有进程。// 我们需要通过在指定应用程序和用户 ID 下运行的进程来限定此条件。// 有指定包名时的过滤逻辑} else {// 该进程是否依赖待终止的包final boolean isDep = app.getPkgDeps() != null&& app.getPkgDeps().contains(packageName);// 如果不依赖,且应用ID不匹配,则跳过if (!isDep && UserHandle.getAppId(app.uid) != appId) {continue;}// 该进程的userId与待终止的userId不匹配,则跳过if (userId != UserHandle.USER_ALL && app.userId != userId) {continue;}// 检查该进程的包名列表里面是否包含待终止的包名final boolean isInPkgList = app.getPkgList().containsKey(packageName);// 如果该进程的包名列表里面不包含待终止的包名,且该进程不依赖待终止的包,则跳过if (!isInPkgList && !isDep) {continue;}// 如果该进程的包名列表里面不包含待终止的包名,且该进程依赖待终止的包,且不是卸载场景,// 且该进程的包信息不为空,且该进程所在包未被冻结,则允许重启if (!isInPkgList && isDep && !uninstalling && app.info != null&& !pm.isPackageFrozen(app.info.packageName, app.uid, app.userId)) {// This package has a dependency on the given package being stopped,// while it's not being frozen nor uninstalled, allow to restart it.// 此包依赖于正在停止的给定包,当它未被冻结或卸载时,允许重新启动它shouldAllowRestart = true;}}// Process has passed all conditions, kill it!// 如果不需要终止,则返回trueif (!doit) {return true;}// 如果需要终止,需要被移除,则设置相关的flagif (setRemoved) {app.setRemoved(true);}// 记录待终止的进程procs.add(new Pair<>(app, shouldAllowRestart));// MIUI ADD: Performance_ProcessKillPolicyProcessListStub.get().notifyProcessDied(app);// END Performance_ProcessKillPolicy}}// 判断是否属于用户应用(应用ID在应用UID范围内)final boolean killingUserApp = appId >= Process.FIRST_APPLICATION_UID&& appId <= Process.LAST_APPLICATION_UID;// 用户应用按UID排序,保证同UID进程连续处理if (killingUserApp) {procs.sort((o1, o2) -> Integer.compare(o1.first.uid, o2.first.uid));}int idx = 0;while (idx < procs.size()) {// 获取当前UID对应的所有进程子列表final List<Pair<ProcessRecord, Boolean>> uidProcs = getUIDSublist(procs, idx);final int packageUID = uidProcs.get(0).first.uid;// Do not freeze for system apps or for dependencies of the targeted package, but// make sure to freeze the targeted package for all users if called with USER_ALL.// 不要冻结系统应用程序或目标包的依赖项,但请确保在使用 USER_ALL 调用时冻结所有用户的目标包。// 用户应用且当前UID匹配目标应用ID时冻结资源 系统应用或依赖进程不冻结 final boolean doFreeze = killingUserApp && UserHandle.getAppId(packageUID) == appId;// 冻结Binder通信和CPU调度(防止终止过程中产生新请求)if (doFreeze) freezeBinderAndPackageCgroup(uidProcs, packageUID);// 逐进程执行终止操作for (Pair<ProcessRecord, Boolean> proc : uidProcs) {removeProcessLocked(proc.first, callerWillRestart, allowRestart || proc.second,reasonCode, subReason, reason, !doFreeze /* async */);}// 终止关联的Zygote子进程(防止残留)killAppZygotesLocked(packageName, appId, userId, false /* force */);// 解冻资源限制if (doFreeze) unfreezePackageCgroup(packageUID);idx += uidProcs.size();}// 更新剩余进程的OOM优先级mService.updateOomAdjLocked(OOM_ADJ_REASON_PROCESS_END);// 返回是否终止了至少一个进程return procs.size() > 0;}

​​一、进程筛选条件​​

​​1. 进程类型过滤​​
​​持久化进程跳过​​:除非显式要求 (evenPersistent=true),否则不终止 isPersistent 标记的进程。
​​预移除进程处理​​:已标记为 isRemoved 的进程直接加入待终止列表,并根据依赖关系决定是否允许重启。
​​2. OOM优先级限制​​
仅终止 OOM_ADJ 值≥指定 minOomAdj 的低优先级进程(如后台进程)。
​​3. 包名与用户ID匹配规则​​
​​未指定包名​​:根据用户ID(userId)和应用ID(appId)过滤所有相关进程。
​​指定包名​​:
终止包名列表中包含该包名或依赖该包的进程(pkgDeps)。
若非卸载场景,依赖此包的进程允许重启(需包未被冻结)。

​​二、进程处理流程​​

  1. 列表排序优化​​
    若目标是用户应用(appId在应用UID范围内),按UID排序进程列表,确保同UID进程连续,便于批量处理。
  2. 资源冻结阶段​​
    冻结条件​​:仅针对普通用户应用且UID匹配应用ID的进程。
    ​​操作内容​​:
    Binder通信冻结​​:阻止进程接收新的Binder请求。
    CGroup限制​​:停止CPU调度,防止进程执行新任务。
    ​​目的​​:确保终止时不会因新请求导致残留问题。
  3. 进程终止与清理​​
    逐进程移除​​:调用 removeProcessLocked 终止进程,设置重启策略(允许依赖进程重启)。
    ​​关联Zygote清理​​:终止产卵该进程的Zygote子进程,避免僵尸进程。
  4. 资源解冻恢复​​
    同批次冻结的进程终止后,解除CGroup限制,恢复资源调度。

三、结束处理​​

  1. 系统状态更新​​
    调用 updateOomAdjLocked 更新剩余进程的OOM优先级,优化系统资源分配。
  2. ​​返回值​​
    返回 true 表示至少终止了一个进程(或无需实际终止时符合条件)。

四、​​关键设计逻辑​​

  1. ​​同UID批量处理​​
    按UID分组处理避免资源竞争,同时利用 subList 高效分割连续进程,减少遍历成本。
  2. 依赖进程特殊处理​​
    对依赖被终止包的进程,允许重启以维持系统稳定性,避免级联崩溃。
  3. 冻结-终止-解冻流程​​
    确保进程终止过程中无法接收新任务,提升终止可靠性,防止状态不一致。
  4. 系统进程保护机制​​
    跳过持久化进程及系统UID保护,避免影响系统核心功能。

五、术语解析​​

  • ​​OOM_ADJ​​:Android进程优先级指标,值越小优先级越高(如前台应用为0)。
  • ​​CGroup​​:Linux内核资源控制机制,限制进程组资源使用。
  • ​​Zygote​​:Android应用进程孵化器,清理残留子进程可释放资源。

http://www.mrgr.cn/news/100036.html

相关文章:

  • RabbitMQ 基础核心概念详解
  • Ubuntu22学习记录
  • 【数据可视化-22】脱发因素探索的可视化分析
  • TensorFlow深度学习实战(14)——循环神经网络详解
  • Ubuntu / WSL 安装pipx
  • 【Linux】基本指令(下)
  • pycharm2024.3.2项目解释器选择问题
  • docker 配置代理
  • 面试之消息队列
  • http协议、全站https
  • 2025第十六届蓝桥杯python B组满分题解(详细)
  • 每天学一个 Linux 命令(30):cut
  • 【华为】防火墙双击热备-之-主备模式-单外网线路-分享
  • 第9章 多模态大语言模型
  • 阿里云99机器总是宕机,实测还是磁盘性能差
  • 常用第三方库:cached_network_image图片加载优化
  • 自动化标注软件解析
  • 【农气项目】基于适宜度的产量预报
  • Linux 服务器运维常用命令大全
  • CMCC RAX3000M CH EC 算力版刷机(中国移动 RAX3000M 算力版)刷机备份数据