Advanced OS Customizations & Bootloaders

Mastering Android Cgroup v2: A ‘How-To’ Guide for Custom Resource Allocation

Google AdSense Native Placement - Horizontal Top-Post banner

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, and freezer.
  • 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: max and period. max is the total time (in microseconds) that processes in the cgroup can run during each period (also in microseconds). For example, 50000 100000 means 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, and nr_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.rc scripts 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 io controller (files like io.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 →
Google AdSense Inline Placement - Content Footer banner