Introduction
Android, at its core, relies on the Linux kernel to manage system resources. With the advent of Cgroup v2, a powerful and unified resource management mechanism, developers and system integrators gain unprecedented control over how CPU, memory, I/O, and other resources are allocated to applications and services. This guide delves into the intricacies of Cgroup v2 on Android, providing a hands-on approach to creating custom cgroups and fine-tuning resource distribution for optimal performance, stability, and battery life.
Understanding and manipulating Cgroup v2 is crucial for advanced Android customization, especially in embedded systems, specialized devices, or when troubleshooting resource contention. We will explore its filesystem, learn how to create custom control groups, and assign specific resource limits to processes.
Understanding Cgroup v2 on Android
Cgroup v2 (control groups version 2) represents a significant evolution from Cgroup v1. While v1 allowed for multiple, independent hierarchies, v2 enforces a single, unified hierarchy, simplifying management and resolving many of the conceptual complexities of its predecessor. Android has increasingly adopted Cgroup v2, leveraging its capabilities for managing foreground/background tasks, system services, and the ActivityManager’s low memory killer (LMK).
Key Concepts:
- Unified Hierarchy: All controllers (CPU, memory, I/O, etc.) are available in a single tree.
- Controllers: Specific resource management modules like
cpu,memory,io,pid,pids,rdma, andfreezer. - Delegation: Subtrees can be delegated to unprivileged users, enabling more flexible management.
- No Internal Processes: Parent cgroups do not contain processes directly; processes reside only in leaf cgroups or those explicitly marked for delegation.
Android’s implementation often involves a root cgroup at /sys/fs/cgroup, under which various system-defined cgroups exist (e.g., /sys/fs/cgroup/system, /sys/fs/cgroup/foreground, /sys/fs/cgroup/background, /sys/fs/cgroup/top-app). These are managed by the Android system to prioritize user-facing applications.
Prerequisites for Customization
Before you begin, ensure you have the following:
- A rooted Android device.
- ADB (Android Debug Bridge) installed and configured on your host machine.
- Basic familiarity with Linux shell commands.
- Kernel support for Cgroup v2 (most modern Android kernels do, verify by checking for
/sys/fs/cgroup/cgroup.controllers).
Exploring the Cgroup v2 Filesystem
The Cgroup v2 hierarchy is mounted at /sys/fs/cgroup. Let’s inspect its structure:
adb shellsu # Grant root access on devicecd /sys/fs/cgroup# List controllers available at the rootls cgroup.controllers# Check processes associated with the root cgroupcat cgroup.procs# List immediate subdirectories (Android's default cgroups)ls -l
You’ll typically see files like cgroup.controllers (lists available controllers for this cgroup), cgroup.subtree_control (lists active controllers for immediate children), cgroup.procs (lists PIDs in this cgroup), and various controller-specific files (e.g., cpu.max, memory.max).
Step-by-Step: Creating a Custom Cgroup
Let’s create a custom cgroup named my_special_app and enable CPU and memory controllers for it.
# 1. Navigate to the root of the cgroup hierarchycd /sys/fs/cgroup# 2. Create the new cgroup directorymkdir my_special_app# 3. Enable desired controllers for the new cgroup's children# This command adds the 'cpu' and 'memory' controllers to the subtree_control file# for the *parent* cgroup (in this case, the root cgroup), # meaning they become available for use by 'my_special_app'echo "+cpu +memory" > my_special_app/cgroup.subtree_control# Verify that the controllers are active for the new cgroupcat my_special_app/cgroup.controllers
After these steps, my_special_app will have its own set of control files (e.g., my_special_app/cpu.max, my_special_app/memory.max) ready for configuration.
Managing CPU Resources
The CPU controller allows you to limit the CPU usage of processes within a cgroup. Key files are cpu.max and cpu.weight.
cpu.max: Defines a maximum CPU usage. It takes two space-separated values:maxandperiod.maxis the total time (in microseconds) that processes in the cgroup can run during eachperiod(also in microseconds). For example,50000 100000means 50ms of CPU time per 100ms period (50% CPU).cpu.weight: Defines a proportional share of CPU resources. It’s a unitless value between 1 and 10000, with 100 being the default. Higher weight means more CPU time relative to other cgroups.
Example: Restricting an App to 25% CPU
# Limit CPU to 25% (25ms out of every 100ms period)echo "25000 100000" > my_special_app/cpu.max# Set a relative weight (e.g., half of default)echo "50" > my_special_app/cpu.weight# Verify settingscat my_special_app/cpu.maxcat my_special_app/cpu.weight
Managing Memory Resources
The memory controller allows you to limit the amount of RAM a cgroup can consume. Key files include memory.max, memory.high, and memory.low.
memory.max: Absolute upper limit on memory usage (in bytes). If processes exceed this, they might be OOM-killed.memory.high: A soft limit. When memory usage exceeds this, the kernel will attempt to reclaim memory or throttle processes within the cgroup, without immediately killing them.memory.low: A minimum memory threshold that the cgroup should try to keep free.
Example: Limiting an App to 512MB RAM
# Limit memory to 512MB (512 * 1024 * 1024 bytes)echo "536870912" > my_special_app/memory.max# Set a high watermark at 400MB to trigger reclamation earlier (400 * 1024 * 1024 bytes)echo "419430400" > my_special_app/memory.high# Verify settingscat my_special_app/memory.maxcat my_special_app/memory.high
Assigning Processes to Custom Cgroups
To apply these resource limits, you must move the desired process’s PID into your custom cgroup. You’ll need to know the PID of the application or service.
# 1. Find the PID of your target application/service# Replace "com.example.myapp" with the actual package namePID=$(pidof com.example.myapp)# Or, if it's a specific process name (e.g., a service)PID=$(ps -A | grep "my_service_name" | awk '{print $2}')# 2. Assign the PID to your custom cgroup (ensure 'my_special_app' exists and controllers are active)echo $PID > /sys/fs/cgroup/my_special_app/cgroup.procs# 3. Verify the process is in the new cgroupcat /sys/fs/cgroup/my_special_app/cgroup.procs# Or inspect the process's cgroup membership directlycat /proc/$PID/cgroup
Note that if the application respawns, you may need to re-assign its new PID. For persistent control, you might integrate these commands into an init.rc script (for services launched at boot) or a custom Android service that monitors and manages PIDs.
Monitoring and Verification
After setting up your cgroups, it’s crucial to monitor their behavior:
- `cgroup.stat`: Provides statistics for the cgroup. For memory, it might show
anon,file,shmem,sock,kernel_stack, etc. - `cpu.stat`: Contains
usage_usec(total CPU time consumed),user_usec,system_usec, andnr_periods,nr_throttled,throttled_usec(useful for debugging CPU limits). - `memory.current`: Shows current memory usage in bytes.
- `top` / `htop`: If installed on your device, these tools can show real-time process CPU/memory usage.
# Get memory stats for your cgroupcat /sys/fs/cgroup/my_special_app/memory.stat# Get CPU stats for your cgroupcat /sys/fs/cgroup/my_special_app/cpu.stat# See current memory usagecat /sys/fs/cgroup/my_special_app/memory.current
Advanced Considerations
- Android’s Default Cgroups: Be mindful of how your custom cgroups interact with Android’s own resource management. Creating a sub-cgroup under
/sys/fs/cgroup/background, for instance, could inherit some of its limitations. - Persistence: Changes made via ADB are not persistent across reboots. For system-level changes, you’ll need to modify
init.rcscripts or develop a custom system service. This often involves creating new service entries or modifying existing ones to add `cgroup_path` directives. - Debugging: If limits aren’t applying, double-check permissions, ensure controllers are correctly enabled in
cgroup.subtree_control, and verify PIDs are correctly assigned. - I/O Throttling: Explore the
iocontroller (files likeio.max,io.weight) for managing disk and network I/O, which is particularly useful for bandwidth-intensive applications.
Conclusion
Mastering Cgroup v2 provides an unparalleled level of control over resource allocation on Android. By understanding its unified hierarchy and leveraging controllers like cpu and memory, you can create highly optimized environments for specific applications, enhance system stability, and even improve battery efficiency. This guide has provided a foundational ‘how-to’ for custom cgroup creation and management. With these tools, you’re empowered to fine-tune your Android device beyond standard settings, opening doors for specialized embedded systems, performance critical applications, and advanced system diagnostics.
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 →