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 的可能取值,这里的预定义值也是对应用进程的一种分类。

扫描二维码关注公众号,回复: 15882267 查看本文章

// 这是一个仅托管不可见活动的进程,因此它可以在没有任何干扰的情况下被终止。
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;

value ActivityManager.java ProcessList.java
0 Process.THREAD_GROUP_BACKGROUND SCHED_GROUP_BACKGROUND
1 Process.THREAD_GROUP_RESTRICTED SCHED_GROUP_RESTRICTED
2 Process.THREAD_GROUP_DEFAULT SCHED_GROUP_DEFAULT
3 Process.THREAD_GROUP_TOP_APP SCHED_GROUP_TOP_APP
4 Process.THREAD_GROUP_TOP_APP SCHED_GROUP_TOP_APP_BOUND

3.Android 进程优先级的变化

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

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

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

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

组件 方法名称 描述
Activity realStartActivityLocked 启动Activity
resumeTopActivityInnerLocked 恢复栈顶Activity
finishCurrentActivityLocked 结束当前Activity
destroyActivityLocked 摧毁当前Activity
Service realStartServiceLocked 启动服务
bindServiceLocked 绑定服务(只更新当前app)
unbindServiceLocked 解绑服务(只更新当前app)
bringDownServiceLocked 结束服务(只更新当前app)
sendServiceArgsLocked 在启动或清理服务过程中调用(只更新当前app)
Broadcast BQ.processNextBroadcast 处理下一个广播
BQ.processCurBroadcastLocked 处理当前广播
BQ.deliverToRegisteredReceiverLocked 分发已注册的广播(只更新当前app)
ContentProvider AMS.removeContentProvider 移除provider
AMS.publishContentProviders 发布provider(只更新当前app)
AMS.getContentProviderImpl 获取provider(只更新当前app)
Process setSystemProcess 创建并设置系统进程
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_NONE updateOomAdj_meh 没有特定的 OOM Adj 原因
OOM_ADJ_REASON_ACTIVITY updateOomAdj_activityChange Activity 变化导致的 OOM Adj 更新
OOM_ADJ_REASON_FINISH_RECEIVER updateOomAdj_finishReceiver 结束 Receiver 导致的 OOM Adj 更新
OOM_ADJ_REASON_START_RECEIVER updateOomAdj_startReceiver 启动 Receiver 导致的 OOM Adj 更新
OOM_ADJ_REASON_BIND_SERVICE updateOomAdj_bindService 绑定 Service 导致的 OOM Adj 更新
OOM_ADJ_REASON_UNBIND_SERVICE updateOomAdj_unbindService 解绑 Service 导致的 OOM Adj 更新
OOM_ADJ_REASON_START_SERVICE updateOomAdj_startService 启动 Service 导致的 OOM Adj 更新
OOM_ADJ_REASON_GET_PROVIDER updateOomAdj_getProvider 获取 Content Provider 导致的 OOM Adj 更新
OOM_ADJ_REASON_REMOVE_PROVIDER updateOomAdj_removeProvider 移除 Content Provider 导致的 OOM Adj 更新
OOM_ADJ_REASON_UI_VISIBILITY updateOomAdj_uiVisibility UI 可见性变化导致的 OOM Adj 更新
OOM_ADJ_REASON_WHITELIST updateOomAdj_whitelistChange 白名单变化导致的 OOM Adj 更新
OOM_ADJ_REASON_PROCESS_BEGIN updateOomAdj_processBegin 进程启动导致的 OOM Adj 更新
OOM_ADJ_REASON_PROCESS_END updateOomAdj_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官方认证微信卡片免费领取↓↓↓

猜你喜欢

转载自blog.csdn.net/Eqiqi/article/details/131538782