Mobile Development 23 min read

Android Process and Thread Scheduling: OOM Adjustment, Priority Levels, and Scheduling Groups

The article explains Android’s process lifecycle and how component states translate into OOM adjustments, LowMemoryKiller levels, scheduling groups, and Linux thread priorities, detailing the mapping of importance levels to oom_score_adj, schedGroup, procState, and cgroup policies, with code examples and a bug case.

iQIYI Technical Product Team
iQIYI Technical Product Team
iQIYI Technical Product Team
Android Process and Thread Scheduling: OOM Adjustment, Priority Levels, and Scheduling Groups

This article continues the series "From Linux Process Scheduling to Android Thread Management" and focuses on Android process lifecycle, OOM adjustment (oom_score_adj), LowMemoryKiller levels, and how the system maps process importance to scheduling groups.

Process Importance Levels

Foreground process

Visible process

Service process

Background process

Empty process

The importance of a process changes through various system events, which are reflected in the /proc/[pid]/oom_score_adj file (range -1000 to +1000). Older kernels used /proc/[pid]/oom_adj (range -17 to +15).

LowMemoryKiller (LMK) Levels

CACHED_APP_MAX_ADJ

CACHED_APP_MIN_ADJ

BACKUP_APP_ADJ

PERCEPTIBLE_APP_ADJ

VISIBLE_APP_ADJ

FOREGROUND_APP_ADJ

LMK kills processes starting from the highest‑adj level when memory is low.

ProcessRecord Fields

<span style="font-weight: 600; color: rgb(23, 81, 153)">int</span> maxAdj;          // Maximum OOM adjustment for this process<br/><span style="font-weight: 600; color: rgb(23, 81, 153)">int</span> curRawAdj;       // Current OOM unlimited adjustment<br/><span style="font-weight: 600; color: rgb(23, 81, 153)">int</span> setRawAdj;       // Last set OOM unlimited adjustment<br/><span style="font-weight: 600; color: rgb(23, 81, 153)">int</span> curAdj;          // Current OOM adjustment<br/><span style="font-weight: 600; color: rgb(23, 81, 153)">int</span> setAdj;          // Last set OOM adjustment<br/><span style="font-weight: 600; color: rgb(23, 81, 153)">int</span> verifiedAdj;    // Verified OOM adjustment

Process State Mapping

ActivityManager defines process_state levels that are kept in sync with oom_score_adj. The article lists the mapping between activity, service, broadcast, and content‑provider events and the resulting schedGroup, adj, and procState values.

Schedule Group Constants (ActivityManager)

<span style="font-weight: 600">static final int SCHED_GROUP_BACKGROUND = 0;</span><br/><span style="font-weight: 600">static final int SCHED_GROUP_DEFAULT = 1;</span><br/><span style="font-weight: 600">static final int SCHED_GROUP_TOP_APP = 2;</span><br/><span style="font-weight: 600">static final int SCHED_GROUP_TOP_APP_BOUND = 3;</span>

ProcessRecord also stores curSchedGroup and setSchedGroup to reflect the desired scheduling class.

Priority Changes for Activities, Services, and ContentProviders

The article provides detailed tables that show how different component states (e.g., a visible activity, a foreground service, a heavy‑weight process, a home/launcher process, a recent content‑provider) map to adj, schedGroup, and procState. It also explains the handling of bind‑service flags such as BIND_WAIVE_PRIORITY, BIND_NOT_FOREGROUND, BIND_IMPORTANT, and BIND_ADJUST_WITH_ACTIVITY.

Key code excerpt for service binding:

<span style="font-weight: 600">if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {<br/>    if ((cr.flags & Context.BIND_NOT_FOREGROUND) == 0) {<br/>        if (client.curSchedGroup > schedGroup) {<br/>            if ((cr.flags & Context.BIND_IMPORTANT) != 0) {<br/>                schedGroup = client.curSchedGroup;<br/>            } else {<br/>                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;<br/>            }<br/>        }<br/>    }<br/>}</span>

Similar logic is shown for content‑provider handling and recent‑provider boosting.

Thread Priority Mapping (Java ↔ Linux Nice)

Java thread priorities (1‑10) are mapped to Linux nice values via Thread.setNativePriority. The mapping table is:

Java Priority

Nice Value

1

19

2

16

3

13

4

10

5

0

6

-2

7

-4

8

-5

9

-6

10

-8

Developers can also set thread priority via Process.setThreadPriority(int), which directly changes the Linux nice value.

Applying OOM Adjustment and Scheduling Changes

After the computeOomAdjLocked calculation (≈700 lines), applyOomAdjLocked updates adj, procState, and schedGroup. The code then maps schedGroup to a Linux thread group ( THREAD_GROUP_BG_NONINTERACTIVE, THREAD_GROUP_TOP_APP, or THREAD_GROUP_DEFAULT) and updates cgroups and scheduling policies for all tasks of the process.

if (app.setSchedGroup != app.curSchedGroup) {<br/>    int oldSchedGroup = app.setSchedGroup;<br/>    app.setSchedGroup = app.curSchedGroup;<br/>    // setProcessGroup() updates cgroup for every task<br/>    setProcessGroup(app.pid, processGroup);<br/>    // Adjust UI thread priority when the app becomes top<br/>    if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {<br/>        scheduleAsFifoPriority(app.pid, true);<br/>        if (app.renderThreadTid != 0) {<br/>            scheduleAsFifoPriority(app.renderThreadTid, true);<br/>        }<br/>    } else {<br/>        setThreadPriority(app.pid, 0); // reset to normal<br/>        if (app.renderThreadTid != 0) {<br/>            setThreadPriority(app.renderThreadTid, 0);<br/>        }<br/>    }<br/>}

The article concludes with a practical case: a bug where the main thread was unintentionally set to THREAD_PRIORITY_BACKGROUND, causing the UI to run at a low priority and leading to noticeable jank.

Overall, the piece gives a comprehensive view of how Android derives process priority from component lifecycle events, how those priorities are represented in oom_score_adj, and how they are enforced through Linux scheduling groups and cgroups.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

AndroidLowMemoryKillerOOM Adjustmentprocess schedulingThread Priority
iQIYI Technical Product Team
Written by

iQIYI Technical Product Team

The technical product team of iQIYI

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.