一:概念
cgroup,其名称源自控制组群(control group)的简写,是Linux内核的一个功能,用来限制、控制与分离一个进程组的资源(如CPU、内存、磁盘输入输出等)。
二:名词

相互关系
1.每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认 cgroup(我们称之为 root cgroup ,此cgroup在创建层级时自动创建,后面在该层级中创建的cgroup都是此cgroup的后代)的初始成员。
2.一个子系统最多只能附加到一个层级。
3.一个层级可以附加多个子系统
4.一个任务可以是多个cgroup的成员,但是这些cgroup必须在不同的层级。
5.系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在 cgroup 的成员。然后可根据需要将该子任务移动到不同的 cgroup 中,但开始时它总是继承其父任务的cgroup。
三:子系统

四:cgroup描述文件
cgroup 在 cgroups.json 文件(位于/system/core/libprocessgroup/profiles/ 下)中描述。各个控制器在子部分中描述,且必须至少包含以下内容:
名称,由 Controller 字段定义。
装载路径,由 Path 字段定义。
Mode、UID(用户 ID)和 GID(组 ID),用于描述该路径下文件的所有者模式和访问模式(均为可选字段)。
Optional 属性,将其设置为 true,让系统忽略内核不支持装载的 cgroup 控制器引起的装载错误。
需要注意的是,cgroups.json文件可能不止一个:
/system/core/libprocessgroup/profiles/cgroups.json //默认文件
/system/core/libprocessgroup/profiles/cgroups_<API level>.json //API级别的文件
/vendor/xxx/cgroups.json //vendor自定义的文件
这三个文件加载的顺序是: 默认–> API级别 --> vendor,于是就存在一个覆盖的流程。只要后面一个文件中定义的"Controller"与前面的字符串相同,就会覆盖前者的定义。
五:cgroup任务配置文件
task_profiles.json 文件位于 /system/core/libprocessgroup/profiles/ 下。该文件用于描述要应用于进程或线程的一组特定操作。这组操作与一个配置文件名称相关联,后者在 SetTaskProfiles 和 SetProcessProfiles 调用中用于调用配置文件操作。task_profiles.json主要由三部分组成, Attributes, Profiles和AggregateProfiles。
Attributes 是任务配置文件定义中的引用。在任务配置文件之外,仅当框架需要直接访问相应文件且无法使用任务配置文件抽象访问时,才应使用属性。在所有其他情况下,请使用任务配置文件;它们可以更好地分离所需行为及其实现详情。作为 Attributes 列表中的条目,每个条目都包含以下内容:
Name 字段 - 指定 Attribute 的名称。
Controller 字段 - 按名称引用 cgroups.json 文件中的 cgroup 控制器。
File 字段 - 为相应控制器下的特定文件命名。
Profiles 部分使用以下字段来包含任务配置文件定义:
Name 字段 - 定义配置文件的名称。
Actions 部分 - 列出了应用配置文件后执行的一组操作。每项操作都包含以下几项:
Name 字段,用于指定操作
Params 部分,用于指定操作的一组参数
Android 12 及更高版本具有一个 AggregateProfiles 部分,其中包含聚合配置文件,每个聚合配置文件都是一个或多个配置文件的别名。聚合配置文件定义由以下内容组成:
Name 字段 - 指定聚合配置文件的名称。
Profiles 字段 - 列出聚合配置文件中包含的配置文件的名称。
task_profiles.json也可能不止一个:
/system/core/libprocessgroup/profiles/task_profiles.json
/system/core/libprocessgroup/profiles/task_profiles_<API>.json
/vendor/xxx/task_profiles.json
加载、覆盖的顺序和cgroups.json类似,按照"Name"来匹配,只要两个文件中定义了同名项,后者就会覆盖前者的定义。
六:cgroup应用示例
6.1 cache进程冻结就是通过cgroup的freezer子系统来实现的,具体调用流程可查看Android墓碑机制(AndroidU)_getprocessfreezeinfo-优快云博客
6.2 如何修改surfaceflinger对应的cpuset (PS:之前有碰到surfaceflinger绘制不及时导致卡顿的问题,正好这里说下)
6.2.1 adb shell ps -A |grep surfaceflinger ,找到surfaceflinger对应的pid,假设pid为2000
6.2.2 adb shell cat /proc/2000/cgroup 可以看到 3:cpuset:/system-background ,也就是surfaceflinger对应的cpuset是system-background
6.2.3 adb shell cat /dev/cpuset/system-background/cpus 结果为0-3, 此项目0-3为小核,即system-background只允许运行在小核上
6.2.4 接下来查看surfaceflinger代码
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp,发现在init时,有绑定profiles的动作
void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
...
// Set SF main policy after initializing RenderEngine which has its own policy.
if (!SetTaskProfiles(0, {"SFMainPolicy"})) {
ALOGW("Failed to set main task profile");
}
...
}
6.2.5 查看task_profiles.json,找到SFMainPolicy对应的profiles
{
"Name": "SFMainPolicy",
"Actions": [
{
"Name": "JoinCgroup",
"Params":
{
"Controller": "cpuset",
"Path": "system-background"
}
}
]
},
这里可以看到SFMainPolicy对应的cpuset就是system-background,把这里的system-background修改为foreground,查看trace,发现surfaceflinger可以跑在大核了,查看surfaceflinger对应的cgroup,cpuset也从system-background变成了foreground
七:番外篇
cgroup子系统中,我用的比较多的是cpuset,这里简单介绍下cpuset。cpuset可以控制task可以运行在哪些CPU上。具体可以在adb shell , dev/cpuset中查看

像background、foreground、restricted、system-background、top-app等,都是很常用的分组,打开background目录

其中cpus节点保存的就是这个background可以使用哪些CPU,tasks保存的是background所属的所有task。
2024

被折叠的 条评论
为什么被折叠?



