Warstwa abstrakcji Cgroup

Android 10 i nowsze wersje korzystają z warstwy abstrakcji grupy kontrolnej (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. System wykonuje następnie określone działania profili zadań, aby wybrać co najmniej jedną odpowiednią grupę kontrolną, za pomocą której stosowane są ograniczenia. Zmiany w podstawowym zestawie funkcji grupy kontrolnej można wprowadzać 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 specjalnym zachowaniu. Android używa grup kontrolnych do kontrolowania i rozliczania zasobów systemowych, takich jak wykorzystanie i przydzielanie procesora i pamięci, z obsługą grup kontrolnych v1v2 jądra Linux.

Android 9 i starsze

W Androidzie 9 i starszych wersjach skrypt inicjowania 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ł konkretny zestaw grup kontrolnych o określonej wersji i hierarchii podgrup, zgodnie ze skryptem. Ograniczało to możliwość wyboru następnej wersji cgroup lub zmiany hierarchii cgroup w celu korzystania z nowych funkcji.

Android 10 lub nowszy

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

  • Konfiguracja cgroup 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.
  • 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 zawierać 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 cgroup, użyj funkcji interfejsu API CgroupGetControllerPath.

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 w procesie 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 administratora.

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 rozdzielenie 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ść do zapisania 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 profilu zbiorczego składają się z tych elementów:

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

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

task_profiles init language command

języku inicjowania Androida dostępna jest komenda task_profiles, która umożliwia aktywowanie profilu zadania dla określonego procesu na urządzeniach z Androidem 12 lub nowszym. 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

    Wycofana w Androidzie 12. 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. 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żyj tego 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 jednak 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ń zależność biblioteki libcutils z pliku makefile.

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 atrybut profilu określony przez attr_name istnieje. 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 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 kontrolnych pamięci dla poszczególnych aplikacji.