Cgroup-Abstraktionsschicht

In Android 10 und höher wird eine Abstraktionsebene für Kontrollgruppen (cgroups) mit Aufgabenprofilen verwendet, mit der Entwickler eine oder mehrere Einschränkungen für einen Thread oder Prozess beschreiben können. Das System folgt dann den vorgeschriebenen Aktionen der Aufgabenprofile, um eine oder mehrere geeignete cgroups auszuwählen, über die Einschränkungen angewendet werden. Änderungen an den zugrunde liegenden cgroup-Feature-Sets können vorgenommen werden, ohne dass sich dies auf höhere Softwareebenen auswirkt.

Über cgroups

Cgroups bieten einen Mechanismus zum Aggregieren und Partitionieren von Aufgabensätzen (bestehend aus Prozessen, Threads und allen ihren zukünftigen untergeordneten Elementen) in hierarchische Gruppen mit spezialisiertem Verhalten. In Android werden cgroups verwendet, um Systemressourcen wie CPU- und Arbeitsspeichernutzung und -zuweisung zu steuern und zu erfassen. Dabei werden Linux-Kernel-cgroups v1 und cgroups v2 unterstützt.

Android 9 und niedriger

In Android 9 und niedriger enthielt das Initialisierungsskript init.rc die verfügbaren cgroups, ihre Bereitstellungspunkte und Versionen. Diese konnten zwar geändert werden, aber das Android-Framework erwartete, dass sich bestimmte cgroups an bestimmten Orten mit einer bestimmten Version und Untergruppenhierarchie befinden, basierend auf dem Skript. Dadurch war die Möglichkeit eingeschränkt, die nächste zu verwendende cgroup-Version auszuwählen oder die cgroup-Hierarchie zu ändern, um neue Funktionen zu nutzen.

Android 10 und höher

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

  • Cgroup-Einrichtung : Entwickler beschreiben die cgroups-Einrichtung in der Datei cgroups.json, um Sätze von cgroups sowie ihre Bereitstellungsorte und Attribute zu definieren. Alle cgroups werden in der frühen Initialisierungsphase des Initialisierungsprozesses bereitgestellt.
  • Aufgabenprofile : Diese bieten eine Abstraktion, die die erforderliche Funktionalität von den Details der Implementierung entkoppelt. Das Android-Framework wendet die Aufgabenprofile wie in der Datei task_profiles.json beschrieben auf einen Prozess oder Thread an. Dazu werden die APIs SetTaskProfiles und SetProcessProfiles verwendet. Diese APIs sind nur in Android 11 und höher verfügbar.

Um Abwärtskompatibilität zu gewährleisten, bieten die Legacy-Funktionen set_cpuset_policy, set_sched_policy und get_sched_policy dieselbe API und Funktionalität. Ihre Implementierung wurde jedoch so geändert, dass Aufgabenprofile verwendet werden. Für neue Anwendungsfälle empfiehlt AOSP, anstelle der Legacy-Funktion set_sched_policy neue APIs für Aufgabenprofile zu verwenden.

Datei mit der Beschreibung von cgroups

Cgroups werden in der cgroups.json Datei unter <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ beschrieben. Jeder Controller wird in einem Unterabschnitt beschrieben und muss mindestens Folgendes enthalten:

  • Name, definiert durch das Feld Controller.
  • Bereitstellungspfad, definiert durch das Feld Path.
  • Mode, UID (Nutzer-ID) und GID (Gruppen-ID) zur Beschreibung des Inhabers und der Zugriffsmodi für die Dateien unter diesem Pfad (alle optional).
  • Optional -Attribut, auf true gesetzt, damit das System den Bereitstellungsfehler ignoriert, der durch einen cgroup-Controller verursacht wird, dessen Bereitstellung vom Kernel nicht unterstützt wird.

Beispieldatei cgroups.json

Im folgenden Beispiel sind Beschreibungen für cgroup v1 (Cgroups) und cgroup v2 (Cgroups2) Controller mit den jeweiligen Pfaden zu sehen.

{
  "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 Ort bereitgestellt. Daher hat der Abschnitt Cgroups2 eigene Attribute für Path, Mode, UID und GID, um den Ort und die Attribute für den Stamm der Hierarchie zu beschreiben. Das Attribut Path 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 Pfad und Modus als "Optional" angegeben wird, indem Sie ihn auf truesetzen.

Die Datei cgroups.json wird im Rahmen des Initialisierungsprozesses in der frühen Initialisierungsphase geparst und die cgroups werden an den angegebenen Orten bereitgestellt. Um die Bereitstellungsorte der cgroups später abzurufen, verwenden Sie die API-Funktion CgroupGetControllerPath.

Datei mit Aufgabenprofilen

Die task_profiles.json Datei befindet sich unter <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Verwenden Sie sie, um eine bestimmte Reihe von Aktionen zu beschreiben, die auf einen Prozess oder Thread angewendet werden sollen. Eine Reihe von Aktionen ist mit einem Profilnamen verknüpft, der in SetTaskProfiles - und SetProcessProfiles-Aufrufen verwendet wird, 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 Attributes zu. Jeder Eintrag enthält Folgendes:

  • Das Feld Name gibt den Namen des Attributs an.
  • Das Feld Controller verweist anhand des Namens auf einen cgroup-Controller aus der Datei cgroups.json.
  • Das Feld File gibt eine bestimmte Datei unter diesem Controller an.

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

Der Abschnitt Profiles enthält Definitionen von Aufgabenprofilen mit Folgendem:

  • Das Feld Name definiert den Profilnamen.
  • Im Abschnitt Actions sind eine Reihe von Aktionen aufgeführt, die beim Anwenden des Profils ausgeführt werden. Jede Aktion hat Folgendes:

    • Das Feld Name gibt die Aktion an.
    • Im Abschnitt Params ist 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-Slack in Nanosekunden
SetAttribute Name Ein Name, der auf ein Attribut im Abschnitt Attributes verweist
Value Ein Wert, der in die Datei geschrieben werden soll, die durch das benannte Attribut dargestellt wird
WriteFileFilePathPfad zur Datei
ValueEin Wert, der in die Datei geschrieben werden soll
JoinCgroup Controller Ein Name des cgroup-Controllers aus cgroups.json
Path Ein Untergruppenpfad in der Hierarchie des cgroup-Controllers

In Android 12 und höher gibt es einen Abschnitt AggregateProfiles, der Aggregatprofile enthält. Jedes davon ist ein Alias für eine Reihe von einem oder mehreren Profilen. Definitionen von Aggregatprofilen bestehen aus Folgendem:

  • Das Feld Name gibt den Namen des Aggregatprofils an.
  • Im Feld Profiles sind die Namen der Profile aufgeführt, die im Aggregatprofil enthalten sind.

Wenn ein Aggregatprofil angewendet wird, werden auch alle darin enthaltenen Profile automatisch angewendet. Aggregatprofile können sowohl einzelne Profile als auch andere Aggregatprofile enthalten, sofern keine Rekursionen vorhanden sind (ein Profil, das sich selbst enthält).

task_profiles-Befehl in der Init-Sprache

Für Android 12 und höher ist ein -Befehl in der Android-Init-Sprache verfügbar, um die Aktivierung von Aufgabenprofilen für einen bestimmten Prozess zu erleichtern.task_profiles Er ersetzt den Befehl writepid (in Android 12 verworfen), der verwendet wurde, um einen Prozess zwischen cgroups zu migrieren. Der Befehl task_profiles bietet Flexibilität bei der Änderung zugrunde liegender Implementierungen, ohne dass sich dies auf höhere Ebenen auswirkt. Im folgenden Beispiel führen diese beiden Befehle dieselbe Operation aus:

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

    In Android 12 verworfen. Dieser Befehl wurde verwendet, um die PID der aktuellen Aufgabe in die Datei /dev/cpuctl/top-app/tasks zu schreiben.

  • task_profiles MaxPerformance

    Fügt den aktuellen Prozess der Gruppe „top-app“ unter dem Controller „cpu“ (cpuctl) hinzu, wodurch die PID des Prozesses in dev/cpuctl/top-app/tasks geschrieben wird.

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

Aufgabenprofile pro API-Ebene

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

Um die Definitionen basierend auf der API-Ebene zu überschreiben, müssen die folgenden Dateien auf dem Gerät vorhanden sein:

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

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

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

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

Um die Definitionen aus der Anbieterpartition zu überschreiben, 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 verwendet, überschreibt die Definition der Datei (API-Ebene oder Anbieterebene) die vorherige Definition. 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 Dateien.
  2. Dateien, die spezifisch für die API-Ebene sind, falls vorhanden.
  3. Dateien der Anbieterpartition, falls vorhanden.

Änderungen an der vorhandenen API

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

Der Header cutils/sched_policy.h ist zwar weiterhin vorhanden, aber um zu vermeiden, dass vorhandener Code unterbrochen wird, sollte neuer Code stattdessen einen neuen Header processgroup/sched_policy.h enthalten.

Module, die eine dieser Funktionen verwenden, sollten ihrer Make-Datei eine Abhängigkeit von der Bibliothek libprocessgroup hinzufügen. Wenn ein Modul keine anderen libcutils-Funktionen verwendet, entfernen Sie die Abhängigkeit von der Bibliothek libcutils aus der Make-Datei.

APIs für Aufgabenprofile

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

Typ API und Definition
bool SetTaskProfiles(int tid, const std::vector& profiles)
Wendet die in profiles angegebenen Aufgabenprofile auf den Thread an, der durch eine Thread-ID (tid) angegeben wird. Dazu wird der Parameter tid verwendet.
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles)
Wendet die in profiles angegebenen Aufgabenprofile auf den Prozess an, der durch seine Nutzer- und Prozess-IDs angegeben wird. Dazu werden die Parameter uid und pid verwendet.
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
Gibt zurück, ob ein cgroup-Controller vorhanden ist, der durch cgroup_name angegeben wird. Wenn 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 Profilattribut vorhanden ist, das durch attr_name angegeben wird. Wenn true, wird die Variable path auf den Pfad der Datei gesetzt, die mit diesem Profilattribut verknüpft ist.
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)
Gibt zurück, ob ein Profilattribut vorhanden ist, das durch attr_name angegeben wird. Wenn true, wird die Variable path auf den Pfad der Datei gesetzt, die mit diesem Profilattribut verknüpft ist, und auf den Thread, der durch seine Thread-ID angegeben wird. Dazu wird der Parameter tid verwendet.
bool UsePerAppMemcg()
Gibt zurück, ob das System so konfiguriert ist, dass cgroups für den Arbeitsspeicher pro App verwendet werden.