Android进程管理1—优先级adj

优先级adj

1. Android应用进程的分类

Android将应用进程分为五大类,分别为Forground类、Visible类、Service类、Background类及Empty类。

  1. Forground类

该类中的进程重要性最高,属于该类的进程包括下面几种情况:

  • 含一个前端Activity(即onResume函数被调用过了,或者说当前正在显示的那个Activity)。
  • 含一个Service,并且该Service和一个前端Activity绑定(例如Music应用包括一个前端界面和一个播放Service,当我们一边听歌一边操作Music界面时,该Service即和一个前端Activity绑定)。
  • 含一个调用了startForground的Service,或者该进程的Service正在调用其生命周期的函数(onCreate、onStart或onDestroy)。
  • 最后一种情况是,该进程中有BroadcastReceiver实例正在执行onReceive函数。
  1. Visible类

    该进程中没有处于前端的组件,但是用户仍然能看到它们,例如位于一个对话框后的Activity界面。目前该类进程包括两种:

  • 该进程包含一个仅onPause被调用的Activity(即它还在前台,只不过部分界面被遮住)。
  • 或者包含一个Service,并且该Service和一个Visible(或Forground)的Activity绑定(从字面意义上看,这种情况不太好和Forground进程中第二种情况区分)。(3) Service类、Background类及Empty类

这三类进程都没有可见的部分,具体情况如下。

  1. **Service进程:**该类进程包含一个Service。此Service通过startService启动,并且不属于前面两类进程。这种进程一般在后台默默地干活,例如前面介绍的MediaScannerService。
  2. **Background进程:**该类进程包含当前不可见的Activity(即它们的onStop被调用过)。系统保存这些进程到一个LRU(最近最少使用)列表。当系统需要回收内存时,该列表中那些最近最少使用的进程将被杀死。
  3. **Empty进程:**这类进程中不包含任何组件。为什么会出现这种不包括任何组件的进程呢?其实很简单,假设该进程仅创建了一个Activity,它完成工作后主动调用finish函数销毁(destroy)自己,之后该进程就会成为Empty进程。系统保留Empty进程的原因是当又重新需要它们时(例如用户在别的进程中通过startActivity启动了它们),可以省去fork进程、创建Android运行环境等一系列漫长而艰苦的工作。

通过以上介绍可发现,当某个进程和前端显示有关系时,其重要性相对要高,这或许是体现Google重视用户体验的一个很直接的证据吧。

五个还是四个有疑问

developer.android.com/guide/compo…

2.Android 进程优先级的相关概念

2.1 oom_score_adj级别

对于每一个运行中的进程,Linux 内核都通过 proc 文件系统暴露 /proc/[pid]/oom_score_adj 这样一个文件来允许其他程序修改指定进程的优先级,这个文件允许的值的范围是:-1000 ~ +1001之间。值越小,表示进程越重要。当内存非常紧张时,系统便会遍历所有进程,以确定哪个进程需要被杀死以回收内存,此时便会读取 oom_score_adj 这个文件的值。

PS:在Linux 2.6.36之前的版本中,Linux 提供调整优先级的文件是 /proc/[pid]/oom_adj 。这个文件允许的值的范围是-17 ~ +15之间。数值越小表示进程越重要。 这个文件在新版的 Linux 中已经废弃。但你仍然可以使用这个文件,当你修改这个文件的时候,内核会直接进行换算,将结果反映到 oom_score_adj 这个文件上。Android早期版本的实现中也是依赖 oom_adj 这个文件。但是在新版本中,已经切换到使用 oom_score_adj 这个文件。

为了便于管理,ProcessList.java中预定义了 oom_score_adj 的可能取值,这里的预定义值也是对应用进程的一种分类。


// 这是一个仅托管不可见活动的进程,因此它可以在没有任何干扰的情况下被终止。
static final int CACHED_APP_MAX_ADJ = 999;
static final int CACHED_APP_MIN_ADJ = 900;

// 这是我们允许首先退出的oom_adj级别。除非正在为进程分配oom_score_adj等于CACHED_APP_MAX_ADJ,
// 否则它不能等于CACHED_APP_MAX_ADJ。
static final int CACHED_APP_LMK_FIRST_ADJ = 950;

// SERVICE_ADJ的B列表-这些是旧的和老化的服务,不如A列表中的服务那么好看。
static final int SERVICE_B_ADJ = 800;

// 这是用户之前使用过的应用程序的进程。该进程保持在其他内容之上,因**为切换回先前的应用程**序非常常见。
这对于最近的任务切换(在两个最近的应用程序之间切换)以及正常的UI流非常重要,
例如在电子邮件应用程序中点击URI以在浏览器中查看,然后按返回键返回到电子邮件。
static final int PREVIOUS_APP_ADJ = 700;

// 这是托管主页应用程序的进程-即使它通常处于后台状态,我们也要尽量避免杀死它,因为用户与之交互非常频繁。
static final int HOME_APP_ADJ = 600;

// 这是托管应用程序服务的进程-杀死它不会对用户产生太大影响。
static final int SERVICE_ADJ = 500;

// 这是具有重型应用程序的进程。它在后台运行,但我们希望尽量避免杀死它。
在启动时在system/rootdir/init.rc中设置的值。
static final int HEAVY_WEIGHT_APP_ADJ = 400;

// 这是目前正在进行备份操作的进程。杀死它并不完全致命,但通常不是一个好主意。
static final int BACKUP_APP_ADJ = 300;

// 这是由系统(或其他应用程序)绑定的进程,比服务更重要,但不会立即影响用户如果被杀死。
static final int PERCEPTIBLE_LOW_APP_ADJ = 250;

// 这是仅托管对用户可见组件的进程,并且我们确实希望避免杀死它们,但它们不是立即可见的。
// 例如,后台音乐播放就是一个例子。
static final int PERCEPTIBLE_APP_ADJ = 200;

// 这是仅托管对用户可见活动的进程,因此我们希望它们不会消失。
static final int VISIBLE_APP_ADJ = 100;
//200 -100 -1
static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;

// 这是最近处于前景应用程序并移动到FGS的进程。在一段时间内,继续将其视为几乎与前台应用程序相同。
// @see TOP_TO_FGS_GRACE_PERIOD
static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50;

// 运行当前前台应用程序的进程。是普通应用程序能够获取到的最高优先级。
static final int FOREGROUND_APP_ADJ = 0;

// 系统或持久进程绑定到的进程,并指出它很重要。
static final int PERSISTENT_SERVICE_ADJ = -700;

// 这是一个系统持久进程,例如电话。绝对不希望杀死它,但这样做并不完全致命。
static final int PERSISTENT_PROC_ADJ = -800;

// 系统进程以默认调整运行。
static final int SYSTEM_ADJ = -900;

// 用于原生进程的特殊代码,这些进程不受系统管理(因此系统不会分配oom adj)。
static final int NATIVE_ADJ = -1000;

一些重要的adj级别

FOREGROUND_APP_ADJ = 0是普通应用程序能够获取到的最高优先级。

VISIBLE_APP_ADJ是具有可见Activity进程的优先级:同一时刻,不一定只有一个Activity是可见的,如果前台Activity设置了透明属性,那么背后的Activity也是可见的。

PERCEPTIBLE_APP_ADJ是指用户可感知的进程,可感知的进程包括:

  • 进程中包含了处于pause状态或者正在pause的Activity
  • 进程中包含了正在stop的Activity
  • 进程中包含了前台的Service

HEAVY_WEIGHT_APP_ADJ 描述的重量级进程是指那些通过Manifest指明不能保存状态的应用进程。

除此之外,Android系统中,有一些系统应用会常驻内存,这些应用通常是系统实现的一部分,如果它们不存在,系统将处于比较奇怪的状态,例如SystemUI(状态栏,Keyguard都处于这个应用中)。

所以它们的优先级比所有应用进程的优先级更高:PERSISTENT_SERVICE_ADJ = -700PERSISTENT_PROC_ADJ = -800

另外,还有一些系统服务的实现,如果这些系统服务不存在,系统将无法工作,所以这些应用的优先级最高,几乎是任何任何时候都需要存在的:SYSTEM_ADJ = -900NATIVE_ADJ = -1000

2.2 ProcessRecord中涉及oom_score_adj的属性

**ProcessRecord.java**
//用于LRU列表控制
long lastActivityTime;   // For managing the LRU list
long lruWeight;      // Weight for ordering in LRU list
//和oom_adj有关
int maxAdj;           // Maximum OOM adjustment for thisprocess
int hiddenAdj;       // If hidden, this is the adjustment touse
int curRawAdj;       // Current OOM unlimited adjustment forthis process
int setRawAdj;       // Last set OOM unlimited adjustment forthis process
int curAdj;           // Current OOM adjustment for thisprocess
int setAdj;           // Last set OOM adjustment for thisprocess
//和调度优先级有关
int curSchedGroup;   // Currently desired scheduling class
int setSchedGroup;   // Last set to background scheduling class
//回收内存级别,见后文解释
int trimMemoryLevel; // Last selected memorytrimming level
//判断该进程的状态,主要和其中运行的Activity,Service有关
boolean keeping;     // Actively running code sodon't kill due to that?
boolean setIsForeground;    // Running foreground UI when last set?
boolean foregroundServices; // Running anyservices that are foreground?
boolean foregroundActivities; // Running anyactivities that are foreground?
boolean systemNoUi;   // This is a system process, but notcurrently showing UI.
boolean hasShownUi;  // Has UI been shown in this process since itwas started?
boolean pendingUiClean;     // Want to clean up resources from showingUI?
boolean hasAboveClient;     // Bound using BIND_ABOVE_CLIENT, so wantto be lower
//是否处于系统BadProcess列表
boolean bad;                // True if disabled in the badprocess list
//描述该进程因为是否有太多后台组件而被杀死
boolean killedBackground;   // True when proc has been killed due to toomany bg
String waitingToKill;       // Process is waiting to be killed whenin the bg; reason
//序号,每次调节进程优先级或者LRU列表位置时,这些序号都会递增
int adjSeq;                 // Sequence id for identifyingoom_adj assignment cycles
int lruSeq;                 // Sequence id for identifyingLRU update cycles

2.2.1 ProcessState

进程的状态会影响虚拟机对于进程的内存分配和垃圾回收策略,ProcessRecord中的下面这几个属性记录了进程的状态:

对应的在 ActivityManager 重定义了 process_state 级别的划分,Android 系统会在修改进程状态的同时更新 oom_score_adj 的分级:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QmcyHg5L-1688460965268)(https://link.juejin.cn/?target=http%3A%2F%2Fimages.notend.cn%2F2018-03-15-18-03-57.png “http://images.notend.cn/2018-03-15-18-03-57.png”)]

2.2.2 ScheduleGroup

内核负责了进程的CPU调度,所有运行中的进程并非能平等的能获取相等的时间片。在ProcessRecord中,通过Schedule Group来记录进程的调度组:

对应到底层进程分组,除了上面提到的 Process.java 定义的不同线程组的定义,同时还为 Activity manager 定义了一套类似的调度分组,和之前的线程分组定义也存在对应关系:

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

// Activity manager's version of Process.THREAD_GROUP_BACKGROUND
    static final int SCHED_GROUP_BACKGROUND = 0;
      // Activity manager's version of Process.THREAD_GROUP_RESTRICTED
    static final int SCHED_GROUP_RESTRICTED = 1;
    // Activity manager's version of Process.THREAD_GROUP_DEFAULT
    static final int SCHED_GROUP_DEFAULT = 2;
    // Activity manager's version of Process.THREAD_GROUP_TOP_APP
    public static final int SCHED_GROUP_TOP_APP = 3;
    // Activity manager's version of Process.THREAD_GROUP_TOP_APP
    // Disambiguate between actual top app and processes bound to the top app
    static final int SCHED_GROUP_TOP_APP_BOUND = 4;

valueActivityManager.javaProcessList.java
0Process.THREAD_GROUP_BACKGROUNDSCHED_GROUP_BACKGROUND
1Process.THREAD_GROUP_RESTRICTEDSCHED_GROUP_RESTRICTED
2Process.THREAD_GROUP_DEFAULTSCHED_GROUP_DEFAULT
3Process.THREAD_GROUP_TOP_APPSCHED_GROUP_TOP_APP
4Process.THREAD_GROUP_TOP_APPSCHED_GROUP_TOP_APP_BOUND

3.Android 进程优先级的变化

进程的优先级反应了系统对于进程重要性的判定。

在Android系统中,进程的优先级影响着以下三个因素:

  • 当内存紧张时,系统对于进程的回收策略
  • 系统对于进程的CPU调度策略
  • 虚拟机对于进程的内存分配和垃圾回收策略

我们知道影响 Android 应用进程优先级变化的是根据 Android应用组件的生命周期变化相关。Android进程调度之adj算法 里面罗列了所有会触发进程状态发生变化的事件,主要包括:

组件方法名称描述
ActivityrealStartActivityLocked启动Activity
resumeTopActivityInnerLocked恢复栈顶Activity
finishCurrentActivityLocked结束当前Activity
destroyActivityLocked摧毁当前Activity
ServicerealStartServiceLocked启动服务
bindServiceLocked绑定服务(只更新当前app)
unbindServiceLocked解绑服务(只更新当前app)
bringDownServiceLocked结束服务(只更新当前app)
sendServiceArgsLocked在启动或清理服务过程中调用(只更新当前app)
BroadcastBQ.processNextBroadcast处理下一个广播
BQ.processCurBroadcastLocked处理当前广播
BQ.deliverToRegisteredReceiverLocked分发已注册的广播(只更新当前app)
ContentProviderAMS.removeContentProvider移除provider
AMS.publishContentProviders发布provider(只更新当前app)
AMS.getContentProviderImpl获取provider(只更新当前app)
ProcesssetSystemProcess创建并设置系统进程
addAppLocked创建persistent进程
attachApplicationLocked进程创建后attach到system_server的过程
trimApplications清除未使用的app
appDiedLocked进程死亡
killAllBackgroundProcesses杀死所有后台进程(ADJ>9或removed=true的普通进程)
killPackageProcessesLocked以包名的形式杀掉相关进程

以上都会直接或间接调用到 AMS 中的 updateOomAdjLocked 方法来更新进程的优先级,最终实现在OomAdjuster.java类中。

3.1 OomAdjuster的updateOomAdjLocked

主要有以下两个方法负责更新进程优先级

void updateOomAdjLocked(String oomAdjReason) 针对所有进程

boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll, String oomAdjReason) {针对单个进程

3.1.1 针对单独进程调整adj updateOomAdjLocked

对应代码


    private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord TOP_APP, boolean doingAll, long now) {
        if (app.thread == null) {
            return false;
        }

        computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now, false);

        return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
    }

3.1.2 computeOomAdjLocked

computeOomAdjLocked 方法负责计算进程的优先级,总计约700行,实在是太长了。简短总结为根据进程的不同状态分别更新adj,procstate和schedgruop。总结为下图。没有挨个校验,具体以实际代码为准。

进程优先级.png

3.1.3 applyOomAdjLocked

  1. 据adj变化处理内存压缩 AppCompactor
  2. 更新进程的oom adj,通过socket写给lmkd
  3. 更新SchedGroup
  • 对于需要被杀的bg进程杀掉。如果waitingToKill不为null(waitingToKill =reason),receiver为空并且为SCHED_GROUP_BACKGROUND
  • 根据 ProcessList.java ActivityManager.java两者group对应关系最终通过setProcessGroup(pid, group);更新group,联系上边看下。
  1. 对于变成前台或者从前台变化的进程,进行RT和FIFO的变换,通过scheduleAsFifoPriority和setThreadPriority更改优先级和实时策略
  2. 更新nextPssTime,这个值即是下次更新PSS的时间。
  3. 和PROCESS_STATE_SERVICE相比较,判断是不是重要进程
  4. 新单个进程的memFactor状态,这个值和trim memory相关
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
    @GuardedBy("mService")
    private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
            long nowElapsed) {
        boolean success = true;

        if (app.getCurRawAdj() != app.setRawAdj) {
            app.setRawAdj = app.getCurRawAdj();
        }
        int changes = 0;

        // don't compact during bootup
	      //1.内存压缩相关逻辑
        if (mAppCompact.useCompaction() && mService.mBooted) {
            // Cached and prev/home compaction
            if (app.curAdj != app.setAdj) {
                // Perform a minor compaction when a perceptible app becomes the prev/home app
                // Perform a major compaction when any app enters cached
                // reminder: here, setAdj is previous state, curAdj is upcoming state
                if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
                        (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
                                app.curAdj == ProcessList.HOME_APP_ADJ)) {
                    mAppCompact.compactAppSome(app);
                } else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ
                                || app.setAdj > ProcessList.CACHED_APP_MAX_ADJ)
                        && app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
                        && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
                    mAppCompact.compactAppFull(app);
                }
            } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
                    && app.setAdj < ProcessList.FOREGROUND_APP_ADJ
                    // Because these can fire independent of oom_adj/procstate changes, we need
                    // to throttle the actual dispatch of these requests in addition to the
                    // processing of the requests. As a result, there is throttling both here
                    // and in AppCompactor.
                    && mAppCompact.shouldCompactPersistent(app, now)) {
                mAppCompact.compactAppPersistent(app);
            } else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE
                    && app.getCurProcState()
                        == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
                    && mAppCompact.shouldCompactBFGS(app, now)) {
                mAppCompact.compactAppBfgs(app);
            }
        }
				//2.设置进程的oomadj
        if (app.curAdj != app.setAdj) {
            ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
                String msg = "Set " + app.pid + " " + app.processName + " adj "
                        + app.curAdj + ": " + app.adjType;
                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
            }
            app.setAdj = app.curAdj;
            app.verifiedAdj = ProcessList.INVALID_ADJ;
        }

        final int curSchedGroup = app.getCurrentSchedulingGroup();
	//3.更新进程SchedGroup,判断进程是否需要被杀
        if (app.setSchedGroup != curSchedGroup) {
            int oldSchedGroup = app.setSchedGroup;
            app.setSchedGroup = curSchedGroup;
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
                String msg = "Setting sched group of " + app.processName
                        + " to " + curSchedGroup + ": " + app.adjType;
                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
            }
//如果waitingToKill不为null(waitingToKill =reason),receiver为空并且为SCHED_GROUP_BACKGROUND
则被杀
            if (app.waitingToKill != null && app.curReceivers.isEmpty()
                    && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
                app.kill(app.waitingToKill, true);
                success = false;
            } else {
                int processGroup;
                switch (curSchedGroup) {
                    case ProcessList.SCHED_GROUP_BACKGROUND:
                        processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
                        break;
                    case ProcessList.SCHED_GROUP_TOP_APP:
                    case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
                        processGroup = THREAD_GROUP_TOP_APP;
                        break;
                    case ProcessList.SCHED_GROUP_RESTRICTED:
                        processGroup = THREAD_GROUP_RESTRICTED;
                        break;
                    default:
                        processGroup = THREAD_GROUP_DEFAULT;
                        break;
                }
                mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage(
                        0 /* unused */, app.pid, processGroup));
//4.对于变成前台或者从前台变化的进程,进行RT和FIFO的变换,通过scheduleAsFifoPriority和setThreadPriority
更改优先级和实时策略
                try {
                    if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                        // do nothing if we already switched to RT
                        if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                            app.getWindowProcessController().onTopProcChanged();
                            if (mService.mUseFifoUiScheduling) {
                                // Switch UI pipeline for app to SCHED_FIFO
                                app.savedPriority = Process.getThreadPriority(app.pid);
                                mService.scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
                                if (app.renderThreadTid != 0) {
                                    mService.scheduleAsFifoPriority(app.renderThreadTid,
                                            /* suppressLogs */true);
                                    if (DEBUG_OOM_ADJ) {
                                        Slog.d("UI_FIFO", "Set RenderThread (TID " +
                                                app.renderThreadTid + ") to FIFO");
                                    }
                                } else {
                                    if (DEBUG_OOM_ADJ) {
                                        Slog.d("UI_FIFO", "Not setting RenderThread TID");
                                    }
                                }
                            } else {
                                // Boost priority for top app UI and render threads
                                setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);
                                if (app.renderThreadTid != 0) {
                                    try {
                                        setThreadPriority(app.renderThreadTid,
                                                TOP_APP_PRIORITY_BOOST);
                                    } catch (IllegalArgumentException e) {
                                        // thread died, ignore
                                    }
                                }
                            }
                        }
                    } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
                            curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                        app.getWindowProcessController().onTopProcChanged();
                        if (mService.mUseFifoUiScheduling) {
                            try {
                                // Reset UI pipeline to SCHED_OTHER
                                setThreadScheduler(app.pid, SCHED_OTHER, 0);
                                setThreadPriority(app.pid, app.savedPriority);
                                if (app.renderThreadTid != 0) {
                                    setThreadScheduler(app.renderThreadTid,
                                            SCHED_OTHER, 0);
                                    setThreadPriority(app.renderThreadTid, -4);
                                }
                            } catch (IllegalArgumentException e) {
                                Slog.w(TAG,
                                        "Failed to set scheduling policy, thread does not exist:\n"
                                                + e);
                            } catch (SecurityException e) {
                                Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);
                            }
                        } else {
                            // Reset priority for top app UI and render threads
                            setThreadPriority(app.pid, 0);
                            if (app.renderThreadTid != 0) {
                                setThreadPriority(app.renderThreadTid, 0);
                            }
                        }
                    }
                } catch (Exception e) {
                    if (DEBUG_ALL) {
                        Slog.w(TAG, "Failed setting thread priority of " + app.pid, e);
                    }
                }
            }
        }
        if (app.repForegroundActivities != app.hasForegroundActivities()) {
            app.repForegroundActivities = app.hasForegroundActivities();
            changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
        }
        if (app.getReportedProcState() != app.getCurProcState()) {
            app.setReportedProcState(app.getCurProcState());
            if (app.thread != null) {
                try {
                    if (false) {
                        //RuntimeException h = new RuntimeException("here");
                        Slog.i(TAG, "Sending new process state " + app.getReportedProcState()
                                + " to " + app /*, h*/);
                    }
                    app.thread.setProcessState(app.getReportedProcState());
                } catch (RemoteException e) {
                }
            }
        }
//5.如果进程setProcState等于PROCESS_STATE_NONEXISTENT,或者和内存记录的ProcState对比有变化
更新nextPssTime
        if (app.setProcState == PROCESS_STATE_NONEXISTENT
                || ProcessList.procStatesDifferForMem(app.getCurProcState(), app.setProcState)) {
            if (false && mService.mTestPssMode
                    && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
                // Experimental code to more aggressively collect pss while
                // running test...  the problem is that this tends to collect
                // the data right when a process is transitioning between process
                // states, which will tend to give noisy data.
                long start = SystemClock.uptimeMillis();
                long startTime = SystemClock.currentThreadTimeMillis();
                long pss = Debug.getPss(app.pid, mTmpLong, null);
                long endTime = SystemClock.currentThreadTimeMillis();
                mService.recordPssSampleLocked(app, app.getCurProcState(), pss,
                        mTmpLong[0], mTmpLong[1], mTmpLong[2],
                        ProcessStats.ADD_PSS_INTERNAL_SINGLE, endTime-startTime, now);
                mService.mPendingPssProcesses.remove(app);
                Slog.i(TAG, "Recorded pss for " + app + " state " + app.setProcState
                        + " to " + app.getCurProcState() + ": "
                        + (SystemClock.uptimeMillis()-start) + "ms");
            }
            app.lastStateTime = now;
            app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
                    app.procStateMemTracker, mService.mTestPssMode,
                    mService.mAtmInternal.isSleeping(), now);
            if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
                    + ProcessList.makeProcStateString(app.setProcState) + " to "
                    + ProcessList.makeProcStateString(app.getCurProcState()) + " next pss in "
                    + (app.nextPssTime-now) + ": " + app);
        } else {
            if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
                    && now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
                    mService.mTestPssMode)))) {
                if (mService.requestPssLocked(app, app.setProcState)) {
                    app.nextPssTime = ProcessList.computeNextPssTime(app.getCurProcState(),
                            app.procStateMemTracker, mService.mTestPssMode,
                            mService.mAtmInternal.isSleeping(), now);
                }
            } else if (false && DEBUG_PSS) {
                Slog.d(TAG_PSS,
                        "Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
            }
        }
        if (app.setProcState != app.getCurProcState()) {
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.uid) {
                String msg = "Proc state change of " + app.processName
                        + " to " + ProcessList.makeProcStateString(app.getCurProcState())
                        + " (" + app.getCurProcState() + ")" + ": " + app.adjType;
                reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
            }
//6.判断是否是重要进程
            boolean setImportant = app.setProcState < PROCESS_STATE_SERVICE;
            boolean curImportant = app.getCurProcState() < PROCESS_STATE_SERVICE;
            if (setImportant && !curImportant) {
                // This app is no longer something we consider important enough to allow to use
                // arbitrary amounts of battery power. Note its current CPU time to later know to
                // kill it if it is not behaving well.
                app.setWhenUnimportant(now);
                app.lastCpuTime = 0;
            }
            // Inform UsageStats of important process state change
            // Must be called before updating setProcState
            maybeUpdateUsageStatsLocked(app, nowElapsed);

            maybeUpdateLastTopTime(app, now);

            app.setProcState = app.getCurProcState();
            if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
                app.notCachedSinceIdle = false;
            }
//7.更新单个进程的memFactor状态,这个值和trim memory相关
            if (!doingAll) {
                mService.setProcessTrackerStateLocked(app,
                        mService.mProcessStats.getMemFactorLocked(), now);
            } else {
                app.procStateChanged = true;
            }
        } else if (app.reportedInteraction && (nowElapsed - app.getInteractionEventTime())
                > mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
            // For apps that sit around for a long time in the interactive state, we need
            // to report this at least once a day so they don't go idle.
            maybeUpdateUsageStatsLocked(app, nowElapsed);
        } else if (!app.reportedInteraction && (nowElapsed - app.getFgInteractionTime())
                > mConstants.SERVICE_USAGE_INTERACTION_TIME) {
            // For foreground services that sit around for a long time but are not interacted with.
            maybeUpdateUsageStatsLocked(app, nowElapsed);
        }

        if (changes != 0) {
            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                    "Changes in " + app + ": " + changes);
            ActivityManagerService.ProcessChangeItem item =
                    mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
            item.changes = changes;
            item.foregroundActivities = app.repForegroundActivities;
            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                    "Item " + Integer.toHexString(System.identityHashCode(item))
                            + " " + app.toShortString() + ": changes=" + item.changes
                            + " foreground=" + item.foregroundActivities
                            + " type=" + app.adjType + " source=" + app.adjSource
                            + " target=" + app.adjTarget);
        }

        return success;
    }

3.2 updateOomAdjLocked(String oomAdjReason) 针对所有进程

oomAdjReason相关的场景参考下面的表格。

常量名log日志描述
OOM_ADJ_REASON_NONEupdateOomAdj_meh没有特定的 OOM Adj 原因
OOM_ADJ_REASON_ACTIVITYupdateOomAdj_activityChangeActivity 变化导致的 OOM Adj 更新
OOM_ADJ_REASON_FINISH_RECEIVERupdateOomAdj_finishReceiver结束 Receiver 导致的 OOM Adj 更新
OOM_ADJ_REASON_START_RECEIVERupdateOomAdj_startReceiver启动 Receiver 导致的 OOM Adj 更新
OOM_ADJ_REASON_BIND_SERVICEupdateOomAdj_bindService绑定 Service 导致的 OOM Adj 更新
OOM_ADJ_REASON_UNBIND_SERVICEupdateOomAdj_unbindService解绑 Service 导致的 OOM Adj 更新
OOM_ADJ_REASON_START_SERVICEupdateOomAdj_startService启动 Service 导致的 OOM Adj 更新
OOM_ADJ_REASON_GET_PROVIDERupdateOomAdj_getProvider获取 Content Provider 导致的 OOM Adj 更新
OOM_ADJ_REASON_REMOVE_PROVIDERupdateOomAdj_removeProvider移除 Content Provider 导致的 OOM Adj 更新
OOM_ADJ_REASON_UI_VISIBILITYupdateOomAdj_uiVisibilityUI 可见性变化导致的 OOM Adj 更新
OOM_ADJ_REASON_WHITELISTupdateOomAdj_whitelistChange白名单变化导致的 OOM Adj 更新
OOM_ADJ_REASON_PROCESS_BEGINupdateOomAdj_processBegin进程启动导致的 OOM Adj 更新
OOM_ADJ_REASON_PROCESS_ENDupdateOomAdj_processEnd进程结束导致的 OOM Adj 更新

代码太长了贴不动了。之后在分析吧

4.Process中对线程和进程的调度

frameworks/base/core/java/android/os/Process.java

/*
   设置线程的Group,实际上就是设置线程的调度策略,目前Android定义了三种Group。
   THREAD_GROUP_DEFAULT:Default thread group - gets a 'normal'share of the CPU
   THREAD_GROUP_BG_NONINTERACTIVE:Background non-interactive thread group.
   Allthreads in this group are scheduled with a reduced share of the CPU
   THREAD_GROUP_FG_BOOST:Foreground 'boost' thread group - Allthreads in
   this group are scheduled with an increasedshare of the CPU.
   目前代码中还没有地方使用THREAD_GROUP_FG_BOOST这种Group
*/
public static final native void setThreadGroup(inttid, int group)
           throws IllegalArgumentException, SecurityException;

//设置进程的调度策略,包括该进程的所有线程
public static final native void setProcessGroup(int pid, int group)
           throws IllegalArgumentException, SecurityException;
设置线程的调度策略和优先级 针对tid。linux实现
public static final native void setThreadScheduler(int tid, int policy, int priority)
            throws IllegalArgumentException;
//设置线程的调度优先级
public static final native void setThreadPriority(int priority)
           throws IllegalArgumentException, SecurityException;

值得一提的是linux不区分进程和线程的概念。Android 中的线程对应到 Linux 内核可以看为轻量级进程,所以 Linux 为其分配资源适用 Linux 进程调度策略。其中主线程等同于应用进程的优先级。

我们为应用中各子线程设置的优先级,将直接影响到主线程在抢占各种系统资源尤其是 CPU 资源时候的优先级,所以为了保证主线程执行的顺畅,我们应尽量控制子线程的优先级。

在Android 中常见的几种异步方式 new Thread()、AysncTask、HandlerThread、ThreadPoolExecutor、IntentService。除了 AysncTask 以外,其他的创建线程的过程中,默认都是和当前线程(一般是 UI 线程)保持一样的优先级,只有 AysncTask 默认是 THREAD_PRIORITY_BACKGROUND 的优先级,所以为了保证主线程能够拥有较为优先的执行级别,建议在创建异步线程的过程中注意对优先级的控制。

5.总结

在 Android 应用状态发生变化以后,会导致进程的 oom_score_adjprocStateschedGroup 等进程状态的重新计算和设置,,并且通过 applyOomAdjLocked 方法将对应的优先级、adj、进程状态等值应用到进程上,从而改变进程的优先级和调度策略。以上的过程大概可以概括为:

  • 通过设置进程组,改变了进程所在 cgroup,

  • 通过设置调度策略实现主线程在实时优先级和普通优先级的切换,

  • 通过设置优先级改变进程 nice 值,同时在底层会改变进程所在的 cgroup。

image.png

延伸问题

  1. 什么是cgroup、线程调度策略的区别,线程优先级的应用?
  2. adj更新和lmkd是如何配合?

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值