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

Android 系统源码级进程保活全方案:从进程创建到后台防护

引言

在 Android 开发中,进程保活是系统级应用(如 Launcher、安全软件、导航工具)的核心需求。随着 Android 版本迭代,前台服务、JobScheduler 等应用层保活手段逐渐失效,而 系统源码级修改 能直接干预进程管理核心逻辑,实现 “接近系统进程” 的保活强度。

本文基于 Android 10-13 源码(ActivityManagerService 核心模块),梳理 6 个关键进程管理方法 的修改方案,覆盖 “进程创建→死亡重启→优先级锁定→后台防护” 全链路,帮助开发者实现目标应用的稳定运行。

一、保活核心思路

Android 系统通过 进程优先级(OomAdj)进程状态(ProcState)清理策略 三大机制管控进程生命周期。源码级保活的核心是:

  1. 提升优先级:将目标应用标记为系统核心进程,OomAdj 强制设为最高(SYSTEM_ADJ = -16);
  2. 防止死亡:进程意外终止后立即强制重启;
  3. 突破限制:跳过后台启动限制、前台清理、后台杀死等系统策略;
  4. 稳定状态:锁定进程状态为前台,避免被系统判定为后台进程回收。

二、全链路源码修改方案

以下所有修改均基于 ActivityManagerService(AMS)及关联类,需在系统源码环境(如 AOSP)中编译生效。

2.1 进程创建:标记为系统核心进程(newProcessRecordLocked)

原方法功能

创建 ProcessRecord(进程元数据记录),初始化进程名、UID、调度组等基础属性,是进程生命周期的起点。

保活修改

在进程创建后,强制为目标应用设置系统级属性,避免后续被低优先级判定。

java

@GuardedBy("mService")
ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,boolean isolated, int isolatedUid, boolean isSdkSandbox, int sdkSandboxUid,String sdkSandboxClientAppPackage, HostingRecord hostingRecord) {// 1. 原有逻辑:初始化进程名、UID、隔离进程处理String proc = customProcess != null ? customProcess : info.processName;final int userId = UserHandle.getUserId(info.uid);int uid = info.uid;if (isSdkSandbox) uid = sdkSandboxUid;if (isolated) {// 隔离进程UID分配(原有逻辑,略)IsolatedUidRange uidRange = getOrCreateIsolatedUidRangeLocked(info, hostingRecord);if (uidRange == null) return null;uid = uidRange.allocateIsolatedUidLocked(userId);if (uid == -1) return null;// 隔离UID注册(原有逻辑,略)mAppExitInfoTracker.mIsolatedUidRecords.addIsolatedUid(uid, info.uid);mService.getPackageManagerInternal().addIsolatedUid(uid, info.uid);mService.mBatteryStatsService.addIsolatedUid(uid, info.uid);FrameworkStatsLog.write(FrameworkStatsLog.ISOLATED_UID_CHANGED, info.uid, uid,FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);}// 2. 创建ProcessRecord实例(原有逻辑)final ProcessRecord r = new ProcessRecord(mService, info, proc, uid,sdkSandboxClientAppPackage, hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName());final ProcessStateRecord state = r.mState;// 3. 原有系统进程配置(针对默认系统持久化进程)if (!isolated && !isSdkSandbox && userId == UserHandle.USER_SYSTEM&& (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK&& TextUtils.equals(proc, info.processName)) {state.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);state.setSetSchedGroup(ProcessList.SCHED_GROUP_DEFAULT);r.setPersistent(true);state.setMaxAdj(ProcessList.PERSISTENT_PROC_ADJ);}// ==============================================// 保活核心:目标应用强制标记为系统核心进程// ==============================================final String TARGET_PACKAGE = "com.your.target.package"; // 替换为目标包名if (TARGET_PACKAGE.equals(info.packageName)) {r.setPersistent(true); // 持久化保护,系统不主动回收r.mState.setMaxAdj(ProcessList.SYSTEM_ADJ); // 最高OomAdj(-16)r.mState.setCurAdj(ProcessList.SYSTEM_ADJ); // 当前Adj同步锁定r.importance = ProcessList.IMPORTANCE_FOREGROUND; // 前台重要性r.adjType = "SYSTEM_CORE"; // 标记为系统核心类型Slog.d(TAG, "KeepAlive: Process created as system core - " + info.packageName);}// ==============================================// 4. 隔离进程特殊配置(原有逻辑,略)if (isolated && isolatedUid != 0) {state.setMaxAdj(ProcessList.PERSISTENT_SERVICE_ADJ);}addProcessNameLocked(r);return r;
}

2.2 进程死亡:强制重启目标应用(handleAppDiedLocked)

原方法功能

进程终止后清理资源(活动、服务、Binder 连接),从系统列表移除进程,是进程生命周期的终点。

保活修改

在资源清理后,跳过 “移除记录” 步骤,直接重启目标应用,实现 “死亡即复活”。

java

@GuardedBy("this")
final void handleAppDiedLocked(ProcessRecord app, int pid,boolean restarting, boolean allowRestart, boolean fromBinderDied) {// 1. 原有逻辑:清理进程关联资源(活动、服务等)boolean kept = cleanUpApplicationRecordLocked(app, pid, restarting, allowRestart, -1,false /*replacingPid*/, fromBinderDied);// ==============================================// 保活核心:目标应用进程死亡后强制重启// ==============================================final String TARGET_PACKAGE = "com.your.target.package";if (app.info != null && TARGET_PACKAGE.equals(app.info.packageName)) {// 清理旧进程记录,避免冲突mProcessList.removeProcessLocked(app, true, "app_died_force_restart");// 调用系统方法重启进程,参数与默认启动逻辑一致startProcessLocked(app, "force_restart", // 重启原因app.processName, null, 0, 0, null, null, false, false, false);Slog.d(TAG, "KeepAlive: Process restarted - " + app.info.packageName);return; // 跳过后续移除逻辑,避免刚启动的进程被删除}// ==============================================// 2. 原有逻辑:非目标应用移除记录if (!kept && !restarting) {removeLruProcessLocked(app);if (pid > 0) ProcessList.remove(pid);}// 3. 原有逻辑:性能分析与窗口管理回调(略)mAppProfiler.onAppDiedLocked(app);mAtmInternal.handleAppDied(app.getWindowProcessController(), restarting, () -> {Slog.w(TAG, "Crash of app " + app.processName);Bundle info = new Bundle();info.putString("shortMsg", "Process crashed.");finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);});
}

2.3 后台启动:突破系统限制(getAppStartModeLOSP)

原方法功能

判断应用启动模式(正常 / 延迟 / 禁止),是 Android 8.0+ 后台启动限制的核心判断方法。

保活修改

直接为目标应用返回 “正常启动” 模式,跳过后台限制逻辑。

java

@GuardedBy(anyOf = {"this", "mProcLock"})
int getAppStartModeLOSP(int uid, String packageName, int packageTargetSdk,int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {// ==============================================// 保活核心:目标应用强制跳过后台启动限制// ==============================================final String TARGET_PACKAGE = "com.your.target.package";if (TARGET_PACKAGE.equals(packageName)) {Slog.d(TAG, "KeepAlive: Skip background restriction - " + packageName);return ActivityManager.APP_START_MODE_NORMAL; // 强制正常启动}// ==============================================// 1. 原有逻辑:顶层应用豁免(前台应用优先,略)if (mInternal.isPendingTopUid(uid)) {return ActivityManager.APP_START_MODE_NORMAL;}// 2. 原有逻辑:UID状态检查(空闲/待机判断,略)UidRecord uidRec = mProcessList.getUidRecordLOSP(uid);if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.isIdle()) {// 临时应用判断(原有逻辑,略)boolean ephemeral = (uidRec == null) ? getPackageManagerInternal().isPackageEphemeral(UserHandle.getUserId(uid), packageName): uidRec.isEphemeral();if (ephemeral) return ActivityManager.APP_START_MODE_DISABLED;// 后台启动限制判断(原有逻辑,略)if (disabledOnly) return ActivityManager.APP_START_MODE_NORMAL;final int startMode = (alwaysRestrict)? appRestrictedInBackgroundLOSP(uid, packageName, packageTargetSdk): appServicesRestrictedInBackgroundLOSP(uid, packageName, packageTargetSdk);// 前台调用者豁免(原有逻辑,略)if (startMode == ActivityManager.APP_START_MODE_DELAYED && callingPid >= 0) {ProcessRecord proc;synchronized (mPidsSelfLocked) {proc = mPidsSelfLocked.get(callingPid);}if (proc != null && !ActivityManager.isProcStateBackground(proc.mState.getCurProcState())) {return ActivityManager.APP_START_MODE_NORMAL;}}return startMode;}return ActivityManager.APP_START_MODE_NORMAL;
}

2.4 前台清理:避免被系统杀死(killForegroundAppsForUser)

原方法功能

在用户切换、资源紧张时,杀死指定用户的所有前台应用,释放内存。

保活修改

筛选待杀死进程时,排除目标应用,确保其前台状态不被清理。

java

public void killForegroundAppsForUser(@UserIdInt int userId) {final ArrayList<ProcessRecord> procs = new ArrayList<>();synchronized (mProcLock) {final int numOfProcs = mProcessList.getProcessNamesLOSP().getMap().size();for (int ip = 0; ip < numOfProcs; ip++) {final SparseArray<ProcessRecord> apps =mProcessList.getProcessNamesLOSP().getMap().valueAt(ip);final int NA = apps.size();for (int ia = 0; ia < NA; ia++) {final ProcessRecord app = apps.valueAt(ia);// 原有逻辑:跳过持久化进程(系统核心进程)if (app.isPersistent()) continue;// ==============================================// 保活核心:排除目标应用,不加入杀死列表// ==============================================final String TARGET_PACKAGE = "com.your.target.package";if (app.info != null && TARGET_PACKAGE.equals(app.info.packageName)) {Slog.d(TAG, "KeepAlive: Skip killing foreground app - " + app.info.packageName);continue; // 目标应用跳过,不加入杀死列表}// ==============================================// 原有逻辑:筛选“指定用户的前台应用”加入杀死列表if (app.isRemoved() || (app.userId == userId && app.mState.hasForegroundActivities())) {procs.add(app);}}}}// 原有逻辑:杀死筛选出的进程(略)final int numOfProcs = procs.size();if (numOfProcs > 0) {synchronized (ActivityManagerService.this) {for (int i = 0; i < numOfProcs; i++) {mProcessList.removeProcessLocked(procs.get(i), false, true,ApplicationExitInfo.REASON_OTHER,ApplicationExitInfo.SUBREASON_KILL_ALL_FG,"kill all fg");}}}
}

2.5 OomAdj:全链路锁定最高优先级(updateOomAdjInnerLSP)

原方法功能

计算所有进程的 OomAdj 值(优先级),处理进程依赖循环,是系统内存回收的核心依据。

保活修改

在 OomAdj 计算完成后,强制覆盖目标应用的优先级,确保不被系统降级。

java

@GuardedBy({"mService", "mProcLock"})
private void updateOomAdjInnerLSP(String oomAdjReason, final ProcessRecord topApp,ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles,boolean startProfiling) {// 1. 原有逻辑:初始化准备(跟踪开始、进程列表获取、UID状态重置,略)if (startProfiling) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);mService.mOomAdjProfiler.oomAdjStarted();}final long now = SystemClock.uptimeMillis();final boolean fullUpdate = processes == null;ArrayList<ProcessRecord> activeProcesses = fullUpdate ? mProcessList.getLruProcessesLOSP() : processes;// 2. 原有逻辑:计算原始OomAdj(含循环依赖处理,略)for (int i = activeProcesses.size() - 1; i >= 0; i--) {ProcessRecord app = activeProcesses.get(i);if (!app.isKilledByAm() && app.getThread() != null) {computeOomAdjLSP(app, ProcessList.UNKNOWN_ADJ, topApp, fullUpdate, now, false, true);}}// 循环依赖重试、缓存进程排序(原有逻辑,略)mProcessesInCycle.clear();// ==============================================// 保活核心:强制目标应用OomAdj为系统最高级// ==============================================final String TARGET_PACKAGE = "com.your.target.package";for (ProcessRecord app : activeProcesses) {if (app.info != null && TARGET_PACKAGE.equals(app.info.packageName) && !app.isKilledByAm() && app.getThread() != null) {ProcessStateRecord state = app.mState;state.setCurRawAdj(ProcessList.SYSTEM_ADJ); // 原始Adj强制为-16state.setMaxAdj(ProcessList.SYSTEM_ADJ); // 最大Adj锁定,防止后续降级state.setCurRawProcState(ProcessList.PROCESS_STATE_FOREGROUND); // 前台进程状态app.importance = ProcessList.IMPORTANCE_FOREGROUND; // 前台重要性app.adjType = "SYSTEM_CORE"; // 标记系统核心Slog.d(TAG_OOM_ADJ, "KeepAlive: OomAdj locked - " + app.info.packageName);}}// ==============================================// 3. 原有逻辑:应用OomAdj并修剪低优先级进程(略)mNumNonCachedProcs = 0;mNumCachedHiddenProcs = 0;boolean allChanged = updateAndTrimProcessLSP(now, SystemClock.elapsedRealtime(), now - mConstants.mMaxEmptyTimeMillis, uids, oomAdjReason);// 4. 原有逻辑:统计、日志更新(略)if (startProfiling) {mService.mOomAdjProfiler.oomAdjEnded();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}
}

2.6 后台清理:拦截 killBackgroundProcesses 调用

原方法功能

公开接口,允许有权限的应用杀死指定包名的后台进程(如任务管理器清理后台)。

保活修改

在执行杀死前,拦截目标应用的清理请求,直接退出方法。

java

@Override
public void killBackgroundProcesses(final String packageName, int userId) {// 1. 原有逻辑:权限校验(无权限则抛异常,略)if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)!= PackageManager.PERMISSION_GRANTED &&checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)!= PackageManager.PERMISSION_GRANTED) {String msg = "Permission Denial: killBackgroundProcesses() from pid="+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();Slog.w(TAG, msg);throw new SecurityException(msg);}// 2. 原有逻辑:调用者信息与杀死权限判断(略)final int callingUid = Binder.getCallingUid();final int callingPid = Binder.getCallingPid();ProcessRecord proc;synchronized (mPidsSelfLocked) {proc = mPidsSelfLocked.get(callingPid);}final boolean hasKillAllPermission = PERMISSION_GRANTED == checkPermission(android.Manifest.permission.FORCE_STOP_PACKAGES, callingPid, callingUid)|| UserHandle.isCore(callingUid)|| (proc != null && proc.info.isSystemApp());// 3. 原有逻辑:处理多用户ID(略)userId = mUserController.handleIncomingUser(callingPid, callingUid,userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);final int[] userIds = mUserController.expandUserId(userId);final long callingId = Binder.clearCallingIdentity();try {IPackageManager pm = AppGlobals.getPackageManager();// ==============================================// 保活核心:拦截目标应用的清理请求// ==============================================final String TARGET_PACKAGE = "com.your.target.package";if (TARGET_PACKAGE.equals(packageName)) {Slog.d(TAG, "KeepAlive: Skip killing background - " + packageName);return; // 直接返回,不执行后续杀死逻辑}// ==============================================// 4. 原有逻辑:遍历用户执行杀死(略)for (int targetUserId : userIds) {int appId = -1;try {appId = UserHandle.getAppId(pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, targetUserId));} catch (RemoteException e) {continue;}if (appId == -1 || (!hasKillAllPermission && appId != callingAppId)) {Slog.w(TAG, "Invalid packageName: " + packageName);return;}synchronized (this) {synchronized (mProcLock) {mProcessList.killPackageProcessesLSP(packageName, appId, targetUserId,ProcessList.SERVICE_ADJ,ApplicationExitInfo.REASON_USER_REQUESTED,ApplicationExitInfo.SUBREASON_KILL_BACKGROUND,"kill background");}}}} finally {Binder.restoreCallingIdentity(callingId);}
}

三、调试验证方法

修改后需验证保活效果,推荐以下调试命令:

  1. 查看 OomAdj 值adb shell dumpsys activity oom | grep "com.your.target.package"若输出 adj=-16,说明 OomAdj 锁定成功。

  2. 过滤保活日志adb logcat | grep "KeepAlive"进程创建、重启、OomAdj 锁定时会打印日志,确认逻辑触发。

  3. 模拟内存紧张adb shell am kill-all杀死所有后台进程,观察目标应用是否存活(通过 adb shell ps | grep 包名 验证)。

四、注意事项

  1. 系统版本兼容性:不同 Android 版本(如 10/11/12/13)的方法参数、常量定义可能差异,需根据实际源码调整(如 killPackageProcessesLSP 参数可能增减)。

  2. 资源风险:目标应用长期占用系统核心资源,可能导致其他应用频繁被回收,引发卡顿、耗电,需在 “保活需求” 与 “用户体验” 间平衡。

  3. 合规性:该方案仅适用于系统级应用,普通应用使用可能违反应用商店审核规则(如 Google Play 禁止源码级保活)。

  4. 编译环境:需基于 AOSP 源码编译,确保依赖的类(如 ProcessListUidRecord)可正常引用,避免编译错误。

五、总结

本文提供的 6 个核心方法修改,覆盖了 Android 进程生命周期的全链路:从创建时标记系统核心,到死亡后重启,再到 OomAdj 优先级锁定和后台清理拦截,形成 “双重防护”(高优先级 + 不被清理)。

该方案适合对稳定性要求极高的系统级应用(如车载系统、工业控制应用),但需注意资源占用与合规性问题。普通应用建议优先采用系统推荐的后台任务方案(如 WorkManager、前台服务),避免过度干预系统进程管理。

如需进一步优化,可添加 “重启频率限制”(避免短时间内反复重启)、“资源监控”(当系统内存过低时临时降低优先级),提升方案的鲁棒性。

http://www.dtcms.com/a/405767.html

相关文章:

  • 在hadoop中Job提交的流程
  • 基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
  • 01MemoryOS环境搭建 python3.10
  • 建设部网站职责划定html精美登录界面源码
  • 网站建设基本步骤顺序网站的整体风格
  • Leetcode 146. LRU 缓存 哈希表 + 双向链表
  • VideollaMA 3论文阅读
  • Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
  • 《红色脉络:一部PLMN在中国的演进史诗 (1G-6G)》 第11篇 | 核心网演进终局:从EPC到5GC——微服务与“云原生”
  • k8s中的NetworkPolicy
  • 【大语言模型】大模型后训练入门指南
  • 【初学】使用 node 编写 MCP Server
  • 阿里云云原生挑战官方用例SPL
  • 销售管理软件免费版什么叫seo优化
  • Apache POI 在 Linux 无图形界面环境下因字体配置问题导致Excel导出失败的解决方案
  • 咨询顾问进阶——146页PPT详解麦肯锡-企业管理整合咨询-组织设计方案【附全文阅读】
  • 力扣995. K 连续位的最小翻转次数
  • Resources$NotFoundException
  • pg下使用 TimescaleDB并创建1亿数据
  • 自动化脚本的操作逻辑与实现
  • UVa12418 Game of 999
  • 基于51单片机的音乐弹奏系统
  • 负载均衡式的在线OJ项目编写(二)
  • 美篇在哪个网站做的外链代发工具
  • Linux高级技巧之集群部署(七)
  • 外贸做那种网站wordpress获取图片的绝对地址
  • 【自然语言处理与大模型】RAFT(Retrieval Augmented Fine Tuning)方法
  • 湖南网站建设公司 找磐石网络一流跨境电商平台app排名
  • 动态IP使用中 报错407 怎么办???
  • 手机百度建设网站台州企业网站建设