В Android 10 и более поздних версиях используется абстрактный уровень группы управления (cgroup) с профилями задач, с помощью которых разработчики могут описывать наборы ограничений, применяемых к потоку или процессу. Затем система выполняет действия, описанные в профилях задач, чтобы выбрать одну или несколько подходящих групп cgroup, через которые применяются ограничения. При этом изменения в базовом наборе функций cgroup не влияют на более высокие уровни ПО.
О группах контроля
Cgroups позволяют объединять и разделять наборы задач (состоящие из процессов, потоков и всех их дочерних элементов) на иерархические группы со специальным поведением. Android использует cgroups для контроля и учета системных ресурсов, таких как использование и выделение ЦП и памяти, с поддержкой ядра Linux cgroups v1 и cgroups v2.
Android 9 и более ранних версий
В Android 9 и более ранних версиях скрипт инициализации init.rc содержал набор доступных групп cgroup, их точки подключения и версии. Хотя их можно было изменить, фреймворк Android ожидал, что определенный набор cgroup будет существовать в определенных местах с определенной версией и иерархией подгрупп на основе скрипта. Это ограничивало возможность выбора следующей версии cgroup или изменения иерархии cgroup для использования новых функций.
Android 10 и более поздних версий
В Android 10 и более поздних версий используются группы управления с профилями задач:
- Настройка групп управления ресурсами. Разработчики описывают настройку 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.json, который находится в каталоге <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/.
Каждый контроллер описан в отдельном подразделе и должен содержать как минимум следующие сведения:
- Название, указанное в поле Контроллер.
- Путь монтирования, заданный в поле Путь.
- Режим, 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 версии 1) и Cgroups2 (описывает контроллеры cgroup версии 2). Все контроллеры в иерархии cgroups v2 монтируются в одном и том же месте.
Поэтому в разделе Cgroups2 есть собственные атрибуты Path, Mode, UID и GID, описывающие местоположение и атрибуты для корня иерархии. Атрибут Path для Controllers в Cgroups2 относится к этому корневому пути. В Android 12 и более поздних версий можно задать контроллер cgroup, указанный с помощью пути и режима "Optional", установив для него значение true.
Файл cgroups.json анализируется в рамках процесса инициализации на этапе ранней инициализации, и контрольные группы монтируются в указанных местах. Чтобы получить точки подключения 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. - Поле File (Файл) содержит название определенного файла, относящегося к этому контролеру.
Атрибуты – это ссылки в определениях профилей задач. Вне профилей задач используйте их только в том случае, если фреймворку требуется прямой доступ к этим файлам и доступ нельзя абстрагировать с помощью профилей задач. Во всех остальных случаях используйте профили задач, поскольку они обеспечивают лучшее разделение между требуемым поведением и деталями его реализации.
В разделе Профили содержатся определения профилей задач со следующими элементами:
- В поле Название задается название профиля.
В разделе Действия перечислены действия, которые выполняются при применении профиля. У каждого действия есть:
- В поле Название указывается действие.
- В разделе Params указан набор параметров для действия.
Поддерживаемые действия перечислены в таблице ниже.
| Действие | Параметр | Описание |
|---|---|---|
SetTimerSlack |
Slack |
Задержка таймера в наносекундах |
SetAttribute |
Name |
Название, относящееся к атрибуту из раздела Атрибуты. |
Value |
Значение, которое будет записано в файл, представленный именованным атрибутом. | |
WriteFile | FilePath | путь к файлу; |
Value | значение, которое нужно записать в файл. | |
JoinCgroup |
Controller |
Название контроллера cgroup из cgroups.json. |
Path |
Путь к подгруппе в иерархии контроллера cgroup |
В Android 12 и более поздних версий есть раздел AggregateProfiles, в котором содержатся агрегированные профили. Каждый из них представляет собой псевдоним для набора из одного или нескольких профилей. Определения агрегированных профилей состоят из следующих элементов:
- В поле Название указывается название агрегированного профиля.
- В поле Профили перечислены названия профилей, включенных в агрегированный профиль.
При применении агрегированного профиля все входящие в него профили также применяются автоматически. Агрегированные профили могут содержать как отдельные профили, так и другие агрегированные профили, если нет рекурсий (профиль, который включает сам себя).
task_profiles init language command
В Android 12 и более поздних версиях ОС для активации профиля задачи для определенного процесса доступна команда task_profiles в языке инициализации Android. Она заменяет команду writepid (не поддерживается в Android 12), которая использовалась для переноса процесса между группами управления. Команда task_profiles позволяет изменять базовые реализации, не затрагивая верхние уровни. В приведенном ниже примере обе команды выполняют одну и ту же операцию:
writepid /dev/cpuctl/top-app/tasksУстарело в Android 12. Ранее использовалось для записи PID текущей задачи в файл
/dev/cpuctl/top-app/tasks.task_profiles MaxPerformanceДобавляет текущий процесс в группу приложений, которые больше всего нагружают процессор, в контроллере cpu (
cpuctl). В результате идентификатор процесса записывается в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Используйте это для cgroups, относящихся к уровню 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 не изменились.
Однако в Android 10 эти функции перенесены в каталог libprocessgroup, который теперь содержит все функции, связанные с cgroup.
Заголовок cutils/sched_policy.h по-прежнему существует, но, чтобы не нарушать работу существующего кода, убедитесь, что новый код включает заголовок processgroup/sched_policy.h.
Модули, в которых используются какие-либо из этих функций, должны добавить в свой файл makefile зависимость от библиотеки libprocessgroup. Если модуль не использует другие функции 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()
Возвращает информацию о том, настроена ли система на использование cgroup памяти для каждого приложения. |