Android oom_adj 详细解读

news2024/11/25 2:39:18

源码基于:Android R

 

 

0. 前言

在博文《oom_adj 内存水位算法剖析》一文中详细的分析了lmkd 中针对 oom_adj 内存水位的计算、使用方法,在博文《oom_adj 更新原理(1)》《oom_adj 更新原理(2)》中对Android 系统中 oom_adj 的更新原理进行了详细的剖析。通过这几篇博文我们对 oom_adj 有了更深地了解。

本文在之前博文的基础上,剖析代码细节,对每个 oom_adj 的值进行详细地解读。

 

1. adj 等级

首先如之前几篇博文,还是先把 oom_adj 的值列举出来,下文将对每个 oom_adj 的值进行单独地解读。 

frameworks/base/services/core/java/com/android/server/am/ProcessList.java

ADJ 等级取值说明
UNKNOWN_ADJ1001用于特定地方,一般指将要cache进程,不知道确切值
CACHED_APP_MAX_ADJ999不可见进程的最大值,进程可以无任何干扰的被杀
CACHED_APP_LMK_FIRST_ADJ950oom_adj 等级第一个允许被杀的level,不能等于CACHED_APP_MAX_ADJ
CACHED_APP_MIN_ADJ900不可见进程的最小值
SERVICE_B_ADJ800B List中的Service(较老的、使用可能性更小)
PREVIOUS_APP_ADJ700上一个App的进程(往往通过按返回键)
HOME_APP_ADJ600Home进程
SERVICE_ADJ500app service 进程,杀掉它一般不会有太大的影响
HEAVY_WEIGHT_APP_ADJ400后台的重量级进程,system/rootdir/init.rc文件中startup
BACKUP_APP_ADJ300备份进程,杀掉它不完全致命,但不好
PERCEPTIBLE_LOW_APP_ADJ250被用户或系统绑定的进程,比service 要重要,但是如果被杀掉,不会立即影响客户的感官
PERCEPTIBLE_APP_ADJ200可感知的进程,如后台music 播放
VISIBLE_APP_ADJ100可视进程
PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ50recently TOP 进程
FOREGROUND_APP_ADJ0前台进程
PERSISTENT_SERVICE_ADJ-700关联系统的进程或一个常驻进程
PERSISTENT_PROC_ADJ-800

系统常驻进程,例如telephony

绝对不想杀,但不完全致命

SYSTEM_ADJ-900系统进程
NATIVE_ADJ-1000native 进程,不归系统管理,所以没有oom_adj 适配

2. ADJ < 0

在 adj 的分级中 FOREGROUND_APP_ADJ 的值为0,拥有该 adj 的进程为前台进程。系统认为小于 0 的进程为系统中比较重要的进程。如下:

  • NATIVE_ADJ(-1000):是由 init 进程 fork 出来的 native 进程,并不受 system 管控;
  • SYSTEM_ADJ(-900):指 system_server 进程;
  • PERSISTENT_PROC_ADJ(-800):是指在 AndroidManifest.xml 中声明 android:persistent 为 true的系统 (即带有 FLAG_SYSTEM标记) 进程。persistent 进程一般情况下并不会被杀,即便被杀或者发生 crash 系统也会立即重新拉起该进程;
  • PERSISTENT_SERVICE_ADJ(-700):是由函数 startIsolatedProcess() 方式启动的进程,或者是由 system_server 或者 persistent 进程所绑定的 (并且带有 BIND_ABOVE_CLIENT 或 BIND_IMPORTANT) 服务进程;

 

2.1 SYSTEM_ADJ(-900)

SYSTEM_ADJ 仅指 system_server 进程。在 SystemServer.startBootstrapServices() 过程中会调用 AMS.setSystemProcess(),而该函数中会将system_server 的maxAdj 设置为 SYSTEM_ADJ

frameworks/base/services/core/java/com/android/server/am/AMS.java

    public void setSystemProcess() {
        try {
            ...

            synchronized (this) {
                ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
                        false,
                        0,
                        new HostingRecord("system"));
                app.setPersistent(true);
                app.pid = app.mPidForCompact = MY_PID;
                app.getWindowProcessController().setPid(MY_PID);
                app.maxAdj = ProcessList.SYSTEM_ADJ; //----这里设定system_server 的 maxAdj
                app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
                addPidLocked(app);
                mProcessList.updateLruProcessLocked(app, false, null);
                updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
            }
        }
        ...
    }

在调用 updateOomAdjLocked() 函数的时候传入的是一个参数,从博文《oom_adj 更新原理(2)》中的 computeOomAdjLocked() 得知:

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
    ...
    app.curAdj = app.maxAdj;
    ...
}

最终的system_server 进程的 adj 被设置为 -900,从 dumpsys meminfo 中也能看到:

    153,028K: System
        153,028K: system (pid 1143 / adj -900)

2.2 PERSISTENT_PROC_ADJ(-800)

PERSISTENT_PROC_ADJ 的进程需要在 AndroidManifest.xml 中声明 android:persistent 属性为 true 的系统 (带有 FLAG_SYSTEM) 进程,又称 persistent 进程。对于 persistent 进程常规情况下是不会被 kill 的,一旦被kill 或者发生 crash,系统也会立即重启拉起该进程。

设定位置:

  • ProcessList.newProcessRecordLocked();
  • AMS.addAppLocked();

在新的application 启动过程中都会调用 newProcessRecordLocked(),甚至包括 system_server 进程,例如 上一节 提到的 setSystemProcess() 函数:

frameworks/base/services/core/java/com/android/server/am/AMS.java

    public void setSystemProcess() {
        try {
            ...

            synchronized (this) {
                ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
                        false,
                        0,
                        new HostingRecord("system"));
                app.setPersistent(true);
                app.pid = app.mPidForCompact = MY_PID;
                app.getWindowProcessController().setPid(MY_PID);
                app.maxAdj = ProcessList.SYSTEM_ADJ; //----这里设定system_server 的 maxAdj
                app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
                addPidLocked(app);
                mProcessList.updateLruProcessLocked(app, false, null);
                updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
            }
        }
        ...
    }

代码中第一句话就是通过 newProcessRecordLocked() 函数创建 ProcessRecord 对象。

 来看下该函数:

frameworks/base/services/core/java/com/android/server/am/ProcessList.java

    final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
            boolean isolated, int isolatedUid, HostingRecord hostingRecord) {
        String proc = customProcess != null ? customProcess : info.processName;
        final int userId = UserHandle.getUserId(info.uid);
        int uid = info.uid;
        if (isolated) {
            ...
        }
        final ProcessRecord r = new ProcessRecord(mService, info, proc, uid);

        if (!mService.mBooted && !mService.mBooting
                && userId == UserHandle.USER_SYSTEM
                && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
            // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
            r.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
            r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
            r.setPersistent(true);
            r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
        }
        if (isolated && isolatedUid != 0) {
            // Special case for startIsolatedProcess (internal only) - assume the process
            // is required by the system server to prevent it being killed.
            r.maxAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
        }
        addProcessNameLocked(r);
        return r;
    }

通过函数得知,只有在 system_server 启动时会被置为 PERSISTENT_PROC_ADJ,但在 setSystemProcess() 最后会将system_server 的 maxAdj 修改为 SYSTEM_ADJ。

如果该进程是 isolated,maxAdj 会被设为 PERSISTENT_SERVICE_ADJ,详细可以查看第 2.3 节。

来看下另一个函数 addAppLocked():

frameworks/base/services/core/java/com/android/server/am/AMS.java

    final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
            boolean disableHiddenApiChecks, boolean disableTestApiChecks,
            boolean mountExtStorageFull, String abiOverride, int zygotePolicyFlags) {
        ProcessRecord app;
        if (!isolated) {
            app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
                    info.uid, true);
        } else {
            app = null;
        }

        if (app == null) {
            app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0,
                    new HostingRecord("added application",
                            customProcess != null ? customProcess : info.processName));
            mProcessList.updateLruProcessLocked(app, false, null);
            updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
        }

        ...

        if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
            app.setPersistent(true);
            app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
        }
        if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
            mPersistentStartingProcesses.add(app);
            mProcessList.startProcessLocked(app, new HostingRecord("added application",
                    customProcess != null ? customProcess : app.processName),
                    zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks,
                    mountExtStorageFull, abiOverride);
        }

        return app;
    }

当 application 的 flag 置 FLAG_SYSTEM | FLAG_PERSISTENT 时,maxAdj 的值才被设为 PERSISENT_PROC_ADJ。

在SystemServer 启动 startOtherServices() 中会调用 AMS.systemReady() 进行boot 的 完成阶段,此处会调用 startPersistentApps():

frameworks/base/services/core/java/com/android/server/am/AMS.java

    void startPersistentApps(int matchFlags) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;

        synchronized (this) {
            try {
                final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
                for (ApplicationInfo app : apps) {
                    if (!"android".equals(app.packageName)) {
                        addAppLocked(app, null, false, null /* ABI override */,
                                ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
                    }
                }
            } catch (RemoteException ex) {
            }
        }
    }

这里加载系统的 persistent 进程,调用 addAppLocked() 函数。

 

2.3 PERSISTENT_SERVICE_ADJ(-700)

PERSISTENT_SERVICE_ADJ 的进程是 startIsolatedProcess() 方式启动的进程,或者是由 system_server 或 persistent 进程所绑定的服务进程。

我们在上一文 newProcessRecordLocked() 中已经提到过了,当进程为 isolated 时,maxAdj 会被设置为 PERSISTENT_SERVICE_ADJ,而newProcessRecordLocked() 触发的流程如下:

AMS.startIsolatedProcess() -> ProcessList.startProcessLocked() ->newProcessRecordLocked()

另外一种就是在 updateOomAdjLocked() 中会调用 computeOomAdjLocked():

  frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {
        ...

        int capabilityFromFGS = 0; // capability from foreground service.
        for (int is = app.numberOfRunningServices() - 1;
                is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                        || procState > PROCESS_STATE_TOP);
                is--) {
            ServiceRecord s = app.getRunningServiceAt(is);
            ...
            
            ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
            for (int conni = serviceConnections.size() - 1;
                    conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                            || procState > PROCESS_STATE_TOP);
                    conni--) {
                ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
                for (int i = 0;
                        i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
                                || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                                || procState > PROCESS_STATE_TOP);
                        i++) {
                    ...

                    int clientAdj = client.getCurRawAdj();
                    int clientProcState = client.getCurRawProcState();

                    if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
                        ...
                        if (adj > clientAdj) {
                            if (app.hasShownUi && !app.getCachedIsHomeProcess()
                                    && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
                                    adjType = "cch-bound-ui-services";
                                }
                            } else {
                                int newAdj;
                                if ((cr.flags&(Context.BIND_ABOVE_CLIENT
                                        |Context.BIND_IMPORTANT)) != 0) {
                                    if (clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
                                        newAdj = clientAdj;
                                    } else {
                                        newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
                                       ...
                                    }
                                }

当前进程绑定有client,且当前进程 adj 优先级还没有 client 优先级高时,确定是否设置了 BIND_ABOVE_CLIENT 或 BIND_IMPORTANT 的flags

3. FOREGROUND_APP_ADJ(0)

场景1:满足以下任一条件的进程都属于FOREGROUND_APP_ADJ(0) 优先级:

  • 正处于resumed 状态的Activity
  • 正执行一个生命周期回调的Service(比如执行onCreate, onStartCommand, onDestroy等)
  • 正执行onReceive() 的BroadcastReceiver
  • 通过startInstrumentation() 启动的进程

 详细代码可以查看博文《oom_adj 更新原理(2)》中的 computeOomAdjLocked() :

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {
        ...

        boolean foregroundActivities = false;
        if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
            // The last app on the list is the foreground app.
            adj = ProcessList.FOREGROUND_APP_ADJ;
            ...
        } else if (app.runningRemoteAnimation) {
            adj = ProcessList.VISIBLE_APP_ADJ;
            ...
        } else if (app.getActiveInstrumentation() != null) {
            adj = ProcessList.FOREGROUND_APP_ADJ;
            ...
        } else if (app.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {
            adj = ProcessList.FOREGROUND_APP_ADJ;
            ...
        } else if (app.executingServices.size() > 0) {
            adj = ProcessList.FOREGROUND_APP_ADJ;
            ...
        } else if (app == topApp) {
            adj = ProcessList.FOREGROUND_APP_ADJ;
            ...
        } else {
            procState = PROCESS_STATE_CACHED_EMPTY;
            ...
        }

场景2: 当客户端进程activity里面调用bindService()方法时flags带有BIND_ADJUST_WITH_ACTIVITY参数,并且该activity处于可见状态,则当前服务进程也属于前台进程,源码如下:

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {

            ...

                    final ActivityServiceConnectionsHolder a = cr.activity;
                    if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
                        if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ
                                && a.isActivityVisible()) {
                            adj = ProcessList.FOREGROUND_APP_ADJ;
                            app.setCurRawAdj(adj);

场景3: 对于provider进程,还有以下两个条件能成为前台进程:

  • 当Provider的客户端进程ADJ<=FOREGROUND_APP_ADJ时,则Provider进程ADJ等于FOREGROUND_APP_ADJ
  • 当Provider有外部(非框架)进程依赖,也就是调用了getContentProviderExternal()方法,则ADJ至少等于FOREGROUND_APP_ADJ

 

4. VISIBLE_APP_ADJ(100)

可见进程:当ActivityRecord的visible=true,也就是Activity可见的进程。

从Android P开始,进一步细化ADJ级别,增加了 VISIBLE_APP_LAYER_MAX(99),是指VISIBLE_APP_ADJ(100) 跟 PERCEPTIBLE_APP_ADJ(200) 之间有99个槽,则可见级别ADJ的取值范围为[100,199]。 算法会根据其所在task的mLayerRank来调整其ADJ,100加上mLayerRank就等于目标ADJ,layer越大,则ADJ越小。

关于TaskRecord的mLayerRank的计算方式是在updateOomAdjLocked()过程调用ASS的rankTaskLayersIfNeeded() 方法。

当TaskRecord顶部的ActivityRecord为空或者结束或者不可见时,则设置该TaskRecord的mLayerRank等于-1; 每个ActivityDisplay的baseLayer都是从0开始,从最上面的TaskRecord开始,第一个ADJ=100,从上至下依次加1,直到199为上限。

5. PERCEPTIBLE_APP_ADJ(200)

可感知进程:当该进程存在不可见的Activity,但Activity正处于PAUSING、PAUSED、STOPPING状态,则为PERCEPTIBLE_APP_ADJ。

在 computeOomAdjLocked() 函数中对于可感知进程也有专门的计算:

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {

        ...

        /********* 场景 1 **********/
        // Examine all activities if not already foreground.
        if (!foregroundActivities && app.getCachedHasActivities()) {
            app.computeOomAdjFromActivitiesIfNecessary(mTmpComputeOomAdjWindowCallback,
                    adj, foregroundActivities, procState, schedGroup, appUid, logUid,
                    PROCESS_STATE_CUR_TOP);

            adj = app.mCachedAdj;
            ...
        }

        ...

        /********* 场景 2 **********/
        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > PROCESS_STATE_FOREGROUND_SERVICE) {
            if (app.hasForegroundServices()) {
                // The user is aware of this app, so make it visible.
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = PROCESS_STATE_FOREGROUND_SERVICE;
                app.adjType = "fg-service";
                app.setCached(false);
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
            } else if (app.hasOverlayUi()) {
                // The process is display an overlay UI.
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = PROCESS_STATE_IMPORTANT_FOREGROUND;
                app.setCached(false);
                app.adjType = "has-overlay-ui";
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
            }
        }

        ...

        /********* 场景 3 **********/
        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                || procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
            if (app.forcingToImportant != null) {
                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
                app.setCached(false);
                app.adjType = "force-imp";
                app.adjSource = app.forcingToImportant;
                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
            }
        }

场景1:如果不是前台进程,且存在cache activities,则需要继续确定adj

调用 computeOomAdjFromActivitiesIfNecessary(),这里是在计算 oom_adj 时,传入一个 callback,通过 window 来确认activity 处于什么状态 visible 还是PAUSING、STOPPING 或其他状态,并根据状态调用 callback 对应的回调函数。

  • visible:adj 如果大于 VISIBLE_APP_ADJ,则会被拉回 VISIBLE_APP_ADJ;
  • PAUSING:adj 如果大于 PERCEPTIBLE_APP_ADJ,则会被拉回 PERCEPTIBLE_APP_ADJ;
  • STOPPING:adj 如果大于 PERCEPTIBLE_APP_ADJ,则会被拉回 PERCEPTIBLE_APP_ADJ;

场景2:进程拥有前台services 或进程用有 overlay UI

前提调价是进程重要性已经低于可感知级别,或者进程状态级别高于带前台service

拥有前台services,是执行 startForegroundService() 函数了;

hasOverlayUi() 为true,表示非activity 的UI 位于屏幕最顶层,例如显示类型  TYPE_APPLICATION_OVERLAY 的窗口。

场景3:进程forcingToImportant 非空

该值非空,表示执行了 setProcessImportant() 函数,例如 Toast 弹出过程;

6. BACKUP_APP_ADJ(300)

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {

        ...

        final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
        if (backupTarget != null && app == backupTarget.app) {
            // If possible we want to avoid killing apps while they're being backed up
            if (adj > ProcessList.BACKUP_APP_ADJ) {
                if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
                adj = ProcessList.BACKUP_APP_ADJ;
                if (procState > PROCESS_STATE_TRANSIENT_BACKGROUND) {
                    procState = PROCESS_STATE_TRANSIENT_BACKGROUND;
                }
                app.adjType = "backup";
                app.setCached(false);
            }
            if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
                procState = ActivityManager.PROCESS_STATE_BACKUP;
                app.adjType = "backup";
            }
        }

前提条件是 backupTarget 不为空:

  • 执行 bindBackupAgent()过程,设置mBackupTarget值;
  • 执行clearPendingBackup()或unbindBackupAgent()过程,置空mBackupTarget值;

7. HEAVY_WEIGHT_APP_ADJ(400)

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {

        ...

        //重量级后台进程,把adj和proc_state都拉回到 heavy weight水平
        if (app.getCachedIsHeavyWeight()) {
            if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                // We don't want to kill the current heavy-weight process.
                adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                app.setCached(false);
                app.adjType = "heavy";
            }
            if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
                procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
                app.adjType = "heavy";
            }
        }
  • realStartActivityLocked()过程,当应用的privateFlags标识PRIVATE_FLAG_CANT_SAVE_STATE,设置mHeavyWeightProcess值;
  • finishHeavyWeightApp(), 置空mHeavyWeightProcess值;

 

8. HOME_APP_ADJ(600)

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {

        ...

        //HOME 进程,将其拉回HOME_APP_ADJ
        if (app.getCachedIsHomeProcess()) {
            if (adj > ProcessList.HOME_APP_ADJ) {
                // This process is hosting what we currently consider to be the
                // home app, so we don't want to let it go into the background.
                adj = ProcessList.HOME_APP_ADJ;
                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                app.setCached(false);
                app.adjType = "home";
            }
            if (procState > ActivityManager.PROCESS_STATE_HOME) {
                procState = ActivityManager.PROCESS_STATE_HOME;
                app.adjType = "home";
            }
        }

当类型为ACTIVITY_TYPE_HOME的应用启动后会设置mHomeProcess,比如桌面APP。

9. PREVIOUS_APP_ADJ(700)

frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
            boolean computeClients) {

        ...

        /********* 场景 1 **********/
        if (app.getCachedIsPreviousProcess() && app.getCachedHasActivities()) {
            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                // This was the previous process that showed UI to the user.
                // We want to try to keep it around more aggressively, to give
                // a good experience around switching between two apps.
                adj = ProcessList.PREVIOUS_APP_ADJ;
                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                app.setCached(false);
                app.adjType = "previous";
            }
            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
                procState = PROCESS_STATE_LAST_ACTIVITY;
                app.adjType = "previous";
            }
        }

        ...

        /********* 场景 2 **********/
        if (app.lastProviderTime > 0 &&
                (app.lastProviderTime + mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
            if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                adj = ProcessList.PREVIOUS_APP_ADJ;
                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                app.setCached(false);
                app.adjType = "recent-provider";
            }
            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
                procState = PROCESS_STATE_LAST_ACTIVITY;
                app.adjType = "recent-provider";
            }
        }

在 computeOomAdjLocked() 函数用有两种场景。

场景1:用户上一个使用的包含UI的进程,为了给用户在两个APP之间更好的切换体验,将上一个进程ADJ设置到PREVIOUS_APP_ADJ的档次。 当activityStoppedLocked()过程会更新上一个应用。

场景2: 当 provider进程,上一次使用时间不超过20S的情况下,优先级不低于PREVIOUS_APP_ADJ。provider进程这个是Android 7.0以后新增的逻辑 ,这样做的好处是在内存比较低的情况下避免拥有provider的进程出现颠簸,也就是启动后杀,然后又被拉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/754174.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32定义变量到指定内存位置

rt thread&#xff0c; 怎么定义变量到指定内存位置&#xff1f; OpenCat是由未来可编程机器人宠物制造商Petoi开发的基于Arduino和Raspberry Pi的开源四足机器人宠物框架。 非 gcc 版 定义一个宏 #ifndef __MEMORY_AT #if (defined (__CC_ARM)) #define _…

来电屏蔽号码分析

场测反馈77号码开头的电话号码屏蔽后&#xff0c;来电可以屏蔽&#xff0c;但是短信无法屏蔽 //Blocker is close 行 2689: 05-19 12:12:36.477096 2348 2348 I TelecomFramework: TelephonyConnectionService: onCallFilteringCompleted(TC3_1, CallFilteringCompletionInf…

leetcode:1184. 公交站间的距离(python3解法)

难度&#xff1a;简单 环形公交路线上有 n 个站&#xff0c;按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离&#xff0c;distance[i] 表示编号为 i 的车站和编号为 (i 1) % n 的车站之间的距离。 环线上的公交车都可以按顺时针和逆时针的方向行驶。 返回乘…

ECharts笔记-------柱状图与折线图

这幅图表由title、legend、series、xAxis、yAxis和tooltip这六个组件组成&#xff0c;每个组件都有对应的属性来调节参数&#xff0c;title和legend的代码跟上一篇一样&#xff0c;这里就不多讲了。 tooltip组件 tooltip: {trigger: axis,axisPointer: { type: cross } }, t…

系统组网图

接收路由器发送的数据信息并解析&#xff0c;做出相应的指示&#xff0c;点击按键表示完成拣货。 标签ID码正面显示无线通信868M&#xff0c;跳频通信通信速率200K/50K覆盖通信半径30米以上多色LED高亮指示灯自定义双向通信协议&#xff0c;安全可靠 电子标签拣货系统就是通过…

诺康达将再次上会接受审核:曾遭暂缓审议,业绩可持续性值得商榷

撰稿|行星 来源|贝多财经 近日&#xff0c;深圳证券交易所披露的信息显示&#xff0c;北京诺康达医药科技股份有限公司&#xff08;下称“诺康达”&#xff09;将于2023年7月20日接受上市委的审议&#xff0c;并于7月13日更新了招股书&#xff08;上会稿&#xff09;。 据招股…

总部V批恩没有发送到分支流量,只有接收分支流量,分支无法访问总部内网资源

环境&#xff1a; 分支设备&#xff1a; AF8.0.48 联想笔记本 总部设备&#xff1a; SSL V批恩 V7.0 AF8.0.75 RUIJIE NBS5710-24GT4SFP-E 问题描述&#xff1a; 总部V批恩没有发送到分支流量&#xff0c;只有接收分支流量&#xff0c;分支无法访问总部内网资源&#…

H3C-Cloud Lab实验-单臂路由实验

实验拓扑图&#xff1a; 实验需求&#xff1a; 1. 按照图示为 PC3 和 PC4 配置 IP 地址和网关 2. PC3 属于 Vlan10&#xff0c;PC4 属于 Vlan20&#xff0c;配置单臂路由实现 Vlan10 和 Vlan20 三层互通 3. PC3 和 PC4 可以互通 实验步骤&#xff1a; 1. 连接所有设备 2. …

Unity游戏源码分享-卡通填色游戏Drawing Coloring Extra Edition 1.09

Unity游戏源码分享-卡通填色游戏Drawing Coloring Extra Edition 1.09 非常适合小朋友玩的小游戏 功能很齐全完善 项目地址&#xff1a;https://download.csdn.net/download/Highning0007/88050261

KuiperInfer深度学习推理框架环境配置-Ubuntu 22.04

KuiperInfer项目地址 Github项目地址 B站课程地址 安装Armadillo 官网&#xff1a;Armadillo官网 介绍&#xff1a;Armadillo C Library是一种C的线性代数库&#xff0c;包含一些矩阵和向量的运算&#xff0c;可以选用高效的LAPACK和BLAS进行加速。 矩阵相关计算的文档&…

Arthas和常量池

一、Arthas 快速入门 | arthas 1、Arthas使用 运行arthas提供的应用程序 curl -O https://arthas.aliyun.com/math-game.jar java -jar math-game.jar 运行arthas工具jar包 curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar 启动界面如下图&…

Google Play针对恶意软件采取最新反制措施!

近日&#xff0c;谷歌开始针对Google Play上不断入侵的恶意软件采取反制措施&#xff0c;要求所有以机构名义注册的新开发者账户在提交应用程序之前提供一个有效的D-U-N-S号码。 这项新措施能有效提高平台的安全性和可信度&#xff0c;同时也能够有效遏制新账户提交恶意软件的…

kubernetes中特定域名使用自定义DNS服务器出现的解析异常

故障发生背景&#xff1a; 租户反馈生产业务服务连接到中间件的时候&#xff0c;偶尔会有连接失败的情况&#xff0c;然后我们查看对应组件服务正常&#xff0c;手动请求组件服务也显示正常&#xff0c;让租户查看业务服务日志发现报错无法解析对应的域名&#xff0c;我们手动是…

数据库的分片策略

数据库的分片策略 1、范围分片2、hash 取模分片3、一致性hash 分片 1.分片策略 数据库的分片策略是指将数据库中的数据按照一定的规则和方式进行分割&#xff08;分片&#xff09;存储在不同的物理节点或服务器上的策略。分片策略旨在实现水平扩展&#xff0c;提高数据库的性…

暑假第九天打卡

英语&#xff1a; 新东方六级一单元单词刷题复习 离散&#xff1a; 例12 使用消解算法判断下述公式是否是可满足的: 公式 S p∧(p∨q)∧(p∨q)∧(q∨r)∧(q∨r) 解&#xff1a; S p∧(p∨q)∧(p∨q)∧(q∨r)∧(q∨r) //化为主合取式 循环1&#xff1a; S0 S1 {p…

Windows 进程和作业

Windows 进程和作业 创建进程CreateProcess 函数的参数CreateProcess 的流程 创建Windows“现代化”进程创建其他类型的进程 进程的内部构造EPROCESSKPROCESSPEBCSR_PROCESSW32PROCESS 受保护进程最小进程和 Pico 进程最小进程Pico进程 Trustlet 安全进程进程的终止作业作业的限…

合并完之后,进行回退

我是将分支合并到了uat_v3上&#xff0c;现在又要求将uat_v3上的代码回退到合并以前&#xff1b; 我是将origin/uat_v3 checkout 除一份本地uat_v3,然后选中合并以前的commit记录&#xff0c;新建分支 temp/reverse 分支&#xff1b; 这样我本地的temp/reverse分支就已经是合…

[Java进阶] Swing两万字大总结一(超详细教程,这不得收藏一波)

&#x1f525;一个人走得远了&#xff0c;就会忘记自己为了什么而出发&#xff0c;希望你可以不忘初心&#xff0c;不要随波逐流&#xff0c;一直走下去&#x1f3b6; &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43e; &#x1f984; …

将类模板做为参数(类模板中使用)

将类模板做为参数&#xff08;类模板中使用&#xff09; 这种方式只在类模板中使用&#xff0c;函数模板不能使用这种方法。 将模板名做为一种特殊的数据类型&#xff0c;实例化对象的时候&#xff0c;使用模板名做为参数&#xff0c;传递给模板。 下面例子中&#xff0c;数组…

Unity 上传文件到阿里云 对象存储OSS服务器

首先登录阿里云 免费试用–对象存储OSS --点击立即试用&#xff0c;可以有三个月的免费试用 创建Buket 新建AccessKey ,新建完成后&#xff0c;会有一个CSV文件&#xff0c;下载下来&#xff0c;里面有Key &#xff0c;代码中需要用到 下载SDK 双击打开 sln文件&#xff0…