Warstwa abstrakcji Cgroup

Android 10 i nowsze wersje korzystają z warstwy abstrakcji grupy kontrolnej (cgroup) z profilami zadań, których programiści mogą używać do opisywania zestawu (lub zestawów) ograniczeń, które można zastosować do wątku lub procesu. Następnie system postępuje zgodnie z zalecanymi działaniami profili zadań, aby wybrać jedną lub więcej odpowiednich grup cgroup, za pomocą których stosowane są ograniczenia i można wprowadzać zmiany w podstawowym zestawie funkcji grupy cgroup bez wpływu na wyższe warstwy oprogramowania.

O grupach cgroup

Grupy C zapewniają mechanizm agregowania i dzielenia zestawów zadań (które składają się z procesów, wątków i wszystkich ich przyszłych elementów potomnych) na grupy hierarchiczne o wyspecjalizowanym zachowaniu. Android używa cgroups do kontrolowania i rozliczania zasobów systemowych, takich jak użycie i alokacja procesora oraz pamięci, z obsługą cgroups v1 i cgroups v2 jądra Linuksa.

Android 9 i starsze

W systemie Android 9 i niższych skrypt inicjujący init.rc zawierał zestaw dostępnych grup c, ich punkty mocowania i wersje. Chociaż można je zmienić, środowisko Androida oczekiwało, że w określonych lokalizacjach będzie istniał określony zestaw grup c z określoną wersją i hierarchią podgrup na podstawie skryptu. Ograniczało to możliwość wyboru następnej wersji cgroup do użycia lub zmiany hierarchii cgroup w celu korzystania z nowych funkcji.

Android 10 i nowszy

Android 10 i nowsze wersje korzystają z grup cgroup z profilami zadań:

  • Konfiguracja Cgroup — programiści opisują konfigurację cgroups w swoim pliku cgroups.json w celu zdefiniowania zestawów cgroups oraz lokalizacji ich montażu i atrybutów. Wszystkie grupy cgroup są montowane na wczesnym etapie procesu inicjalizacji.
  • Profile zadań — stanowią abstrakcję oddzielającą wymaganą funkcjonalność od szczegółów jej implementacji. Struktura systemu Android stosuje profile zadań zgodnie z opisem w pliku task_profiles.json do procesu lub wątku przy użyciu interfejsów API SetTaskProfiles i SetProcessProfiles . (Te interfejsy API są unikalne dla Androida 11 i nowszych wersji).

Aby zapewnić kompatybilność wsteczną, starsze funkcje set_cpuset_policy , set_sched_policy i get_sched_policy zapewniają ten sam interfejs API i funkcjonalność, ale ich implementacja została zmodyfikowana w celu korzystania z profili zadań. W nowych przypadkach AOSP zaleca używanie nowych interfejsów API profili zadań zamiast starszej funkcji set_sched_policy .

Plik opisu grup Cgroup

Grupy C są opisane w pliku cgroups.json znajdującym się w lokalizacji <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ . Każdy kontroler jest opisany w podrozdziale i musi posiadać co najmniej następujące elementy:

  • Nazwa zdefiniowana przez pole Kontroler .
  • Ścieżka montażowa zdefiniowana w polu Ścieżka .
  • Mode , UID (identyfikator użytkownika) i GID (identyfikator grupy) opisujące właściciela i tryby dostępu do plików w tej ścieżce (wszystkie opcjonalne).
  • Atrybut opcjonalny , ustawiony na true , aby system ignorował błąd montowania spowodowany przez kontroler cgroup, którego montowanie nie jest obsługiwane przez jądro.

Przykładowy plik cgroups.json

Poniższy przykład pokazuje opisy kontrolerów cgroup v1 ( Cgroups ) i cgroup v2 ( Cgroups2 ) wraz z ich odpowiednimi ścieżkami.

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

Ten przykładowy plik zawiera dwie sekcje, Cgroups (opisujące kontrolery cgroup v1) i Cgroups2 (opisujące kontrolery cgroup v2). Wszystkie kontrolery w hierarchii cgroups v2 są zamontowane w tej samej lokalizacji. Dlatego sekcja Cgroups2 ma własne atrybuty Path , Mode , UID i GID opisujące lokalizację i atrybuty katalogu głównego hierarchii. Atrybut Path dla kontrolerów w Cgroups2 jest względny w stosunku do tej ścieżki głównej. W Androidzie 12 i nowszych możesz zdefiniować kontroler cgroup, który jest określony ze ścieżką i trybem jako "Optional" , ustawiając go na true .

Plik cgroups.json jest analizowany w ramach procesu inicjowania na wczesnym etapie inicjowania, a grupy cgroups są montowane w określonych lokalizacjach. Aby później uzyskać lokalizacje montażu cgroup, użyj funkcji API CgroupGetControllerPath .

Plik profili zadań

Plik task_profiles.json znajduje się w lokalizacji <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ . Użyj go, aby opisać konkretny zestaw akcji, które mają zostać zastosowane w procesie lub wątku. Zestaw akcji jest powiązany z nazwą profilu, która jest używana w wywołaniach SetTaskProfiles i SetProcessProfiles w celu wywołania akcji profilu.

Przykładowy plik 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" ]
     }
}

Przypisz nazwy do konkretnych plików cgroup jako wpisy na liście Atrybutów . Każdy wpis zawiera następujące informacje:

  • Pole Nazwa - określa nazwę Atrybutu.
  • Pole kontrolera - odwołuje się do kontrolera cgroup z pliku cgroups.json , po jego nazwie.
  • Pole pliku - nazywa konkretny plik w ramach tego kontrolera.

Atrybuty są odniesieniami w definicjach profili zadań. Poza profilami zadań należy ich używać tylko wtedy, gdy struktura wymaga bezpośredniego dostępu do tych plików, a dostępu nie można wyodrębnić przy użyciu profili zadań. We wszystkich innych przypadkach użyj profili zadań; zapewniają lepsze oddzielenie wymaganego zachowania od szczegółów jego implementacji.

Sekcja Profile zawiera definicje profili zadań zawierające następujące elementy:

  • Pole Nazwa - określa nazwę profilu.
  • Sekcja Akcje — zawiera listę działań wykonywanych po zastosowaniu profilu. Każde działanie ma następujące cechy:

    • Pole nazwy określające akcję
    • Sekcja Params określająca zestaw parametrów akcji

Obsługiwane akcje są wymienione w poniższej tabeli.

Działanie Parametr Opis
SetTimerSlack Slack Luz timera w ns
SetAttribute Name Nazwa odnosząca się do atrybutu z sekcji Atrybuty
Value Wartość, która ma zostać zapisana w pliku reprezentowanym przez nazwany atrybut
WriteFile FilePath ścieżka do pliku
Value wartość, która ma zostać zapisana w pliku
JoinCgroup Controller Nazwa kontrolera cgroup z cgroups.json
Path Ścieżka podgrupy w hierarchii kontrolera cgroup

Android 12 i nowsze wersje zawierają sekcję AggregateProfiles zawierającą profile zagregowane, z których każdy jest aliasem dla zestawu jednego lub większej liczby profili. Definicje profili zbiorczych składają się z następujących elementów:

  • Pole Nazwa - określa nazwę profilu zbiorczego.
  • Pole Profile - zawiera listę nazw profili zawartych w profilu zbiorczym.

Po zastosowaniu profilu zbiorczego automatycznie stosowane są także wszystkie profile zawierające. Profile zagregowane mogą zawierać zarówno profile indywidualne, jak i inne profile zagregowane, o ile nie występują w nich rekurencje (profil, który zawiera sam siebie).

task_profiles polecenie języka inicjującego

Polecenie task_profiles w języku Android Init jest dostępne dla systemu Android 12 i nowszych wersji, aby ułatwić aktywację profilu zadania dla określonego procesu. Zastępuje polecenie writepid (przestarzałe w systemie Android 12), które było używane do migracji procesu między grupami cgroup. Komenda task_profiles zapewnia elastyczność zmiany podstawowych implementacji bez wpływu na wyższe warstwy. W poniższym przykładzie te dwa polecenia skutecznie wykonują tę samą operację:

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

    Przestarzałe w systemie Android 12 — zostało użyte do zapisania identyfikatora PID bieżącego zadania w pliku /dev/cpuctl/top-app/tasks .

  • task_profiles MaxPerformance

    Dołącza bieżący proces do grupy top-app pod kontrolerem „cpu” ( cpuctl ), co powoduje zapisanie PID procesu do dev/cpuctl/top-app/tasks .

Zawsze używaj polecenia task_profiles do migracji zadań w hierarchiach cgroup w systemie Android 12 i nowszych wersjach. Akceptuje jeden lub więcej parametrów reprezentujących nazwy profili określonych w pliku task_profiles.json .

Na profile zadań na poziomie interfejsu API

W systemie Android 12 i nowszych wersjach możesz zmieniać lub zastępować definicje w domyślnych plikach cgroups.json i task_profiles.json , opierając zmianę na poziomie interfejsu API systemu Android lub wprowadzając ją z partycji dostawcy.

Aby zastąpić definicje oparte na poziomie API, na urządzeniu muszą znajdować się następujące pliki:

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

    Użyj tego dla grup c-specyficznych dla poziomu API.

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

    Użyj tej opcji w przypadku profili specyficznych dla poziomu interfejsu API.

Aby zastąpić definicje z partycji dostawcy, na urządzeniu muszą znajdować się następujące pliki:

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

Jeśli definicja atrybutu lub profilu w tych plikach ma tę samą nazwę, co w pliku domyślnym, definicja pliku (na poziomie interfejsu API lub na poziomie dostawcy) zastępuje poprzednią definicję. Należy również pamiętać, że definicje na poziomie dostawcy zastępują definicje na poziomie interfejsu API. Jeżeli nowa definicja ma nową nazwę, to zbiór atrybutów lub profili zostaje uzupełniony nową definicją.

System Android ładuje pliki cgroup i task_profile w następującej kolejności:

  1. Domyślne pliki cgroups.json i task_profiles.json .
  2. Pliki specyficzne dla poziomu interfejsu API, jeśli istnieją.
  3. Pliki partycji dostawcy, jeśli są obecne.

Zmiany w istniejącym API

Android 10 i nowsze wersje zachowują funkcje set_cpuset_policy , set_sched_policy i get_sched_policy bez zmian w interfejsie API. Jednak Android 10 przenosi te funkcje do libprocessgroup , która zawiera teraz wszystkie funkcje związane z cgroup.

Chociaż nagłówek cutils/sched_policy.h nadal istnieje, aby uniknąć uszkodzenia istniejącego kodu, upewnij się, że nowy kod zawiera zamiast tego nowy nagłówek processgroup/sched_policy.h .

Moduły korzystające z którejkolwiek z tych funkcji powinny dodać zależność od biblioteki libprocessgroup do swojego pliku makefile. Jeśli moduł nie korzysta z żadnej innej funkcjonalności libcutils , usuń zależność biblioteki libcutils z pliku makefile.

Interfejsy API profili zadań

Prywatne interfejsy API w processgroup/processgroup.h zdefiniowano w poniższej tabeli:

Typ API i definicja
bool SetTaskProfiles(int tid, const std::vector & profiles) SetTaskProfiles(int tid, const std::vector & profiles)

Stosuje profile zadań określone w profiles do wątku określonego przez identyfikator wątku (tid) przy użyciu jego parametru tid .

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

Stosuje profile zadań określone w profiles do procesu określonego przez jego użytkownika i identyfikatory procesów przy użyciu parametrów uid i pid

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

Zwraca informację, czy istnieje kontroler cgroup określony przez cgroup_name ; jeśli true , ustawia zmienną path na katalog główny tej grupy cgroup

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

Zwraca informację, czy istnieje atrybut profilu określony przez attr_name ; jeśli true , ustawia zmienną path na ścieżkę pliku powiązanego z tym atrybutem profilu.

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

Zwraca informację, czy istnieje atrybut profilu określony przez attr_name ; jeśli true , ustawia zmienną path na ścieżkę pliku powiązanego z tym atrybutem profilu oraz na wątek określony przez jego identyfikator wątku za pomocą parametru tid .

bool UsePerAppMemcg()

Zwraca informację, czy system jest skonfigurowany do używania grup pamięci dla poszczególnych aplikacji.