A modern Android smartphone might have hundreds of threads wanting to execute code simultaneously, but it only has 8 physical CPU cores. The kernel must constantly pause and resume threads, swapping them onto the physical cores thousands of times per second.
This complex orchestration is handled by the CPU Scheduler.
The Completely Fair Scheduler (CFS)
The default scheduler for normal user-space tasks in Linux is the Completely Fair Scheduler (CFS).
CFS does not use rigid time-slices (e.g., "everyone gets exactly 10ms"). Instead, it tracks how much actual CPU time each thread has consumed. It maintains a Red-Black Tree (a highly efficient, self-balancing binary search tree) of all runnable threads, ordered by their consumed virtual runtime (vruntime).
The rule is elegantly simple: the thread sitting on the far left of the tree (the one that has had the least amount of CPU time) gets to run next.
Priorities and Nice Values
Not all Android apps are equally important. The active game you are playing needs more CPU time than the email app syncing in the background.
Android controls this using Nice Values (ranging from -20 to +19).
- A lower nice value (e.g., -10) means the process is "less nice" to others and demands more CPU time.
- A higher nice value (e.g., +10) means the process is "nice" and willingly yields the CPU to others.
The Android framework actively adjusts these values. When you minimize an app, the ActivityManagerService tells the kernel to increase the app's nice value to 10 or 19, drastically reducing its CPU allocation so the foreground app can run smoothly.
You can view the nice value of processes using top:
adb shell top -n 1
Look at the NI column. Background processes will have high positive numbers, while critical system daemons will have negative numbers.
Real-Time Scheduling
For highly sensitive tasks, CFS is not fast enough. Audio mixing requires strict millisecond precision to prevent crackling sounds.
For these tasks, Android uses Real-Time scheduling classes (SCHED_FIFO or SCHED_RR).
A real-time thread will absolutely bypass the CFS tree and instantly preempt any normal application running on the CPU. Because a rogue real-time thread can permanently freeze the entire phone, only highly privileged system daemons (like audioserver or SurfaceFlinger) are allowed to use this policy.
// Example of setting a Real-Time priority in C
struct sched_param param;
param.sched_priority = 50; // High priority
// Set the thread to SCHED_FIFO (First In, First Out)
sched_setscheduler(0, SCHED_FIFO, ¶m);
Energy-Aware Scheduling (EAS)
Mobile devices utilize big.LITTLE architectures (mixing large, power-hungry CPU cores with small, battery-efficient cores). Standard Linux schedulers were designed for servers where all CPUs are identical, and they did not understand this asymmetry.
Android actively drove the development of Energy-Aware Scheduling (EAS) in the Linux kernel. EAS mathematically predicts how much energy a thread will consume based on its historical load.
It tries to place lightweight background threads exclusively on the small cores to save battery, only waking up the massive power-hungry cores when the user touches the screen, launches an app, or starts rendering 3D graphics.