Warstwa abstrakcji Cgroup

Android 10 i nowsze wersje używają warstwy abstrakcji grupy sterowania (cgroup) z profilami zadań, których deweloperzy mogą używać do opisywania zestawów ograniczeń do zastosowania w wątku lub procesie. Następnie system wykonuje określone działania w ramach profili zadań, aby wybrać co najmniej jedną odpowiednią grupę cgroup, w której są stosowane ograniczenia, oraz wprowadzić zmiany w podstawowym zbiorze funkcji cgroup bez wpływu na wyższe warstwy oprogramowania.

Grupy

Grupy Cgroups stanowią mechanizm służący do agregowania i dzielenia zbiorów zadań (które składają się z procesów, wątków i wszystkich ich przyszłych elementów podrzędnych) na grupy hierarchiczne o specjalnym zachowaniu. Android używa cgroups do kontrolowania zasobów systemu, takich jak wykorzystanie i przydzielanie procesora i pamięci, z obsługą cgroups w jądrze Linux v1cgroups v2.

Android 9 i starsze

W Androidzie 9 i starszych wersjach skrypt inicjowania init.rc zawierał zestaw dostępnych grup grup, ich punkty podłączania i wersje. Chociaż można je zmienić, platforma Android oczekuje, że w określonych miejscach w ramach skryptu będzie istniał określony zestaw grup, z określoną wersją i hierarchią podgrup. Ograniczało to możliwość wybrania kolejnej wersji cgroup do użycia lub zmiany hierarchii cgroup w celu użycia nowych funkcji.

Android 10 lub nowszy

Android 10 i nowsze korzystają z grup użytkowników z profilami zadań:

  • Konfigurowanie grupy C. Deweloperzy opisują konfigurację grup cgroup w pliku cgroups.json, aby zdefiniować zestawy grup cgroup oraz ich lokalizacje i atrybuty. Wszystkie grupy są montowane na wczesnym etapie procesu inicjalizacji.
  • Profile zadań. Zapewniają one abstrakcję, która odłącza wymaganą funkcjonalność od szczegółów jej implementacji. Platforma Androida stosuje profile zadań zgodnie z opisem w pliku task_profiles.json do procesu lub wątku za pomocą interfejsów API SetTaskProfilesSetProcessProfiles. (te interfejsy API są dostępne tylko na Androidzie 11 i nowszych).

Aby zapewnić zgodność wsteczną, funkcje poprzedniej wersji set_cpuset_policy, set_sched_policy i get_sched_policy udostępniają ten sam interfejs API i te same funkcje, ale ich implementacja została zmodyfikowana, aby używać profili zadań. W przypadku nowych zastosowań AOSP zaleca używanie nowych interfejsów API profili zadań zamiast starszej funkcji set_sched_policy.

Plik z opisem grup

Grupy C zostały opisane w pliku cgroups.json znajdującym się w folderze <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Każdy kontroler jest opisany w podrozdziale i musi mieć co najmniej te elementy:

  • Nazwa określona w polu Administrator.
  • Ścieżka podłączenia określona przez pole Ścieżka.
  • Tryb, 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).
  • Opcjonalny atrybut. Ustaw go na true, aby system ignorował błąd zamontowania spowodowany przez kontroler cgroup, którego jądro nie obsługuje.

Przykładowy plik cgroups.json

Przykład poniżej zawiera opisy kontrolerów cgroup w wersji 1 (Cgroups) i cgroup w wersji 2 (Cgroups2) wraz z 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 2 sekcje: Cgroups (opisująca kontrolery cgroup v1) i Cgroups2 (opisująca kontrolery cgroup v2). Wszystkie kontrolery w hierarchii grup konfiguracji v2 są zamontowane w tej samej lokalizacji. Dlatego sekcja Cgroups2 ma własne atrybuty Ścieżka, Tryb, UID i GID służące do opisania lokalizacji i atrybutów głównej hierarchii. Atrybut Ścieżka w przypadku elementu Controllers w sekcji Cgroups2 jest podany w odniesieniu do tej ścieżki głównej. W Androidzie 12 i nowszych możesz zdefiniować kontroler cgroup, który jest określony za pomocą ścieżki i trybu jako "Optional", ustawiając go na true.

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

Plik profili zadań

Plik task_profiles.json znajduje się w folderze <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Używaj go do opisywania konkretnego zestawu działań, które mają być wykonywane w ramach procesu lub wątku. Z nazwą profilu powiązany jest zestaw działań, który jest używany w wywołaniach SetTaskProfilesSetProcessProfiles do wywoływania działań 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 Atrybuty. Każdy wpis zawiera:

  • Pole Nazwa określa nazwę atrybutu.
  • Pole Controller (sterownik) odwołuje się do sterownika cgroup z pliku cgroups.json według jego nazwy.
  • Pole Plik zawiera nazwę konkretnego pliku w ramach tego kontrolera.

Atrybuty to odniesienia w definicjach profili zadań. Poza profilami zadań używaj ich tylko wtedy, gdy platforma wymaga bezpośredniego dostępu do tych plików i że dostępu nie można pobierać za pomocą profili zadań. We wszystkich innych przypadkach korzystaj z profili zadań – ułatwiają one oddzielenie wymaganego działania od szczegółów jego implementacji.

Sekcja Profile zawiera definicje profili zadań z tymi elementami:

  • Pole Nazwa określa nazwę profilu.
  • Sekcja Działania zawiera zestaw działań wykonywanych po zastosowaniu profilu. Każde działanie obejmuje:

    • Pole Nazwa określa działanie.
    • Sekcja Parametr określa zestaw parametrów działania.

Obsługiwane działania znajdziesz w tabeli:

Działanie Parametr Opis
SetTimerSlack Slack Czas opóźnienia w ns
SetAttribute Name nazwa odwołująca się do atrybutu z sekcji Atrybuty.
Value Wartość do zapisania w pliku reprezentowanym przez atrybuty o nazwie
WriteFileFilePathścieżka do pliku
Valuewartość do zapisania w pliku;
JoinCgroup Controller Nazwa kontrolera cgroup z cgroups.json
Path Ścieżka podgrupy w hierarchii kontrolera grupy

Android 12 i nowsze wersje zawierają sekcję AggregateProfiles, która zawiera profile zbiorcze. Każdy z nich jest aliasem zestawu co najmniej 1 profilu. Definicje profili zbiorczych obejmują:

  • Pole Nazwa określa nazwę profilu zbiorczego.
  • W polu Profile (Profile) podana jest lista nazw profili uwzględnionych w profilu zbiorczym.

Gdy zastosujesz profil zbiorczy, wszystkie profile go zawierające zostaną automatycznie zastosowane. Profile zbiorcze mogą zawierać zarówno profile indywidualne, jak i inne profile zbiorcze, o ile nie ma rekurencji (profilu, który zawiera sam siebie).

Polecenie init language w task_profiles

W Androidzie 12 i nowszych dostępna jest komenda task_profilesjęzyku inicjalizacji Androida, która ułatwia aktywację profilu zadania w przypadku konkretnego procesu. Zastępuje on polecenie writepid (wycofane w Androidzie 12), które służyło do przenoszenia procesu między grupami użytkowników. Polecenie task_profiles zapewnia elastyczność w zakresie zmiany implementacji podrzędnych bez wpływu na warstwy wyższe. W przykładzie poniżej te 2 polecenia wykonują tę samą operację:

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

    Ta funkcja została wycofana w Androidzie 12. Służyła do zapisywania PID bieżącego zadania w pliku /dev/cpuctl/top-app/tasks.

  • task_profiles MaxPerformance

    Dołącza bieżący proces do grupy najlepszych aplikacji w ramach kontrolera „cpu” (cpuctl), co powoduje zapisanie identyfikatora PID procesu w miejscu dev/cpuctl/top-app/tasks.

W Androidzie 12 i nowszych wersjach zawsze używaj polecenia task_profiles do przenoszenia zadań w hierarchiach cgroup. Akceptuje on co najmniej 1 parametr reprezentujący nazwy profili określonych w pliku task_profiles.json.

Profile zadań na poziomie interfejsu API

W Androidzie 12 i nowszych możesz poprawiać lub zastępować definicje w domyślnych plikach cgroups.jsontask_profiles.json, korzystając z poziomu interfejsu API Androida lub z partycji dostawcy.

Aby zastąpić definicje na poziomie interfejsu API, na urządzeniu muszą znajdować się te pliki:

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

    Używaj w przypadku grup cgroups specyficznych dla poziomu interfejsu API.

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

    Używaj tego w przypadku profili związanych z poziomem interfejsu API.

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

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

Jeśli atrybut lub definicja profilu w tych plikach ma taką samą nazwę jak w pliku domyślnym, definicja pliku (na poziomie interfejsu API lub dostawcy) zastępuje poprzednią definicję. Pamiętaj też, że definicje na poziomie dostawcy zastępują definicje na poziomie interfejsu API. Jeśli nowa definicja ma nową nazwę, do zbioru atrybutów lub profili zostanie dodana nowa definicja.

System Android wczytuje pliki cgroup i task_profile w tej kolejności:

  1. Domyślne pliki cgroups.json i task_profiles.json.
  2. Pliki dotyczące konkretnego poziomu interfejsu API (jeśli istnieją).
  3. pliki partycji dostawcy, jeśli występują;

Zmiany w dotychczasowym interfejsie API

Android 10 i nowsze wersje zachowują funkcje set_cpuset_policy, set_sched_policyget_sched_policy bez zmian w interfejsie API. W Androidzie 10 te funkcje zostały przeniesione do libprocessgroup, który zawiera teraz wszystkie funkcje związane z cgroup.

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

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

Interfejsy API profili zadań

Interfejsy API prywatne w processgroup/processgroup.h są zdefiniowane w tabeli:

Typ Interfejs API i definicja
bool SetTaskProfiles(int tid, const std::vector& profiles)
Stosuje profile zadań określone w profiles do wątku określonego przez identyfikator wątku (tid), używając parametru tid.
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles)
Stosuje profile zadań określone w profiles do procesu określonego przez jego identyfikatory użytkowników i procesów za pomocą parametrów uid i pid
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
Zwraca wartość wskazującą, czy kontroler cgroup określony przez cgroup_name istnieje; jeśli true, ustawia zmienną path na wartość równą korzeniowi tego cgroup
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path)
Zwraca informację, czy atrybut profilu określony przez parametr attr_name istnieje. Jeśli tak, ustawia zmienną path na ścieżkę do pliku powiązanego z tym atrybutem profilu.true
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 tak, za pomocą parametru tid ustawia zmienną path na ścieżkę pliku powiązanego z tym atrybutem profilu oraz na wątek określony przez jego identyfikator wątku.true
bool UsePerAppMemcg()
Wskazuje, czy system jest skonfigurowany do używania pamięci cgroups dla poszczególnych aplikacji.