代码改变世界

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

2025-09-29 18:27  tlnshuju  阅读(9)  评论(0)    收藏  举报

引言

在 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 procs = new ArrayList<>();
    synchronized (mProcLock) {
        final int numOfProcs = mProcessList.getProcessNamesLOSP().getMap().size();
        for (int ip = 0; ip < numOfProcs; ip++) {
            final SparseArray 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 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 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强制为-16
            state.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、前台服务),避免过度干预系统进程管理。

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