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 Linuxa w wersji 1cgroups w wersji 2.

Android 9 i starsze

W Androidzie 9 i starszych skrypt inicjalizacji init.rc zawierał zestaw dostępnych grup, ich punktów montażowych i wersji. Chociaż można je zmienić, platforma Android oczekuje, że w określonych miejscach w zależności od skryptu będzie istniał określony zestaw grup. Ograniczało to możliwość wybrania następnej wersji cgroup lub zmiany hierarchii cgroup w celu korzystania z 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 przypadków użycia 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 zdefiniowana 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 v1 (Cgroups) i cgroup v2 (Cgroups2) wraz z ich ś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żki, trybu, UID i GID, które opisują lokalizację i atrybuty dla elementu wyższego poziomu w 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.jsonznajduje 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 te informacje:

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

Atrybuty to odniesienia w definicjach profili zadań. Poza profilami zadań używaj ich tylko, gdy platforma wymaga bezpośredniego dostępu do tych plików, a dostępu nie można uzyskać za pomocą profili zadań. W pozostałych przypadkach używaj profili zadań, które zapewniają lepsze rozdzielenie wymaganego zachowania i 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żda czynność ma:

    • 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 ms
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 cgroup

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 Androida Init, która ułatwia aktywację profilu zadania w przypadku konkretnego procesu. Zastępuje ono polecenie writepid (wycofane w Androidzie 12), które służyło do przenoszenia procesu między grupami procesó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 sterowniku „cpu” (cpuctl), co powoduje zapisanie PID procesu w grupie dev/cpuctl/top-app/tasks.

Aby przenosić zadania w hierarchiach cgroup w Androidzie 12 i nowszych, zawsze używaj polecenia task_profiles. Akceptuje co najmniej 1 parametr, który reprezentuje 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, zmieniając je na poziomie interfejsu API Androida lub w 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 tego w przypadku grup skoncentrowanych na konkretnym poziomie 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 na poziomie 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ę, zestaw atrybutów lub profili zostanie zmodyfikowany o tą nową definicję.

System Android wczytuje pliki cgrouptask_profile w takiej kolejności:

  1. Domyślne pliki cgroups.json i task_profiles.json.
  2. pliki związane z poziomem interfejsu API (jeśli występują);
  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 są jednak przenoszone do libprocessgroup, który zawiera teraz wszystkie funkcje związane z cgroup.

Chociaż nagłówek cutils/sched_policy.h nadal istnieje, aby uniknąć problemów z obecnym kodem, upewnij się, że nowy kod zawiera zamiast niego nowy nagłówek processgroup/sched_policy.h.

W plikach makefile modułów, które korzystają z którejś z tych funkcji, należy dodać 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 za pomocą identyfikatora wątku (tid) za pomocą 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 za pomocą identyfikatorów użytkownika i procesu za pomocą parametrów uidpid
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 rdzeń 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 atrybut profilu określony przez attr_name istnieje. 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()
Zwraca informacje o tym, czy system jest skonfigurowany do korzystania z grup pamięci na podstawie aplikacji.