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

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

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

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

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

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

Андроид 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 описаны в файле 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 для контроллеров в 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 в виде записей в списке атрибутов . Каждая запись содержит следующее:

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

Профили задач на уровне API

В Android 12 и более поздних версиях вы можете изменять или переопределять определения в файлах cgroups.json и task_profiles.json по умолчанию, либо основываясь на уровне API Android, либо внося их из раздела поставщика.

Чтобы переопределить определения на основе уровня 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()

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