Cgroup-Abstraktionsebene

Android 10 und höher verwenden eine Abstraktionsschicht für eine Kontrollgruppe (Control Group, cgroup) mit Aufgabenprofilen, mit denen Entwickler eine Reihe von Einschränkungen für einen Thread oder Prozess beschreiben können. Das System führt dann die vorgeschriebenen Aktionen der Aufgabenprofile aus, um eine oder mehrere geeignete Cgroups auszuwählen, über die Einschränkungen angewendet werden. Änderungen an der zugrunde liegenden Cgroup-Funktionsgruppe können vorgenommen werden, ohne dass höhere Softwareschichten beeinträchtigt werden.

Informationen zu cgroups

Cgroups bieten einen Mechanismus zum Aggregieren und Partitionieren von Aufgaben (bestehend aus Prozessen, Threads und allen zukünftigen untergeordneten Elementen) in hierarchische Gruppen mit speziellem Verhalten. Android verwendet cgroups, um Systemressourcen wie CPU- und Arbeitsspeichernutzung und ‑zuweisung zu steuern und zu berücksichtigen. Dabei wird cgroups v1 und cgroups v2 des Linux-Kernels unterstützt.

Android 9 und niedriger

In Android 9 und niedriger enthielt das init.rc-Initialisierungsskript die verfügbaren cgroups, ihre Bereitstellungspunkte und Versionen. Diese können zwar geändert werden, das Android-Framework erwartet jedoch, dass an bestimmten Stellen eine bestimmte Gruppe von Cgroups mit einer bestimmten Version und einer bestimmten Hierarchie von Untergruppen vorhanden ist, basierend auf dem Script. Dadurch war es nicht möglich, die nächste zu verwendende cgroup-Version auszuwählen oder die cgroup-Hierarchie so zu ändern, dass neue Funktionen verwendet werden.

Android 10 und höher

Unter Android 10 und höher werden cgroups mit Aufgabenprofilen verwendet:

  • Cgroup-Einrichtung Entwickler beschreiben die Cgroups-Einrichtung in ihrer cgroups.json-Datei, um Cgroups-Sätze und ihre Bereitstellungsorte und ‑attribute zu definieren. Alle cgroups werden während der frühen Initialisierungsphase des Initialisierungsprozesses bereitgestellt.
  • Aufgabenprofile. Sie bieten eine Abstraktion, die die erforderliche Funktionalität von den Details ihrer Implementierung trennt. Das Android-Framework wendet die in der task_profiles.json-Datei beschriebenen Aufgabenprofile mithilfe der SetTaskProfiles- und SetProcessProfiles-APIs auf einen Prozess oder Thread an. Diese APIs gibt es nur für Android 11 und höher.

Aus Gründen der Abwärtskompatibilität bieten die Legacy-Funktionen set_cpuset_policy, set_sched_policy und get_sched_policy dieselbe API und dieselben Funktionen. Ihre Implementierung wurde jedoch so geändert, dass Aufgabenprofile verwendet werden. Für neue Anwendungsfälle empfiehlt AOSP die Verwendung neuer APIs für Aufgabenprofile anstelle der alten set_sched_policy-Funktion.

Cgroups-Beschreibungsdatei

Cgroups werden in der Datei cgroups.json unter <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ beschrieben. Jeder Controller wird in einem Unterabschnitt beschrieben und muss mindestens die folgenden Anforderungen erfüllen:

  • Name, definiert durch das Feld Controller.
  • Bereitstellungspfad, definiert durch das Feld Pfad.
  • Modus, UID (Nutzer-ID) und GID (Gruppen-ID), die den Inhaber und die Zugriffsmodi für die Dateien unter diesem Pfad beschreiben (alle optional).
  • Optionales Attribut. Wenn es auf true gesetzt ist, ignoriert das System den Bereitstellungsfehler, der durch einen Cgroup-Controller verursacht wird, dessen Bereitstellung vom Kernel nicht unterstützt wird.

Beispiel für eine cgroups.json-Datei

Das folgende Beispiel zeigt Beschreibungen für cgroup v1- (Cgroups) und cgroup v2-Controller (Cgroups2) mit ihren jeweiligen Pfaden.

{
  "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"
     }
   ]
 }
}

Diese Beispieldatei enthält zwei Abschnitte: Cgroups (Beschreibung der cgroup v1-Controller) und Cgroups2 (Beschreibung der cgroup v2-Controller). Alle Controller in der cgroups v2-Hierarchie werden am selben Speicherort bereitgestellt. Daher hat der Abschnitt Cgroups2 eigene Attribute Path, Mode, UID und GID, um den Speicherort und die Attribute für die Wurzel der Hierarchie zu beschreiben. Das Attribut Pfad für Controllers unter Cgroups2 ist relativ zu diesem Stammpfad. In Android 12 und höher können Sie einen cgroup-Controller definieren, der mit dem Pfad und Modus als "Optional" angegeben wird, indem Sie ihn auf true setzen.

Die Datei cgroups.json wird im Rahmen des Init-Prozesses in der frühen Init-Phase geparst und die cgroups werden an den angegebenen Speicherorten bereitgestellt. Wenn Sie die Bereitstellungsorte der cgroup später abrufen möchten, verwenden Sie die API-Funktion CgroupGetControllerPath.

Datei mit Aufgabenprofilen

Die Datei task_profiles.json befindet sich unter <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Mit diesem Befehl können Sie eine bestimmte Reihe von Aktionen beschreiben, die auf einen Prozess oder einen Thread angewendet werden sollen. Einem Profilnamen ist eine Reihe von Aktionen zugewiesen, die in SetTaskProfiles- und SetProcessProfiles-Aufrufen verwendet werden, um Profilaktionen aufzurufen.

Beispieldatei „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" ]
     }
}

Weisen Sie bestimmten cgroup-Dateien Namen als Einträge in der Liste Attribute zu. Jeder Eintrag enthält Folgendes:

  • Das Feld Name gibt den Namen des Attributs an.
  • Das Feld Controller verweist auf einen Cgroup-Controller aus der Datei cgroups.json, und zwar anhand seines Namens.
  • Das Feld Datei gibt eine bestimmte Datei unter diesem Controller an.

Attribute sind Verweise in den Definitionen von Aufgabenprofilen. Außerhalb von Aufgabenprofilen sollten Sie sie nur verwenden, wenn das Framework direkten Zugriff auf diese Dateien benötigt und der Zugriff nicht mithilfe von Aufgabenprofilen abstrahiert werden kann. Verwenden Sie in allen anderen Fällen Aufgabenprofile. Sie bieten eine bessere Entkopplung zwischen dem erforderlichen Verhalten und den Implementierungsdetails.

Der Bereich Profile enthält Definitionen für Aufgabenprofile mit folgenden Angaben:

  • Im Feld Name wird der Profilname definiert.
  • Der Abschnitt Aktionen enthält eine Reihe von Aktionen, die bei der Anwendung des Profils ausgeführt werden. Jede Aktion hat Folgendes:

    • Im Feld Name wird die Aktion angegeben.
    • Im Abschnitt Params werden eine Reihe von Parametern für die Aktion angegeben.

Die unterstützten Aktionen sind in der Tabelle aufgeführt:

Aktion Parameter Beschreibung
SetTimerSlack Slack Timer-Toleranz in ns
SetAttribute Name Ein Name, der auf ein Attribut aus dem Abschnitt Attribute verweist
Value Ein Wert, der in die Datei geschrieben werden soll, die durch das benannte Attribut dargestellt wird.
WriteFileFilePathPfad zur Datei
ValueWert, der in die Datei geschrieben wird
JoinCgroup Controller Ein Name des cgroup-Controllers von cgroups.json
Path Ein Untergruppenpfad in der Hierarchie des cgroup-Controllers

Android 12 und höher enthalten einen AggregateProfiles-Abschnitt mit aggregierten Profilen, von denen jedes ein Alias für eine Gruppe von einem oder mehreren Profilen ist. Definitionen für zusammengefasste Profile bestehen aus den folgenden Elementen:

  • Im Feld Name wird der Name des zusammengefassten Profils angegeben.
  • Im Feld Profile sind die Namen der Profile aufgeführt, die im zusammengefassten Profil enthalten sind.

Wenn ein zusammengefasstes Profil angewendet wird, werden automatisch auch alle enthaltenen Profile angewendet. Aggregierungsprofile können sowohl einzelne Profile als auch andere Aggregierungsprofile enthalten, sofern keine Rekursionen (Profile, die sich selbst enthalten) vorhanden sind.

Befehl „task_profiles init language“

Für Android 12 und höher ist der Befehl task_profiles in der Android Init-Sprache verfügbar, um die Aktivierung des Aufgabenprofils für einen bestimmten Prozess zu erleichtern. Er ersetzt den Befehl writepid (in Android 12 verworfen), der zur Migration eines Prozesses zwischen cgroups verwendet wurde. Der Befehl task_profiles bietet Flexibilität bei der Änderung der zugrunde liegenden Implementierungen, ohne dass sich dies auf die höheren Schichten auswirkt. Im folgenden Beispiel führen diese beiden Befehle dieselbe Aktion aus:

  • writepid /dev/cpuctl/top-app/tasks

    In Android 12 nicht mehr unterstützt. Damit wurde die PID der aktuellen Aufgabe in die Datei /dev/cpuctl/top-app/tasks geschrieben.

  • task_profiles MaxPerformance

    Der aktuelle Prozess wird der Top-App-Gruppe unter dem „cpu“-Controller (cpuctl) zugeordnet. Dadurch wird die PID des Prozesses in dev/cpuctl/top-app/tasks geschrieben.

Verwenden Sie immer den Befehl task_profiles, um Aufgaben in cgroup-Hierarchien in Android 12 und höher zu migrieren. Es werden ein oder mehrere Parameter akzeptiert, die die Namen der in der task_profiles.json-Datei angegebenen Profile darstellen.

Aufgabenprofile auf API-Ebene

Unter Android 12 und höher können Sie Definitionen in den Standarddateien cgroups.json und task_profiles.json ändern oder überschreiben. Sie können die Änderung entweder auf der Android API-Ebene vornehmen oder über die Anbieterpartition.

Um die Definitionen auf Grundlage des API-Levels zu überschreiben, müssen die folgenden Dateien auf dem Gerät vorhanden sein:

  • /system/etc/task_profiles/cgroups_<API level>.json

    Verwenden Sie diese Option für cgroups, die für eine API-Ebene spezifisch sind.

  • /system/etc/task_profiles/task_profiles_<API level>.json

    Verwenden Sie diese Option für Profile, die für eine API-Ebene spezifisch sind.

Wenn Sie die Definitionen aus der Anbieterpartition überschreiben möchten, müssen die folgenden Dateien auf dem Gerät vorhanden sein:

  • /vendor/etc/cgroups.json
  • /vendor/etc/task_profiles.json

Wenn ein Attribut oder eine Profildefinition in diesen Dateien denselben Namen wie in der Standarddatei hat, wird die vorherige Definition durch die Dateidefinition (auf API-Ebene oder Anbieterebene) überschrieben. Beachten Sie außerdem, dass Definitionen auf Anbieterebene Definitionen auf API-Ebene überschreiben. Wenn die neue Definition einen neuen Namen hat, wird die Gruppe der Attribute oder Profile mit der neuen Definition ergänzt.

Das Android-System lädt die Dateien cgroup und task_profile in dieser Reihenfolge:

  1. Standarddateien cgroups.json und task_profiles.json.
  2. Spezifische Dateien für API-Ebene, falls vorhanden.
  3. Anbieterpartitionsdateien, falls vorhanden.

Änderungen an der vorhandenen API

Unter Android 10 und höher werden die Funktionen set_cpuset_policy, set_sched_policy und get_sched_policy ohne Änderungen an der API beibehalten. Android 10 verschiebt diese Funktionen jedoch in libprocessgroup, das jetzt alle cgroup-bezogenen Funktionen enthält.

Der cutils/sched_policy.h-Header ist zwar weiterhin vorhanden, aber der neue Code muss stattdessen einen neuen processgroup/sched_policy.h-Header enthalten, damit der vorhandene Code nicht beschädigt wird.

Module, in denen eine dieser Funktionen verwendet wird, sollten in ihrem Makefile eine Abhängigkeit von der libprocessgroup-Bibliothek angeben. Wenn ein Modul keine andere libcutils-Funktion verwendet, löschen Sie die libcutils-Bibliotheksabhängigkeit aus dem Makefile.

APIs für Aufgabenprofile

Die privaten APIs in processgroup/processgroup.h sind in der Tabelle definiert:

Eingeben API und Definition
bool SetTaskProfiles(int tid, const std::vector& profiles)
Wendet die in profiles angegebenen Aufgabenprofile mithilfe des Parameters tid auf den Thread an, der durch eine Thread-ID (tid) angegeben ist.
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles)
Wendet die in profiles angegebenen Aufgabenprofile auf den von den Nutzer- und Prozess-IDs angegebenen Prozess an und verwendet dabei die Parameter uid und pid
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
Gibt an, ob ein mit cgroup_name angegebener cgroup-Controller vorhanden ist. Ist das der Fall (true), wird die Variable path auf den Stamm dieser cgroup gesetzt.
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path)
Gibt zurück, ob ein durch attr_name angegebenes Profilattribut vorhanden ist. Bei true wird die Variable path auf den Pfad der Datei festgelegt, die mit diesem Profilattribut verknüpft ist.
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)
Gibt an, ob ein mit attr_name angegebenes Profilattribut vorhanden ist. Wenn true, wird die Variable path auf den Pfad der Datei festgelegt, die mit diesem Profilattribut verknüpft ist, und auf den Thread, der über die Thread-ID mit dem Parameter tid angegeben ist.
bool UsePerAppMemcg()
Gibt zurück, ob das System für die Verwendung von speicherspezifischen Cgroups pro Anwendung konfiguriert ist.