Cgroup-Abstraktionsschicht

Android 10 und höher verwenden eine Kontrollgruppen-Abstraktionsschicht (Cgroup) mit Aufgabenprofilen, die Entwickler verwenden können, um eine Reihe (oder Sätze) von Einschränkungen zu beschreiben, die auf einen Thread oder einen Prozess angewendet werden sollen. Das System folgt dann den vorgeschriebenen Aktionen der Aufgabenprofile, um eine oder mehrere geeignete Kontrollgruppen auszuwählen, über die Einschränkungen angewendet werden und Änderungen am zugrunde liegenden Kontrollgruppen-Funktionssatz vorgenommen werden können, ohne dass sich dies auf höhere Softwareschichten auswirkt.

Über cgroups

Cgroups bieten einen Mechanismus zum Aggregieren und Partitionieren von Aufgabensätzen (die aus Prozessen, Threads und allen ihren zukünftigen untergeordneten Elementen bestehen) in hierarchische Gruppen mit speziellem Verhalten. Android verwendet cgroups, um Systemressourcen wie CPU- und Speichernutzung und -zuweisung zu steuern und zu berücksichtigen, mit Unterstützung für Linux-Kernel cgroups v1 und cgroups v2 .

Android 9 und niedriger

In Android 9 und niedriger enthielt das Initialisierungsskript init.rc den Satz verfügbarer Kontrollgruppen, ihre Bereitstellungspunkte und Versionen. Obwohl diese geändert werden konnten, erwartete das Android-Framework basierend auf dem Skript, dass an bestimmten Standorten ein bestimmter Satz von Kontrollgruppen mit einer bestimmten Version und Untergruppenhierarchie vorhanden ist. Dies schränkte die Möglichkeit ein, die nächste zu verwendende Kontrollgruppenversion auszuwählen oder die Kontrollgruppenhierarchie zu ändern, um neue Funktionen zu verwenden.

Android 10 und höher

Android 10 und höher verwenden Cgroups mit Aufgabenprofilen:

  • Cgroup-Setup – Entwickler beschreiben das Cgroups-Setup in ihrer cgroups.json -Datei, um Gruppen von Cgroups sowie deren Bereitstellungsorte und Attribute zu definieren. Alle cgroups werden während der Early-Init-Phase des Initialisierungsprozesses gemountet.
  • Aufgabenprofile – diese stellen eine Abstraktion dar, die die erforderliche Funktionalität von den Details ihrer Implementierung entkoppelt. Das Android-Framework wendet die Aufgabenprofile wie in der Datei task_profiles.json beschrieben auf einen Prozess oder Thread an, indem es die APIs SetTaskProfiles und SetProcessProfiles verwendet. (Diese APIs gelten nur für Android 11 und höher.)

Um Abwärtskompatibilität zu gewährleisten, stellen die Legacy-Funktionen set_cpuset_policy , set_sched_policy und get_sched_policy dieselbe API und Funktionalität bereit, ihre Implementierung wurde jedoch geändert, um Aufgabenprofile zu verwenden. Für neue Anwendungsfälle empfiehlt AOSP die Verwendung neuer Aufgabenprofil-APIs anstelle der alten Funktion set_sched_policy .

Cgroups-Beschreibungsdatei

Kontrollgruppen werden in der Datei cgroups.json beschrieben, die sich unter <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ befindet. Jeder Controller wird in einem Unterabschnitt beschrieben und muss mindestens über Folgendes verfügen:

  • Name, definiert durch das Controller- Feld.
  • Montagepfad, definiert durch das Feld „Pfad“ .
  • Modus , UID (Benutzer-ID) und GID (Gruppen-ID), die den Besitzer und die Zugriffsmodi für die Dateien unter diesem Pfad beschreiben (alle optional).
  • Optionales Attribut, auf „true“ gesetzt, damit das System den Mountfehler ignorieren kann, der durch einen cgroup-Controller verursacht wird, dessen Mounten der Kernel nicht unterstützt.

Beispieldatei cgroups.json

Das folgende Beispiel zeigt Beschreibungen für die Controller cgroup v1 ( Cgroups ) und cgroup v2 ( 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 (beschreibt die cgroup v1-Controller) und Cgroups2 (beschreibt die cgroup v2-Controller). Alle Controller in der cgroups v2-Hierarchie werden am selben Ort bereitgestellt. Daher verfügt der Abschnitt „Cgroups2“ über seine eigenen Attribute „Path “, „Mode “, „UID “ und „GID“ , um den Speicherort und die Attribute für die Wurzel der Hierarchie zu beschreiben. Das Path- Attribut für Controller 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 ist, indem Sie ihn auf true setzen.

Die cgroups.json Datei wird als Teil des Init-Prozesses während der frühen Init-Phase analysiert und die cgroups werden an den angegebenen Speicherorten bereitgestellt. Um später die Cgroup-Montageorte zu erhalten, verwenden Sie die API-Funktion CgroupGetControllerPath .

Aufgabenprofildatei

Die Datei task_profiles.json befindet sich unter <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ . Verwenden Sie es, um einen bestimmten Satz von Aktionen zu beschreiben, die auf einen Prozess oder einen Thread angewendet werden sollen. Einem Profilnamen ist eine Reihe von Aktionen zugeordnet, die in SetTaskProfiles und SetProcessProfiles Aufrufen zum Aufrufen von Profilaktionen verwendet werden.

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 Ihrer Attributliste zu. Jeder Eintrag enthält Folgendes:

  • Namensfeld – gibt den Namen des Attributs an.
  • Controller- Feld – verweist anhand seines Namens auf einen Cgroup-Controller aus der Datei cgroups.json .
  • Dateifeld – benennt eine bestimmte Datei unter diesem Controller.

Attribute sind Referenzen in Aufgabenprofildefinitionen. Verwenden Sie sie außerhalb von Aufgabenprofilen nur , wenn das Framework direkten Zugriff auf diese Dateien erfordert und der Zugriff nicht mithilfe von Aufgabenprofilen abstrahiert werden kann. In allen anderen Fällen verwenden Sie Aufgabenprofile; Sie sorgen für eine bessere Entkopplung zwischen erforderlichem Verhalten und seinen Implementierungsdetails.

Der Abschnitt „Profile“ enthält Aufgabenprofildefinitionen mit Folgendem:

  • Namensfeld – definiert den Profilnamen.
  • Abschnitt „Aktionen“ – listet eine Reihe von Aktionen auf, die ausgeführt werden, wenn das Profil angewendet wird. Jede Aktion hat Folgendes:

    • Namensfeld , das die Aktion angibt
    • Params- Abschnitt, der eine Reihe von Parametern für die Aktion angibt

Unterstützte Aktionen sind in der folgenden Tabelle aufgeführt.

Aktion Parameter Beschreibung
SetTimerSlack Slack Timer-Schlupf in ns
SetAttribute Name Ein Name, der auf ein Attribut aus dem Abschnitt „Attribute“ verweist
Value Ein Wert, der in die durch das benannte Attribut dargestellte Datei geschrieben werden soll
WriteFile FilePath Pfad zur Datei
Value ein 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

Android 12 und höher verfügen über einen AggregateProfiles- Abschnitt, der aggregierte Profile enthält, von denen jedes ein Alias ​​für einen Satz von einem oder mehreren Profilen ist. Aggregierte Profildefinitionen bestehen aus Folgendem:

  • Namensfeld – gibt den Namen des Aggregatprofils an.
  • Feld „Profile“ – listet die Namen der im Aggregatprofil enthaltenen Profile auf.

Wenn ein Aggregatprofil angewendet wird, werden automatisch auch alle enthaltenen Profile angewendet. Aggregatprofile können sowohl einzelne Profile als auch andere Aggregatprofile enthalten, solange es keine Rekursionen gibt (ein Profil, das sich selbst einschließt).

task_profiles init-Sprachbefehl

Für Android 12 und höher ist ein task_profiles Befehl in der Android-Init-Sprache verfügbar, um die Aktivierung von Aufgabenprofilen für einen bestimmten Prozess zu erleichtern. Es ersetzt den Befehl writepid (in Android 12 veraltet), der zum Migrieren eines Prozesses zwischen Kontrollgruppen verwendet wurde. Der Befehl task_profiles bietet Flexibilität zum Ändern zugrunde liegender Implementierungen ohne Auswirkungen auf die oberen Ebenen. Im folgenden Beispiel führen diese beiden Befehle praktisch denselben Vorgang aus:

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

    In Android 12 veraltet – 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 Top-App-Gruppe unter dem „CPU“-Controller ( cpuctl ) hinzu, was dazu führt, dass die PID des Prozesses in dev/cpuctl/top-app/tasks geschrieben wird.

Verwenden Sie immer den Befehl task_profiles , um Aufgaben in Cgroup-Hierarchien in Android 12 und höher zu migrieren. Es 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, indem Sie Ihre Änderung entweder auf der Android-API-Ebene basieren oder sie über die Herstellerpartition vornehmen.

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

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

    Verwenden Sie dies für Kontrollgruppen, die für eine API-Ebene spezifisch sind.

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

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

Um die Definitionen der Herstellerpartition 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 verwendet wie in der Standarddatei, überschreibt die Dateidefinition (API- oder Anbieterebene) die vorherige Definition. Beachten Sie auch, dass Definitionen auf Anbieterebene Vorrang vor Definitionen auf API-Ebene haben. Wenn die neue Definition einen neuen Namen hat, wird der Satz von Attributen oder Profilen mit der neuen Definition geändert.

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

  1. Standarddateien cgroups.json und task_profiles.json .
  2. API-Level-spezifische Dateien, falls vorhanden.
  3. Partitionsdateien des Herstellers, falls vorhanden.

Änderungen an der bestehenden API

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

Obwohl der Header cutils/sched_policy.h noch vorhanden ist, stellen Sie sicher, dass neuer Code stattdessen einen neuen Header processgroup/sched_policy.h enthält, um eine Beschädigung des vorhandenen Codes zu vermeiden.

Module, die eine dieser Funktionen verwenden, sollten in ihrem Makefile eine Abhängigkeit von der libprocessgroup Bibliothek hinzufügen. Wenn ein Modul keine andere libcutils Funktionalität verwendet, löschen Sie die Abhängigkeit der libcutils Bibliothek aus dem Makefile.

Aufgabenprofil-APIs

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

Typ API und Definition
bool SetTaskProfiles(int tid, const std::vector & profiles) SetTaskProfiles(int tid, const std::vector & profiles)

Wendet die in profiles angegebenen Aufgabenprofile auf den Thread an, der durch eine Thread-ID (tid) mithilfe seines tid Parameters angegeben wird.

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

Wendet die in profiles angegebenen Aufgabenprofile auf den Prozess an, der durch seine Benutzer- und Prozess-IDs unter Verwendung der Parameter uid “ und pid angegeben wird

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

Gibt zurück, ob ein durch cgroup_name angegebener cgroup-Controller vorhanden ist; Wenn true , wird die path auf das Stammverzeichnis dieser Kontrollgruppe gesetzt

bool CgroupGetAttributePath(const std::string& attr_name, std::string* path)

Gibt zurück, ob ein durch attr_name angegebenes Profilattribut vorhanden ist; Wenn true , wird die path auf den Pfad der Datei gesetzt, die diesem Profilattribut zugeordnet ist.

bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)

Gibt zurück, ob ein durch attr_name angegebenes Profilattribut vorhanden ist; Wenn true , wird die path auf den Pfad der Datei gesetzt, die diesem Profilattribut zugeordnet ist, und auf den Thread, der durch seine Thread-ID unter Verwendung des tid Parameters angegeben wird.

bool UsePerAppMemcg()

Gibt zurück, ob das System für die Verwendung von Arbeitsspeichergruppen pro Anwendung konfiguriert ist.