Introduction to Cgroup v2 and Android Resource Management
Cgroups (control groups) are a Linux kernel feature that allows for the organization of processes into hierarchical groups, enabling resource allocation and isolation. Cgroup v2, the unified hierarchy, simplifies and enhances resource management compared to its predecessor. On Android devices, Cgroup v2 plays a crucial role in managing system resources, ensuring that background applications don’t starve foreground apps and maintaining overall system stability. As Android becomes more complex, fine-grained control over CPU, memory, and I/O becomes indispensable for advanced users seeking to optimize performance, extend battery life, or even ensure specific services receive guaranteed resources.
While Android’s default Cgroup configurations are optimized for general use, a rooted device unlocks the potential for deep customization. By understanding and manipulating Cgroup v2 policies, you can dictate exactly how your device allocates resources, giving priority to your most critical applications or limiting resource hogs.
Prerequisites for Cgroup v2 Customization
Rooted Android Device
Accessing and modifying the Cgroup filesystem requires root privileges. This means your device must be rooted, typically using solutions like Magisk or KernelSU, which provide the necessary `su` binary and mechanism to execute commands as the superuser. Without root access, you will only be able to inspect Cgroup files, not modify them.
Basic Linux Command-Line Proficiency
Familiarity with fundamental Linux commands is essential. You’ll primarily interact with your device using `adb shell` from a computer or a terminal emulator app directly on the device. Key commands include `ls` (list directory contents), `cd` (change directory), `cat` (display file contents), `echo` (write to a file), `mkdir` (create directory), and `ps` (list processes).
Exploring the Android Cgroup v2 Hierarchy
Cgroup v2 enforces a single, unified hierarchy, meaning all controllers (CPU, memory, I/O, etc.) reside within a single tree structure. The primary mount point for the Cgroup v2 filesystem on Android is typically `/sys/fs/cgroup`. Let’s verify this:
su
ls -l /sys/fs/cgroup
You should see various files and directories, confirming the Cgroup v2 hierarchy is active. The `cgroup.controllers` file at the root lists all available controllers on your system:
cat /sys/fs/cgroup/cgroup.controllers
This output might show controllers like `cpu`, `io`, `memory`, `pids`, `rdma`, `freezer`, indicating which resource types can be managed. The `cgroup.subtree_control` file in any Cgroup directory determines which controllers are enabled for its children.
Identifying and Modifying Application-Specific Cgroups
Android places each application’s processes into specific Cgroup slices, usually nested under a hierarchy like `/sys/fs/cgroup/uid_/pid_` or similar structures managed by `init` or `system_server`. To find an application’s Cgroup, you first need its Process ID (PID). Let’s use Chrome as an example:
ps -ef | grep com.android.chrome
From the output, identify the PID of the main Chrome process. Then, you can find its Cgroup path:
cat /proc/<PID>/cgroup
This will show you the path within the Cgroup hierarchy where that specific process resides. Understanding this structure is key to either modifying existing Cgroups or creating new ones to move processes into.
Implementing Custom Cgroup v2 Policies
To implement truly custom policies, it’s often best to create a new Cgroup slice. This allows for isolated resource management without interfering with Android’s default system Cgroups. Let’s create a custom slice named `custom_slice`:
Creating a New Cgroup Slice
su
mkdir /sys/fs/cgroup/custom_slice
echo "+cpu +memory +io" > /sys/fs/cgroup/custom_slice/cgroup.subtree_control
This sequence creates a new directory `/sys/fs/cgroup/custom_slice` and then enables the `cpu`, `memory`, and `io` controllers for any processes that become children of this new Cgroup.
Setting CPU Resource Limits
The `cpu.max` file controls CPU usage. It takes two values: `MAX` and `PERIOD`. `MAX` specifies the maximum CPU time (in microseconds) that processes in the Cgroup can get during each `PERIOD` (also in microseconds). For example, to limit a Cgroup to 50% CPU usage:
echo "50000 100000" > /sys/fs/cgroup/custom_slice/cpu.max
This means the processes in `custom_slice` will get 50,000 microseconds of CPU time every 100,000 microseconds (0.1 seconds).
Managing Memory Resources
Memory management in Cgroup v2 is handled by `memory.high` and `memory.max`. `memory.high` is a soft limit; when memory usage exceeds this, the kernel starts actively reclaiming memory from the Cgroup, but processes can still allocate more if available. `memory.max` is a hard limit; exceeding this will trigger the OOM (Out Of Memory) killer for processes within the Cgroup.
To set a soft memory limit of 200MB for our custom slice:
echo "200M" > /sys/fs/cgroup/custom_slice/memory.high
# Or in bytes: echo "209715200" > /sys/fs/cgroup/custom_slice/memory.high
Controlling I/O Access
The `io.weight` file controls the relative I/O priority for processes within a Cgroup. The default weight is 100. A higher value gives more I/O bandwidth, while a lower value reduces it. `io.max` provides hard I/O limits, similar to `cpu.max` but for I/O operations.
To give higher I/O priority (e.g., for a critical background syncing service):
echo "1000" > /sys/fs/cgroup/custom_slice/io.weight
Moving Processes to a Custom Cgroup
Once your Cgroup policies are defined, you need to move the target processes into it. This is done by writing the process’s PID to the `cgroup.procs` file within your custom Cgroup directory. For example, to move a specific background service:
PID=$(pgrep -f "com.example.backgroundservice")
[ -n "$PID" ] && echo "$PID" > /sys/fs/cgroup/custom_slice/cgroup.procs
Note that newly spawned child processes will inherit the Cgroup of their parent. For applications or services that might restart, you’ll need a mechanism to re-apply this command.
Ensuring Persistence Across Reboots
Changes made directly to the `/sys/fs/cgroup` filesystem are volatile and will be lost upon reboot. To make your custom policies permanent, you need to execute the commands during the device’s boot sequence.
Magisk `post-fs-data.sh` or `service.sh`
The most robust way on rooted devices is to create a Magisk module that runs a script. The `post-fs-data.sh` script (executed very early, after `/data` is mounted) is suitable for creating the Cgroup directory and setting initial policies. If you need to move processes that start later, `service.sh` (executed after `zygote` and `system_server` start) might be more appropriate.
Example `post-fs-data.sh` for a Magisk module:
#!/system/bin/sh
# Create custom Cgroup slice and enable controllers
mkdir /sys/fs/cgroup/custom_slice
echo "+cpu +memory +io" > /sys/fs/cgroup/custom_slice/cgroup.subtree_control
# Set resource limits
echo "50000 100000" > /sys/fs/cgroup/custom_slice/cpu.max
echo "200M" > /sys/fs/cgroup/custom_slice/memory.high
echo "1000" > /sys/fs/cgroup/custom_slice/io.weight
# Note: Moving PIDs here might be too early for some services.
# Consider using service.sh or a loop if the process is not yet running.
# PID=$(pgrep -f "com.example.backgroundservice")
# [ -n "$PID" ] && echo "$PID" > /sys/fs/cgroup/custom_slice/cgroup.procs
`init.d` Scripts (Legacy/Alternative)
Some custom kernels or rooting methods might support `init.d` scripts, which are shell scripts placed in `/system/etc/init.d` (or similar) that are executed during boot. However, Magisk modules are generally preferred due to their systemless nature.
Monitoring and Verification
After applying your policies, always verify them. You can simply `cat` the respective Cgroup files to confirm the values are set correctly:
su
cat /sys/fs/cgroup/custom_slice/cpu.max
cat /sys/fs/cgroup/custom_slice/memory.high
cat /sys/fs/cgroup/custom_slice/io.weight
You can also observe system behavior using tools like `top`, `htop`, or `dumpsys cpuinfo` via `adb shell` to see the effect of your changes on specific processes.
Best Practices and Troubleshooting
- Start Small: Implement and test one change at a time.
- Backup: Always perform a Nandroid backup before making significant system modifications.
- Documentation: Refer to the official Linux kernel documentation for detailed explanations of Cgroup v2 controllers and files.
- Don’t Over-Restrict: Setting overly aggressive limits can lead to system instability, application crashes, or even boot loops.
- Check Logs: If an application misbehaves, check `logcat` for any Cgroup-related errors or OOM events.
- Reboot: Sometimes a full reboot is required for all changes to take effect, especially for process migration.
Conclusion
Cgroup v2 offers an incredibly powerful and flexible mechanism for fine-grained resource management on Linux-based systems, including Android. By taking control of these kernel features on your rooted device, you can tailor your Android experience to an unprecedented degree, optimizing for performance, battery life, or specific application requirements. While the learning curve can be steep, the ability to directly influence how your device’s core resources are allocated provides a level of customization far beyond what stock Android offers. Experiment carefully, understand the implications of each parameter, and unlock the true potential of your device.
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →