Android 10 and higher use a control group (cgroup) abstraction layer with task profiles, which developers can use to describe a set (or sets) of restrictions to apply to a thread or a process. The system then follows the prescribed actions of the task profiles to select one or more appropriate cgroups, through which restrictions are applied, and changes to the underlying cgroup feature set can be made without affecting higher software layers.
About cgroups
Cgroups provide a mechanism for aggregating and partitioning sets of tasks (which consist of processes, threads, and all their future children) into hierarchical groups with specialized behavior. Android uses cgroups to control and account for system resources such as CPU and memory usage and allocation, with support for Linux kernel cgroups v1 and cgroups v2.
Android 9 and lower
In Android 9 and lower, the init.rc
initialization script contained the set of
available cgroups, their mounting points, and versions. While these could be
changed, the Android framework expected a specific set of cgroups to exist at
specific locations with a specific version and subgroup hierarchy, based on the
script. This limited the ability to choose the next cgroup version to use, or to
change the cgroup hierarchy to use new features.
Android 10 and higher
Android 10 and higher use cgroups with task profiles:
- Cgroup setup. Developers describe the cgroups setup in their
cgroups.json
file to define sets of cgroups, and their mounting locations and attributes. All cgroups are mounted during the early-init stage of the initialization process. - Task profiles. These provide an abstraction that decouples the required
functionality from the details of its implementation. The Android framework
applies the task profiles as described in the
task_profiles.json
file to a process or thread using theSetTaskProfiles
andSetProcessProfiles
APIs. (These APIs are unique to Android 11 and higher.)
To provide backward compatibility, the legacy functions set_cpuset_policy
,
set_sched_policy
, and get_sched_policy
provide the same API and functionality,
but their implementation has been modified to use task profiles. For new use
cases AOSP recommends using new task profiles APIs instead of the legacy
set_sched_policy
function.
Cgroups description file
Cgroups are described in the cgroups.json
file located under <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
.
Each controller is described in a subsection and must have a minimum of the following:
- Name, defined by the Controller field.
- Mounting path, defined by the Path field.
- Mode, UID (user ID), and GID (group ID) describing the owner and access modes for the files under this path (all optional).
- Optional attribute, set to true to let the system ignore the mounting error caused by a cgroup controller that the kernel doesn’t support being mounted.
Example cgroups.json file
The example below shows descriptions for cgroup v1 (Cgroups
) and cgroup v2
(Cgroups2
) controllers with their respective paths.
{
"Cgroups": [
{
"Controller": "cpu",
"Path": "/dev/cpuctl",
"Mode": "0755",
"UID": "system",
"GID": "system"
},
{
"Controller": "memory",
"Path": "/dev/memcg",
"Mode": "0700",
"Optional": true
}
],
"Cgroups2": {
"Path": "/sys/fs/cgroup",
"Mode": "0755",
"UID": "system",
"GID": "system",
"Controllers": [
{
"Controller": "freezer",
"Path": ".",
"Mode": "0755",
"UID": "system",
"GID": "system"
}
]
}
}
This example file contains two sections, Cgroups (describing the cgroup v1
controllers) and Cgroups2 (describing the cgroup v2 controllers). All
controllers in the cgroups v2 hierarchy are mounted at the same location.
Therefore, the Cgroups2 section has its own Path, Mode, UID, and
GID attributes to describe the location and attributes for the root of the
hierarchy. The Path attribute for Controllers under Cgroups2 is
relative to that root path. In Android 12 and higher you can define a cgroup
controller that's specified with path and mode as "Optional"
by setting it to true
.
The cgroups.json
file is parsed as part of the init process, during the early-init
stage, and the cgroups are mounted at the specified locations. To later obtain
the cgroup mounting locations, use the CgroupGetControllerPath
API function.
Task profiles file
The task_profiles.json
file is located under <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
.
Use it to describe a specific set of actions to be applied to a process or a
thread. A set of actions is associated with a profile name, which is used in
SetTaskProfiles
and SetProcessProfiles
calls to invoke profile actions.
Example task_profiles.json file
{
"Attributes": [
{
"Name": "MemSoftLimit",
"Controller": "memory",
"File": "memory.soft_limit_in_bytes"
},
{
"Name": "MemSwappiness",
"Controller": "memory",
"File": "memory.swappiness"
}
],
"Profiles": [
{
"Name": "MaxPerformance",
"Actions" : [
{
"Name" : "JoinCgroup",
"Params" :
{
"Controller": "schedtune",
"Path": "top-app"
}
}
]
},
{
"Name": "TimerSlackHigh",
"Actions" : [
{
"Name" : "SetTimerSlack",
"Params" :
{
"Slack": "40000000"
}
}
]
},
{
"Name": "LowMemoryUsage",
"Actions" : [
{
"Name" : "SetAttribute",
"Params" :
{
"Name" : "MemSoftLimit",
"Value" : "16MB"
}
},
{
"Name" : "SetAttribute",
"Params" :
{
"Name" : "MemSwappiness",
"Value" : "150"
}
}
]
}
]
"AggregateProfiles": [
{
"Name": "SCHED_SP_DEFAULT",
"Profiles": [ "TimerSlackHigh", "MaxPerformance" ]
},
{
"Name": "SCHED_SP_BACKGROUND",
"Profiles": [ "LowMemoryUsage" ]
}
}
Assign names to specific cgroup files as entries in your Attributes list. Each entry contains the following:
- Name field specifies the name of the Attribute.
- Controller field references a cgroup controller from the
cgroups.json
file, by its name. - File field names a specific file under this controller.
Attributes are references in task profile definitions. Outside of task profiles, use them only when the framework requires direct access to those files, and access can't be abstracted using task profiles. In all other cases, use task profiles; they provide better decoupling between required behavior and its implementation details.
The Profiles section contains task profile definitions with the following:
- Name field defines the profile name.
Actions section lists a set of actions performed when the profile is applied. Each action has the following:
- Name field specifies the action.
- Params section specifies a set of parameters for the action.
Supported actions are listed in the table:
Action | Parameter | Description |
---|---|---|
SetTimerSlack |
Slack |
Timer slack in ns |
SetAttribute |
Name |
A name referencing an attribute from the Attributes section | Value |
A value to be written to the file represented by the named attribute |
WriteFile | FilePath | path to the file | Value | a value to be written to the file |
JoinCgroup |
Controller |
A name of the cgroup controller from cgroups.json |
Path |
A sub-group path in the cgroup controller's hierarchy |
Android 12 and higher feature an AggregateProfiles section that contains aggregate profiles, each of which is an alias for a set of one or more profiles. Aggregate profile definitions consist of the following:
- Name field specifies the name of the aggregate profile.
- Profiles field lists the names of the profiles included in the aggregate profile.
When an aggregate profile is applied, all the containing profiles are also automatically applied. Aggregate profiles can contain both individual profiles or other aggregate profiles, as long as there are no recursions (a profile that includes itself).
task_profiles init language command
A task_profiles
command in the Android Init Language
is available for Android 12 and higher to facilitate
task profile activation for a specific process. It replaces the writepid
command (deprecated in Android 12) that was used to migrate a
process between cgroups. The task_profiles
command provides flexibility for
changing underlying implementations with no effect on upper layers. In the
example below, these two commands effectively perform the same operation:
writepid /dev/cpuctl/top-app/tasks
Deprecated in Android 12, This was used to write the PID of the current task into the
/dev/cpuctl/top-app/tasks
file.task_profiles MaxPerformance
Joins the current process into the top-app group under "cpu" controller (
cpuctl
), which results in writing the PID of the process todev/cpuctl/top-app/tasks
.
Always use the task_profiles
command to migrate tasks in cgroup hierarchies in
Android 12 and higher. It accepts one or more parameters, representing the
names of the profiles specified in the task_profiles.json
file.
Per API-level task profiles
In Android 12 and higher, you can amend or override
definitions in the default cgroups.json
and task_profiles.json
files, either
basing your change on the Android API level, or making it from the vendor
partition.
To override the definitions based on API level, the following files must be present on the device:
/system/etc/task_profiles/cgroups_<API level>.json
Use this for cgroups specific to an API level.
/system/etc/task_profiles/task_profiles_<API level>.json
Use this for profiles specific to an API level.
To override the definitions from the vendor partition, the following files must be present on the device:
/vendor/etc/cgroups.json
/vendor/etc/task_profiles.json
If an attribute or a profile definition in these files uses the same name as is in the default file, the file (API-level or vendor-level) definition overrides the previous definition. Note also that vendor-level definitions override API-level definitions. If the new definition has a new name, then the set of attributes or profiles is amended with the new definition.
The Android system loads the cgroup
and task_profile
files in this order:
- Default
cgroups.json
andtask_profiles.json
files. - API level-specific files, if present.
- Vendor partition files, if present.
Changes to existing API
Android 10 and higher keeps the functions set_cpuset_policy
,
set_sched_policy
, and get_sched_policy
without changes to the API.
However, Android 10 moves these functions into
libprocessgroup
, which now contains all cgroup-related functionality.
Although the cutils/sched_policy.h
header still exists, to avoid breaking
existing code ensure that new code includes a new processgroup/sched_policy.h
header instead.
Modules that use any of these functions should add dependency on the
libprocessgroup
library into their makefile. If a module doesn't use any other
libcutils
functionality, drop the libcutils
library dependency from the makefile.
Task profiles APIs
The private APIs in processgroup/processgroup.h
are defined in the table:
Type | API and definition |
---|---|
bool |
SetTaskProfiles(int tid, const std::vector
Applies the task profiles specified in profiles to the thread specified by
a thread ID (tid) using its tid parameter. |
bool |
SetProcessProfiles(uid_t uid, pid_t pid, const std::vector
Applies the task profiles specified in profiles to the process specified
by its user and process IDs using uid and pid parameters |
bool |
CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
Returns whether a cgroup controller specified by cgroup_name exists;
if true , sets the path variable to the root of that cgroup |
bool |
CgroupGetAttributePath(const std::string& attr_name, std::string* path)
Returns whether a profile attribute specified by attr_name exists; if
true , sets the path variable to the path of the file associated with
that profile attribute. |
bool |
CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)
Returns whether a profile attribute specified by attr_name exists; if
true , sets the path variable to the path of the file associated with
that profile attribute, and to the thread specified by its thread ID using
the tid parameter. |
bool |
UsePerAppMemcg()
Returns whether system is configured to use per-app memory cgroups. |