Warstwa abstrakcji Cgroup

Android 10 i nowsze wersje korzystają z warstwy abstrakcji grupy sterującej (cgroup) z profilami zadań, których deweloperzy mogą używać do opisywania zestawu (lub zestawów) ograniczeń, które mają być stosowane do wątku lub procesu. Następnie system wykonuje określone działania profili zadań, aby wybrać co najmniej jedną odpowiednią grupę kontrolną, za pomocą której stosowane są ograniczenia i wprowadzane zmiany w podstawowym zestawie funkcji grupy kontrolnej bez wpływu na wyższe warstwy oprogramowania.

Informacje o grupach kontrolnych

Cgroups to mechanizm agregowania i dzielenia zestawów zadań (składających się z procesów, wątków i wszystkich ich przyszłych elementów podrzędnych) na hierarchiczne grupy o specjalistycznym zachowaniu. Android używa grup kontrolnych do kontrolowania i rozliczania zasobów systemowych, takich jak wykorzystanie pamięci i przydzielanie procesora i pamięci, z obsługą grup kontrolnych v1v2 jądra Linux.

Android 9 lub starszy

W Androidzie 9 i starszych wersjach skrypt inicjujący init.rc zawierał zestaw dostępnych grup kontrolnych, ich punkty montowania i wersje. Chociaż można było je zmienić, platforma Android oczekiwała, że w określonych lokalizacjach będzie istniał określony zestaw grup kontrolnych z określoną wersją i hierarchią podgrup, zgodnie ze skryptem. Ograniczało to możliwość wyboru następnej wersji grupy kontrolnej lub zmiany hierarchii grup kontrolnych w celu korzystania z nowych funkcji.

Android 10 lub nowszy

Android 10 i nowszy korzysta z grup kontrolnych z profilami zadań:

  • Konfiguracja grupy kontrolnej. Deweloperzy opisują konfigurację cgroups w pliku cgroups.json, aby zdefiniować zestawy cgroups oraz ich lokalizacje montowania i atrybuty. Wszystkie grupy kontrolne są montowane na wczesnym etapie inicjowania procesu inicjalizacji.
  • Profile zadań Zapewniają one abstrakcję, która oddziela wymaganą funkcjonalność od szczegółów jej implementacji. Platforma Android stosuje profile zadań opisane 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 nowszym).

Aby zapewnić zgodność wsteczną, starsze funkcje set_cpuset_policy, set_sched_policyget_sched_policy oferują ten sam interfejs API i te same funkcje, ale ich implementacja została zmodyfikowana w taki sposób, aby korzystać z profili zadań. W przypadku nowych przypadków użycia AOSP zaleca korzystanie z nowych interfejsów API profili zadań zamiast starszej funkcji set_sched_policy.

Plik opisu grup kontrolnych

Grupy kontrolne są opisane w pliku cgroups.json znajdującym się w katalogu <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Każdy kontroler jest opisany w podsekcji i musi mieć co najmniej te elementy:

  • Nazwa zdefiniowana w polu Administrator.
  • Ścieżka podłączenia określona 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. Ustaw wartość true, aby system ignorował błąd montowania spowodowany przez kontroler cgroup, którego jądro nie obsługuje.

Przykładowy plik cgroups.json

Poniższy przykład 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ącą kontrolery cgroup w wersji 1) i Cgroups2 (opisującą kontrolery cgroup w wersji 2). Wszystkie kontrolery w hierarchii cgroups w wersji 2 są montowane w tej samej lokalizacji. Dlatego sekcja Cgroups2 ma własne atrybuty Path, Mode, UIDGID, które opisują lokalizację i atrybuty korzenia hierarchii. Atrybut Ścieżka dla Kontrolerów w sekcji Cgroups2 jest podawany w odniesieniu do tej ścieżki głównej. W Androidzie 12 i nowszych możesz zdefiniować kontroler cgroup określony za pomocą ścieżki i trybu jako "Optional", ustawiając go na true.

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

Plik profili zadań

Plik task_profiles.json znajduje się w lokalizacji <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Używaj go do opisywania określonego zestawu działań, które mają być zastosowane do 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 odwołuje się do kontrolera cgroup z pliku cgroups.json według jego nazwy.
  • Pole File (Plik) zawiera nazwę konkretnego pliku w ramach tego kontrolera.

Atrybuty to odwołania w definicjach profili zadań. Poza profilami zadań używaj ich tylko wtedy, gdy platforma wymaga bezpośredniego dostępu do tych plików, a dostęp nie może być abstrakcyjny przy użyciu profili zadań. We wszystkich pozostałych przypadkach używaj profili zadań. Zapewniają one lepsze oddzielenie wymaganego działania od szczegółów jego implementacji.

Sekcja Profile (Profile) zawiera definicje profili zadań z tymi informacjami:

  • Pole Nazwa określa nazwę profilu.
  • W sekcji Działania znajduje się lista działań wykonywanych po zastosowaniu profilu. Każda czynność ma te elementy:

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

Obsługiwane działania znajdziesz w tabeli:

Działanie Parametr Opis
SetTimerSlack Slack Opóźnienie timera w nanosekundach
SetAttribute Name Nazwa odwołująca się do atrybutu z sekcji Atrybuty
Value Wartość, która ma zostać zapisana w pliku reprezentowanym przez atrybut o podanej 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 dla zestawu co najmniej 1 profilu. Definicje profili zbiorczych obejmują:

  • Pole Nazwa określa nazwę profilu zbiorczego.
  • W polu Profile (Profile) znajdują się nazwy profili uwzględnionych w profilu zbiorczym.

Gdy zastosujesz profil zbiorczy, wszystkie profile, które zawiera, również zostaną zastosowane automatycznie. Profile zbiorcze mogą zawierać zarówno profile indywidualne, jak i inne profile zbiorcze, o ile nie występują w nich rekursje (profil, który zawiera sam siebie).

polecenie task_profiles init language

języku inicjowania Androida dostępnym w Androidzie 12 i nowszych wersjach jest dostępne polecenie task_profiles, które ułatwia aktywowanie profilu zadania dla określonego procesu. Zastępuje polecenie writepid (wycofane w Androidzie 12), które służyło do przenoszenia procesu między grupami kontrolnymi. Polecenie task_profiles zapewnia elastyczność w zakresie zmiany implementacji bazowych bez wpływu na wyższe warstwy. W przykładzie poniżej oba polecenia wykonują to samo działanie:

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

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

  • task_profiles MaxPerformance

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

Zawsze używaj polecenia task_profiles, aby migrować zadania w hierarchiach grup kontrolnych w Androidzie 12 i nowszych wersjach. Akceptuje co najmniej 1 parametr, który reprezentuje nazwy profili podane w pliku task_profiles.json.

Profile zadań na poziomie interfejsu API

Na Androidzie 12 i nowszym możesz modyfikować lub zastępować definicje w domyślnych plikach cgroups.jsontask_profiles.json, opierając zmiany na poziomie interfejsu Android API lub wprowadzając je z partycji dostawcy.

Aby zastąpić definicje na podstawie poziomu interfejsu API, na urządzeniu muszą być obecne te pliki:

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

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

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

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

Aby zastąpić definicje z partycji dostawcy, na urządzeniu muszą być obecne 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ę, zestaw atrybutów lub profili zostanie uzupełniony o nową definicję.

System Android wczytuje pliki cgrouptask_profile w tej kolejności:

  1. Domyślne pliki cgroups.jsontask_profiles.json.
  2. pliki specyficzne dla poziomu interfejsu API (jeśli występują);
  3. Pliki partycji dostawcy (jeśli są dostępne).

Zmiany w istniejącym 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óre 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 nowy nagłówek processgroup/sched_policy.h.

Moduły, które używają którejkolwiek z tych funkcji, powinny dodać zależność od biblioteki libprocessgroup do pliku makefile. Jeśli moduł nie korzysta z żadnych innych funkcji libcutils, usuń z pliku makefile zależność biblioteki libcutils.

Interfejsy API profili zadań

Prywatne interfejsy API w processgroup/processgroup.h są zdefiniowane w tej tabeli:

Typ Interfejs API i definicja
bool SetTaskProfiles(int tid, const std::vector& profiles)
Stosuje profile zadań określone w parametrze profiles do wątku określonego przez identyfikator 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 parametrze profiles do procesu określonego przez identyfikatory użytkownika i procesu za pomocą parametrów uidpid.
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 tak, ustawia zmienną path na ścieżkę 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, 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.true
bool UsePerAppMemcg()
Zwraca informację, czy system jest skonfigurowany do używania grup kontrolnych pamięci dla poszczególnych aplikacji.