Android 10 и выше используют уровень абстракции контрольной группы (cgroup) с профилями задач, которые разработчики могут использовать для описания набора (или наборов) ограничений для применения к потоку или процессу. Затем система следует предписанным действиям профилей задач, чтобы выбрать одну или несколько соответствующих cgroups, через которые применяются ограничения, и изменения в базовый набор функций cgroup могут быть внесены без влияния на более высокие уровни программного обеспечения.
О группах
Cgroups предоставляют механизм для агрегации и разбиения наборов задач (состоящих из процессов, потоков и всех их будущих потомков) на иерархические группы со специализированным поведением. Android использует cgroups для контроля и учета системных ресурсов, таких как использование и распределение ЦП и памяти, с поддержкой cgroups v1 и cgroups v2 ядра Linux.
Android 9 и ниже
В Android 9 и ниже скрипт инициализации init.rc
содержал набор доступных cgroups, их точек монтирования и версий. Хотя их можно было изменить, фреймворк Android ожидал, что определенный набор cgroups будет существовать в определенных местах с определенной версией и иерархией подгрупп на основе скрипта. Это ограничивало возможность выбора следующей версии cgroup для использования или изменения иерархии cgroup для использования новых функций.
Android 10 и выше
Android 10 и выше используют cgroups с профилями задач:
- Настройка cgroup. Разработчики описывают настройку cgroups в своем файле
cgroups.json
, чтобы определить наборы cgroups, а также их места монтирования и атрибуты. Все cgroups монтируются на ранней стадии процесса инициализации. - Профили задач. Они предоставляют абстракцию, которая отделяет требуемую функциональность от деталей ее реализации. Фреймворк Android применяет профили задач, как описано в файле
task_profiles.json
, к процессу или потоку с помощью APISetTaskProfiles
иSetProcessProfiles
. (Эти API уникальны для Android 11 и выше.)
Для обеспечения обратной совместимости устаревшие функции set_cpuset_policy
, set_sched_policy
и get_sched_policy
предоставляют тот же API и функциональность, но их реализация была изменена для использования профилей задач. Для новых вариантов использования AOSP рекомендует использовать новые API профилей задач вместо устаревшей функции set_sched_policy
.
Файл описания Cgroups
Cgroups описаны в файле cgroups.json
, расположенном в <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
. Каждый контроллер описан в подразделе и должен иметь как минимум следующее:
- Имя, определяемое полем Контроллер .
- Путь монтирования, определяемый полем Путь .
- Mode , UID (идентификатор пользователя) и GID (идентификатор группы), описывающие владельца и режимы доступа для файлов по этому пути (все необязательно).
- Необязательный атрибут, установленный в значение true , позволяет системе игнорировать ошибку монтирования, вызванную контроллером cgroup, монтирование которого ядром не поддерживается.
Пример файла cgroups.json
В примере ниже показаны описания контроллеров cgroup v1 ( Cgroups
) и cgroup v2 ( Cgroups2
) с соответствующими путями.
{
"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"
}
]
}
}
Этот пример файла содержит два раздела: Cgroups (описывающий контроллеры cgroup v1) и Cgroups2 (описывающий контроллеры cgroup v2). Все контроллеры в иерархии cgroups v2 монтируются в одном и том же месте. Поэтому раздел Cgroups2 имеет свои собственные атрибуты Path , Mode , UID и GID для описания местоположения и атрибутов корня иерархии. Атрибут Path для Controllers в Cgroups2 относится к этому корневому пути. В Android 12 и выше вы можете определить контроллер cgroup, указанный с path и mode как "Optional"
, установив его в true
.
Файл cgroups.json
анализируется как часть процесса init на ранней стадии init, и cgroups монтируются в указанных местах. Чтобы позже получить места монтирования cgroup, используйте функцию API CgroupGetControllerPath
.
Файл профилей задач
Файл task_profiles.json
находится в <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
. Используйте его для описания определенного набора действий, которые будут применены к процессу или потоку. Набор действий связан с именем профиля, которое используется в вызовах SetTaskProfiles
и SetProcessProfiles
для вызова действий профиля.
Пример файла task_profiles.json
{
"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" ]
}
}
Назначьте имена определенным файлам cgroup как записям в вашем списке атрибутов . Каждая запись содержит следующее:
- Поле «Имя» указывает имя атрибута.
- Поле Controller ссылается на контроллер cgroup из файла
cgroups.json
по его имени. - Поле «Файл» указывает конкретный файл в этом контроллере.
Атрибуты являются ссылками в определениях профилей задач. За пределами профилей задач используйте их только тогда, когда фреймворк требует прямого доступа к этим файлам, и доступ не может быть абстрагирован с помощью профилей задач. Во всех остальных случаях используйте профили задач; они обеспечивают лучшую развязку между требуемым поведением и деталями его реализации.
Раздел «Профили» содержит определения профилей задач со следующими данными:
- Поле «Имя» определяет имя профиля.
Раздел «Действия» содержит набор действий, выполняемых при применении профиля. Каждое действие имеет следующее:
- Поле «Имя» определяет действие.
- Раздел Params определяет набор параметров для действия.
Поддерживаемые действия перечислены в таблице:
Действие | Параметр | Описание |
---|---|---|
SetTimerSlack | Slack | Таймер завис в нс |
SetAttribute | Name | Имя, ссылающееся на атрибут из раздела «Атрибуты» | Value | Значение, которое должно быть записано в файл, представленный именованным атрибутом. |
WriteFile | FilePath | путь к файлу | Value | значение, которое будет записано в файл |
JoinCgroup | Controller | Имя контроллера cgroup из cgroups.json |
Path | Путь подгруппы в иерархии контроллера cgroup |
В Android 12 и выше есть раздел AggregateProfiles , содержащий профили агрегатов, каждый из которых является псевдонимом для набора из одного или нескольких профилей. Определения профилей агрегатов состоят из следующего:
- Поле «Имя» указывает имя совокупного профиля.
- В поле «Профили» перечислены названия профилей, включенных в совокупный профиль.
При применении совокупного профиля все содержащие его профили также применяются автоматически. Совокупные профили могут содержать как индивидуальные профили, так и другие совокупные профили, пока нет рекурсий (профиль, включающий себя).
task_profiles команда языка инициализации
Команда task_profiles
в Android Init Language доступна для Android 12 и выше для упрощения активации профиля задачи для определенного процесса. Она заменяет команду writepid
(устарела в Android 12), которая использовалась для миграции процесса между cgroups. Команда task_profiles
обеспечивает гибкость для изменения базовых реализаций без влияния на верхние уровни. В примере ниже эти две команды фактически выполняют одну и ту же операцию:
writepid /dev/cpuctl/top-app/tasks
Устарело в Android 12. Использовалось для записи PID текущей задачи в файл
/dev/cpuctl/top-app/tasks
.task_profiles MaxPerformance
Присоединяет текущий процесс к группе top-app под контроллером "cpu" (
cpuctl
), что приводит к записи PID процесса вdev/cpuctl/top-app/tasks
.
Всегда используйте команду task_profiles
для миграции задач в иерархиях cgroup в Android 12 и выше. Она принимает один или несколько параметров, представляющих имена профилей, указанных в файле task_profiles.json
.
Профили задач на уровне API
В Android 12 и более поздних версиях вы можете изменять или переопределять определения в файлах cgroups.json
и task_profiles.json
по умолчанию, либо основывая изменения на уровне API Android, либо внося их из раздела поставщика.
Для переопределения определений на основе уровня API на устройстве должны присутствовать следующие файлы:
/system/etc/task_profiles/cgroups_<API level>.json
Используйте это для контрольных групп, специфичных для определенного уровня API.
/system/etc/task_profiles/task_profiles_<API level>.json
Используйте это для профилей, специфичных для определенного уровня API.
Для переопределения определений из раздела поставщика на устройстве должны присутствовать следующие файлы:
-
/vendor/etc/cgroups.json
-
/vendor/etc/task_profiles.json
Если определение атрибута или профиля в этих файлах использует то же имя, что и в файле по умолчанию, определение файла (уровня API или уровня поставщика) переопределяет предыдущее определение. Обратите внимание также, что определения уровня поставщика переопределяют определения уровня API. Если новое определение имеет новое имя, то набор атрибутов или профилей изменяется с новым определением.
Система Android загружает файлы cgroup
и task_profile
в следующем порядке:
- Файлы
cgroups.json
иtask_profiles.json
по умолчанию. - Файлы, специфичные для уровня API, если они имеются.
- Файлы разделов поставщика, если они есть.
Изменения в существующем API
Android 10 и выше сохраняет функции set_cpuset_policy
, set_sched_policy
и get_sched_policy
без изменений в API. Однако Android 10 перемещает эти функции в libprocessgroup
, которая теперь содержит всю функциональность, связанную с cgroup.
Хотя заголовок cutils/sched_policy.h
все еще существует, чтобы избежать нарушения существующего кода, убедитесь, что новый код включает в себя новый заголовок processgroup/sched_policy.h
.
Модули, использующие любую из этих функций, должны добавить зависимость от библиотеки libprocessgroup
в свой makefile. Если модуль не использует никакой другой функционал libcutils
, удалите зависимость от библиотеки libcutils
из makefile.
API-интерфейсы профилей задач
Частные API в processgroup/processgroup.h
определены в таблице:
Тип | API и определение |
---|---|
bool | SetTaskProfiles(int tid, const std::vector Применяет профили задач, указанные в profiles к потоку, указанному идентификатором потока (tid), используя его параметр tid . |
bool | SetProcessProfiles(uid_t uid, pid_t pid, const std::vector Применяет профили задач, указанные в profiles к процессу, указанному его пользователем, и идентификаторы процесса, используя параметры uid и pid |
bool | CgroupGetControllerPath(const std::string& cgroup_name, std::string* path) Возвращает, существует ли контроллер cgroup, указанный cgroup_name ; если true , устанавливает переменную path в корень этой cgroup |
bool | CgroupGetAttributePath(const std::string& attr_name, std::string* path) Возвращает, существует ли атрибут профиля, указанный attr_name ; если true , устанавливает переменную path на путь к файлу, связанному с этим атрибутом профиля. |
bool | CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path) Возвращает, существует ли атрибут профиля, указанный attr_name ; если true , устанавливает переменную path на путь к файлу, связанному с этим атрибутом профиля, и на поток, указанный его идентификатором потока с помощью параметра tid . |
bool | UsePerAppMemcg() Возвращает информацию о том, настроена ли система на использование контрольных групп памяти для каждого приложения. |