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

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应用进程孵化器,清理残留子进程可释放资源。

相关文章:

Android killPackageProcessesLSP 源码分析

该方法用于终止指定包名/用户ID/应用ID下符合条件的应用进程&#xff0c;涉及多进程管理、资源冻结、进程清理及优先级更新等操作。核心流程分为进程筛选、资源冻结、进程终止与资源恢复三个阶段。 /*** 从已排序的进程列表中&#xff0c;提取从指定起始索引 startIdx 开始的连…...

驱动开发硬核特训 · Day 16:字符设备驱动模型与实战注册流程

&#x1f3a5; 视频教程请关注 B 站&#xff1a;“嵌入式 Jerry” 一、为什么要学习字符设备驱动&#xff1f; 在 Linux 驱动开发中&#xff0c;字符设备&#xff08;Character Device&#xff09;驱动 是最基础也是最常见的一类驱动类型。很多设备&#xff08;如 LED、按键、…...

CDN加速http请求

一、CDN加速定义 CDN&#xff08;Content Delivery Network&#xff0c;内容分发网络&#xff09;是通过全球分布式节点服务器缓存网站内容&#xff0c;使用户就近获取数据的技术。其核心目标是缩短用户与内容之间的物理距离&#xff0c;解决网络拥塞、带宽不足等问题&#xff…...

SpringCloud微服务架构设计与实践 - 面试实战

SpringCloud微服务架构设计与实践 - 面试实战 第一轮提问 面试官&#xff1a;马架构&#xff0c;请问在SpringCloud微服务架构中&#xff0c;如何实现服务注册与发现&#xff1f; 马架构&#xff1a;在SpringCloud中&#xff0c;Eureka是常用的服务注册与发现组件。服务提供…...

关于位运算的一些小记

目录 1.判断一个整数是不是2的幂 2.判断一个整数是不是3的幂 3.大于n的最小的2次幂的数 4.交换两个数 5.找到1-n中缺失的数字 6.判断数组中2个出现次数为奇数的数 6.求给定范围内所有数字&的结果 7. 求出现次数少于m的数 1.判断一个整数是不是2的幂 提取出二进制里最…...

Virtuoso ADE采用Spectre仿真中出现MOS管最小长宽比满足要求依然报错的情况解决方法

在ADE仿真中错误问题如下&#xff1a; ERROR (CMI-2440): "xxx.scs" 46338: I2.M1: The length, width, or area of the instance does not fit the given lmax-lmin, wmax-wmin, or areamax-areamin range for any model in the I2.M3.nch_hvt group. The channel w…...

图论---朴素Prim(稠密图)

O( n ^2 ) 题目通常会提示数据范围&#xff1a; 若 V ≤ 500&#xff0c;两种方法均可&#xff08;朴素Prim更稳&#xff09;。 若 V ≤ 1e5&#xff0c;必须用优先队列Prim vector 存图。 // 最小生成树 —朴素Prim #include<cstring> #include<iostream> #i…...

Java知识日常巩固(四)

什么是 Java 中的自动装箱和拆箱? 在Java中,自动装箱(Autoboxing)和拆箱(Unboxing)是Java 5引入的特性,它们允许基本数据类型(如 int、double 等)和它们对应的包装类(如 Integer、Double 等)之间进行自动转换。 自动装箱是指将基本数据类型的值自动…...

go.mod介绍

在 Go 项目中&#xff0c;.mod 文件&#xff08;全称 go.mod&#xff09;是 Go 语言模块&#xff08;Module&#xff09;系统的核心配置文件&#xff0c;用于定义和管理项目的依赖关系、模块名称及兼容性规则。以下是其核心作用与结构的详细说明&#xff1a; 一、go.mod 文件的…...

大模型应用开发之LLM入门

一、大模型概述 1、大模型概念 LLM是指用有大量参数的大型预训练语言模型&#xff0c;在解决各种自然语言处理任务方面表现出强大的能力&#xff0c;甚至可以展现出一些小规模语言模型所不具备的特殊能力 2、语言模型language model 语言建模旨在对词序列的生成概率进行建模…...

算法之回溯法

回溯法 回溯法定义与概念核心思想回溯法的一般框架伪代码表示C语言实现框架 回溯法的优化技巧剪枝策略实现剪枝的C语言示例记忆化搜索 案例分析N皇后问题子集和问题全排列问题寻路问题 回溯法的可视化理解决策树状态空间树回溯过程 回溯法与其他算法的比较回溯法与动态规划的区…...

武汉昊衡科技OLI光纤微裂纹检测仪:高密度光器件的精准守护者

随着AI技术应用越来越广&#xff0c;算力需求激增&#xff0c;光通信系统正加速向小型化、高密度、多通道方向演进。硅光芯片、高速光模块等核心器件内部的光纤通道数量成倍增加&#xff0c;波导结构愈发精细&#xff0c;传统检测手段因分辨率不足、效率低下&#xff0c;难以精…...

SQL 函数进行左边自动补位fnPadLeft和FORMAT

目录 1.问题 2.解决 方式1 方式2 3.结果 1.问题 例如在SQL存储过程中&#xff0c;将1 或10 或 100 长度不足的时候&#xff0c;自动补足长度。 例如 1 → 001 10→ 010 100→100 2.解决 方式1 SELECT FORMAT (1, 000) AS FormattedNum; SELECT FORMAT(12, 000) AS Form…...

Tailwind CSS实战:快速构建定制化UI的新思路

引言 在当今快节奏的前端开发环境中&#xff0c;开发者不断寻找能够提高效率并保持灵活性的工具。Tailwind CSS作为一个功能型优先的CSS框架&#xff0c;正在改变开发者构建用户界面的方式。与Bootstrap和Material UI等传统组件库不同&#xff0c;Tailwind不提供预设组件&…...

【数据可视化-25】时尚零售销售数据集的机器学习可视化分析

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个…...

UML 活动图深度解析:以在线购物系统为例

目录 一、UML 活动图的基本构成要素 二、题目原型 三、在线购物系统用户购物活动图详细剖析 &#xff08;一&#xff09;概述 &#xff08;二&#xff09;节点分析 三、注意事项 四、活动图绘画 五、UML 活动图在软件开发中的关键价值 六、总结 在软件开发与系统设计领…...

利用车联网中的 V2V 通信技术传播公平的紧急信息

与移动自组织网络 (MANET) 相比,车载自组织网络 (VANET) 的节点移动速度更快。网络连接的节点可以在自身内部或其他基础设施之间交换安全或非安全消息,例如车对车 (V2V) 或车对万物 (V2X)。在车载通信中,紧急消息对于安全至关重要,必须分发给所有节点,以提醒它们注意潜在问…...

文件的读取操作

#import time # 导入time 库 # 打开文件 fileopen("E:\Dasktape/python_test.txt","r",encoding"UTF-8")# 读取文件 print(f"读取文件的所有内容内容:{file.read()}\n") #\n是换行字符 print(f"读取10个字节的文件内容:{file.re…...

数学基础 -- 欧拉恒等式的魅力:让复数旋转起来!

公式推导&#xff1a; e i π − 1 e^{i\pi} -1 eiπ−1 被誉为数学中最美的公式之一&#xff0c;它连接了五个数学中最重要的常数&#xff1a; e i π 1 0 (欧拉恒等式) e^{i\pi} 1 0 \tag{欧拉恒等式} eiπ10(欧拉恒等式) 这不仅是巧合&#xff0c;而是复数与三角函数…...

【android bluetooth 协议分析 06】【l2cap详解 6】【L2CA_Register函数解析】

L2CA_Register() 函数的实现&#xff0c;它的作用是&#xff1a; 注册一个 L2CAP 服务&#xff08;基于 PSM&#xff09;并设置回调函数、MTU、安全等级、传输模式等信息&#xff0c;供 L2CAP 层用于处理连接、配置、数据、断开等事件。 1. L2CA_Register2/L2CA_Register 参数…...

【MFC】 VS2022打开低版本的MFC,双击.rc文件,DIalog加载失败,页面弹窗fatal error RC***:cannot open*****

打开以前的MFC示例报错&#xff0c;打开VS2019的实例以及更早VS版本的实例都一样,打不开&#xff0c;还报错&#xff1b; 错误 MSB8041 此项目需要 MFC 库。从 Visual Studio 安装程序(单个组件选项卡)为正在使用的任何工具集和体系结构安装它们。 GxCameraEvents_VS2015 C:\P…...

Centos9 安装 nginx 及配置

1. 安装nginx 安装依赖软件&#xff0c;安装之前可以看一下是否已经安装过以下软件&#xff0c;dnf list installed | grep zlib dnf install gcc-c dnf install zlib dnf install pcre pcre-devel dnf install openssl openssl-devel下载nginx&#xff0c;这里是下载到opt文…...

使用Handsontable实现动态表格和下载表格

1.效果 2.实现代码 首先要加载Handsontable&#xff0c;在示例中我是cdn的方式引入的&#xff0c;vue的话需要下载插件 let hot null;var exportPlugin null;function showHandsontable(param) {const container document.getElementById("hot-container");// 如果…...

Action:Update your application‘s configuration

在使用Maven项目时&#xff0c;有一个报错信息是&#xff1a;Update your applications configuration 这类问题&#xff0c;就是我们的application.yml文件 或者 application.properties文件 内容哪里写错了 最有可能就是对齐方式有问题...

【计算机网络】IP地址

IPv4 五类地址 1.0.0.0 ~ 126.255.255.255A类子网8位&#xff0c;主机24位128.0.0.0 ~ 191.255.255.255B类子网16位&#xff0c;主机16位192.0.0.0 ~ 223.255.255.255C类子网24位&#xff0c;主机8位224.0.0.0 ~ 239.255.255.255D类不分网络地址和主机地址&#xff0c;作为组播…...

Rundeck 介绍及安装:自动化调度与执行工具

Rundeck介绍 概述&#xff1a;Rundeck 是什么&#xff1f; Rundeck 是一款开源的自动化调度和任务执行工具&#xff0c;专为运维场景设计&#xff0c;帮助工程师通过统一的平台管理和执行跨系统、跨节点的任务。它由 PagerDuty 维护&#xff08;2016 年收购&#xff09;&#…...

vue element使用el-table时,切换tab,table表格列项发生错位问题

展示问题 问题描述&#xff1a;使用el-table的fixed"right"属性后&#xff0c;如果切换tab时&#xff0c;回出现最后一列错误的问题 官网提供解决方法&#xff1a;doLayout 需要注意的事项&#xff1a;我这里是通过组件使用的table组件&#xff0c;涉及多层组件封装…...

第十二章 Python语言-大数据分析PySpark(终)

目录 一. PySpark前言介绍 二.基础准备 三.数据输入 四.数据计算 1.数据计算-map方法 2.数据计算-flatMap算子 3.数据计算-reduceByKey方法 4.数据计算-filter方法 5.数据计算-distinct方法 6.数据计算-sortBy方法 五.数据输出 1.输出Python对象 &#xff08;1&am…...

【RedisLockRegistry】分布式锁

RedisLockRegistry分布式锁 介绍 RedisLockRegistry‌是Spring框架提供的一种分布式锁机制&#xff0c;它基于Redis来实现对共享资源的保护&#xff0c;防止多个进程同时对同一资源进行修改&#xff0c;从而避免数据不一致或其他问题‌ 基本原理 RedisLockRegistry通过Redi…...

leetcode-排序

排序 面试题 01.01. 判定字符是否唯一 题目 实现一个算法&#xff0c;确定一个字符串 s 的所有字符是否全都不同。 示例 1&#xff1a; 输入: s "leetcode" 输出: false 示例 2&#xff1a; 输入: s "abc" 输出: true限制&#xff1a; 0 < len(s) &…...