Уровень абстракции Cgroup

Android 10 и более поздние версии используют уровень абстракции контрольной группы (cgroup) с профилями задач, которые разработчики могут использовать для описания набора (или наборов) ограничений, применяемых к потоку или процессу. Затем система следует предписанным действиям профилей задач, чтобы выбрать одну или несколько подходящих контрольных групп, посредством которых применяются ограничения, и можно вносить изменения в базовый набор функций контрольной группы, не затрагивая более высокие уровни программного обеспечения.

О контрольных группах

Cgroups предоставляют механизм для объединения и разделения наборов задач (состоящих из процессов, потоков и всех их будущих дочерних элементов) на иерархические группы со специальным поведением. Android использует cgroups для контроля и учета системных ресурсов, таких как использование и распределение ЦП и памяти, с поддержкой cgroups v1 и cgroups v2 ядра Linux.

Андроид 9 и ниже

В Android 9 и ниже скрипт инициализации init.rc содержал набор доступных контрольных групп, их точки монтирования и версии. Хотя их можно было изменить, платформа Android ожидала, что определенный набор контрольных групп будет существовать в определенных местах с определенной версией и иерархией подгрупп на основе сценария. Это ограничивало возможность выбора следующей версии cgroup для использования или изменения иерархии cgroup для использования новых функций.

Андроид 10 и выше

Android 10 и выше используют контрольные группы с профилями задач:

  • Настройка cgroup — разработчики описывают настройку cgroups в своем файле cgroups.json , чтобы определить наборы cgroups, их места установки и атрибуты. Все контрольные группы монтируются на ранней стадии процесса инициализации.
  • Профили задач — обеспечивают абстракцию, отделяющую требуемую функциональность от деталей ее реализации. Платформа Android применяет профили задач, как описано в файле task_profiles.json , к процессу или потоку с помощью API SetTaskProfiles и 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/ . Каждый контроллер описан в подразделе и должен иметь как минимум следующее:

  • Имя, определяемое полем Controller .
  • Путь монтирования, заданный полем Path .
  • 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 для контроллеров в Cgroups2 относится к этому корневому пути. В Android 12 и более поздних версиях вы можете определить контроллер cgroup, указанный с путем и режимом, как "Optional" , установив для него значение true .

Файл cgroups.json анализируется как часть процесса инициализации на этапе ранней инициализации, и 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 в виде записей в списке атрибутов . Каждая запись содержит следующее:

  • Поле Имя - указывает имя Атрибута.
  • Поле контроллера — ссылается на контроллер 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 доступна для Android 12 и более поздних версий, чтобы облегчить активацию профиля задачи для определенного процесса. Он заменяет команду writepid (устарела в Android 12), которая использовалась для переноса процесса между контрольными группами. Команда 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 по умолчанию, основываясь либо на уровне Android API, либо в разделе поставщика.

Чтобы переопределить определения, основанные на уровне API, на устройстве должны присутствовать следующие файлы:

  • pro/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 в следующем порядке:

  1. cgroups.json и task_profiles.json по умолчанию.
  2. Файлы уровня API, если они есть.
  3. Файлы разделов производителя, если они есть.

Изменения в существующем 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 в свой make-файл. Если модуль не использует какие-либо другие функции libcutils , удалите зависимость библиотеки libcutils из make-файла.

API профилей задач

Частные API в processgroup/processgroup.h определены в таблице ниже:

Тип API и определение
bool SetTaskProfiles(int tid, const std::vector & profiles) SetTaskProfiles(int tid, const std::vector & profiles)

Применяет профили задач, указанные в profiles , к потоку, заданному идентификатором потока (tid), используя его параметр tid .

bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector & profiles) SetProcessProfiles(uid_t uid, pid_t pid, const std::vector & profiles)

Применяет профили задач, указанные в profiles , к процессу, указанному его пользователем и идентификаторами процесса, используя параметры uid и pid .

bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)

Возвращает, существует ли контроллер cgroup, указанный cgroup_name ; если true , устанавливает переменную path в корень этой контрольной группы

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()

Возвращает, настроена ли система на использование контрольных групп памяти для каждого приложения.