Livello di astrazione Cgroup

Android 10 e versioni successive utilizzano un livello di astrazione del gruppo di controllo (cgroup) con profili di attività, che gli sviluppatori possono utilizzare per descrivere un insieme (o insiemi) di restrizioni da applicare a un thread o a un processo. Il sistema segue quindi le azioni prescritte dei profili di attività per selezionare uno o più cgroup appropriati, tramite i quali vengono applicate le restrizioni e le modifiche al set di funzionalità cgroup sottostante possono essere apportate senza influire sui livelli software superiori.

Informazioni sui cgroup

I cgroup forniscono un meccanismo per aggregare e partizionare insiemi di attività (costituiti da processi, thread e tutti i relativi figli futuri) in gruppi gerarchici con un comportamento specializzato. Android utilizza i cgroup per controllare e contabilizzare le risorse di sistema, come l'utilizzo e l'allocazione di CPU e memoria, con il supporto per i cgroup v1 e v2 del kernel Linux.

Android 9 e versioni precedenti

In Android 9 e versioni precedenti, lo script di inizializzazione init.rc conteneva l'insieme di cgroup disponibili, i relativi punti di montaggio e le versioni. Sebbene questi potessero essere modificati, il framework Android si aspettava che esistesse un insieme specifico di cgroup in posizioni specifiche con una versione e una gerarchia di sottogruppi specifiche, in base allo script. Ciò limitava la possibilità di scegliere la versione cgroup successiva da utilizzare o di modificare la gerarchia cgroup per utilizzare nuove funzionalità.

Android 10 e versioni successive

Android 10 e versioni successive utilizzano i cgroup con i profili di attività:

  • Configurazione cgroup. Gli sviluppatori descrivono la configurazione dei cgroup nel file cgroups.json per definire insiemi di cgroup, le relative posizioni di montaggio e gli attributi. Tutti i cgroup vengono montati durante la fase di inizializzazione iniziale del processo di inizializzazione.
  • Profili di attività. Questi forniscono un'astrazione che disaccoppia la funzionalità richiesta dai dettagli della sua implementazione. Il framework Android applica i profili di attività a un processo o a un thread come descritto nel file task_profiles.json utilizzando le API SetTaskProfiles e SetProcessProfiles. (Queste API sono specifiche di Android 11 e versioni successive.)

Per garantire la compatibilità con le versioni precedenti, le funzioni legacy set_cpuset_policy, set_sched_policy e get_sched_policy forniscono la stessa API e funzionalità, ma la loro implementazione è stata modificata per utilizzare i profili di attività. Per i nuovi casi d'uso, AOSP consiglia di utilizzare le nuove API dei profili di attività anziché la funzione legacy set_sched_policy.

File di descrizione dei cgroup

I cgroup sono descritti nel cgroups.json file che si trova in <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Ogni controller è descritto in una sottosezione e deve avere almeno quanto segue:

  • Nome, definito dal campo Controller.
  • Percorso di montaggio, definito dal campo Path.
  • Modalità, UID (ID utente) e GID (ID gruppo) che descrivono il proprietario e le modalità di accesso per i file in questo percorso (tutti facoltativi).
  • Attributo Optional, impostato su true per consentire al sistema di ignorare l'errore di montaggio causato da un controller cgroup che il kernel non supporta.

Esempio di file cgroups.json

L'esempio seguente mostra le descrizioni dei controller cgroup v1 (Cgroups) e cgroup v2 (Cgroups2) con i rispettivi percorsi.

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

Questo file di esempio contiene due sezioni, Cgroups (che descrive i controller cgroup v1) e Cgroups2 (che descrive i controller cgroup v2). Tutti i controller nella gerarchia cgroup v2 sono montati nella stessa posizione. Pertanto, la sezione Cgroups2 ha i propri attributi Path, Mode, UID e GID per descrivere la posizione e gli attributi della radice della gerarchia. L'attributo Path per Controllers in Cgroups2 è relativo a questo percorso radice. In Android 12 e versioni successive puoi definire un controller cgroup specificato con percorso e modalità come "Optional" impostandolo su true.

Il file cgroups.json viene analizzato come parte del processo di inizializzazione, durante la fase di inizializzazione iniziale, e i cgroup vengono montati nelle posizioni specificate. Per ottenere in un secondo momento le posizioni di montaggio dei cgroup, utilizza la funzione API CgroupGetControllerPath.

File dei profili di attività

Il task_profiles.json file si trova in <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Utilizzalo per descrivere un insieme specifico di azioni da applicare a un processo o a un thread. Un insieme di azioni è associato a un nome di profilo, che viene utilizzato nelle chiamate SetTaskProfiles e SetProcessProfiles per richiamare le azioni del profilo.

Esempio di file 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" ]
     }
}

Assegna nomi a file cgroup specifici come voci nell'elenco Attributes. Ogni voce contiene quanto segue:

  • Il campo Name specifica il nome dell'attributo.
  • Il campo Controller fa riferimento a un controller cgroup del file cgroups.json in base al nome.
  • Il campo File assegna un nome a un file specifico in questo controller.

Gli attributi sono riferimenti nelle definizioni dei profili di attività. Al di fuori dei profili di attività, utilizzali solo quando il framework richiede l'accesso diretto a questi file e l'accesso non può essere astratto utilizzando i profili di attività. In tutti gli altri casi, utilizza i profili di attività, che forniscono un migliore disaccoppiamento tra il comportamento richiesto e i dettagli di implementazione.

La sezione Profiles contiene le definizioni dei profili di attività con quanto segue:

  • Il campo Name definisce il nome del profilo.
  • La sezione Actions elenca un insieme di azioni eseguite quando viene applicato il profilo. Ogni azione ha quanto segue:

    • Il campo Name specifica l'azione.
    • La sezione Params specifica un insieme di parametri per l'azione.

Le azioni supportate sono elencate nella tabella:

Azione Parametro Descrizione
SetTimerSlack Slack Slack del timer in ns
SetAttribute Name Un nome che fa riferimento a un attributo della sezione Attributes
Value Un valore da scrivere nel file rappresentato dall'attributo denominato
WriteFileFilePathPercorso del file
ValueUn valore da scrivere nel file
JoinCgroup Controller Un nome del controller cgroup da cgroups.json
Path Un percorso di sottogruppo nella gerarchia del controller cgroup

Android 12 e versioni successive includono una sezione AggregateProfiles che contiene profili aggregati, ognuno dei quali è un alias per un insieme di uno o più profili. Le definizioni dei profili aggregati sono costituite da quanto segue:

  • Il campo Name specifica il nome del profilo aggregato.
  • Il campo Profiles elenca i nomi dei profili inclusi nel profilo aggregato.

Quando viene applicato un profilo aggregato, vengono applicati automaticamente anche tutti i profili contenuti. I profili aggregati possono contenere sia profili individuali sia altri profili aggregati, purché non ci siano ricorsioni (un profilo che include se stesso).

Comando del linguaggio di inizializzazione task_profiles

Per Android 12 e versioni successive è disponibile un comando task_profiles nel linguaggio di inizializzazione di Android per facilitare l'attivazione dei profili di attività per un processo specifico. Sostituisce il comando writepid (ritirato in Android 12) utilizzato per eseguire la migrazione di un processo tra i cgroup. Il comando task_profiles offre flessibilità per la modifica delle implementazioni sottostanti senza influire sui livelli superiori. Nell'esempio seguente, questi due comandi eseguono effettivamente la stessa operazione:

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

    Ritirato in Android 12, veniva utilizzato per scrivere il PID dell'attività corrente nel file /dev/cpuctl/top-app/tasks.

  • task_profiles MaxPerformance

    Unisce il processo corrente al gruppo top-app nel controller "cpu" (cpuctl), il che comporta la scrittura del PID del processo in dev/cpuctl/top-app/tasks.

Utilizza sempre il comando task_profiles per eseguire la migrazione delle attività nelle gerarchie cgroup in Android 12 e versioni successive. Accetta uno o più parametri, che rappresentano i nomi dei profili specificati nel file task_profiles.json.

Profili di attività per livello API

In Android 12 e versioni successive, puoi modificare o sostituire le definizioni nei file cgroups.json e task_profiles.json predefiniti, basando la modifica sul livello API di Android o apportandola dalla partizione del fornitore.

Per sostituire le definizioni in base al livello API, i seguenti file devono essere presenti sul dispositivo:

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

    Utilizza questo file per i cgroup specifici di un livello API.

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

    Utilizza questo file per i profili specifici di un livello API.

Per sostituire le definizioni dalla partizione del fornitore, i seguenti file devono essere presenti sul dispositivo:

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

Se un attributo o una definizione di profilo in questi file utilizza lo stesso nome del file predefinito, la definizione del file (a livello di API o di fornitore) sostituisce la definizione precedente. Tieni presente inoltre che le definizioni a livello di fornitore sostituiscono le definizioni a livello di API. Se la nuova definizione ha un nuovo nome, l'insieme di attributi o profili viene modificato con la nuova definizione.

Il sistema Android carica i file cgroup e task_profile in questo ordine:

  1. File cgroups.json e task_profiles.json predefiniti.
  2. File specifici del livello API, se presenti.
  3. File della partizione del fornitore, se presenti.

Modifiche all'API esistente

Android 10 e versioni successive mantengono le funzioni set_cpuset_policy, set_sched_policy e get_sched_policy senza modifiche all'API. Tuttavia, Android 10 sposta queste funzioni in libprocessgroup, che ora contiene tutte le funzionalità correlate ai cgroup.

Sebbene l'intestazione cutils/sched_policy.h esista ancora, per evitare di interrompere il codice esistente, assicurati che il nuovo codice includa invece una nuova intestazione processgroup/sched_policy.h.

I moduli che utilizzano una di queste funzioni devono aggiungere la dipendenza dalla libreria libprocessgroup nel makefile. Se un modulo non utilizza altre funzionalità libcutils, elimina la dipendenza della libreria libcutils dal makefile.

API dei profili di attività

Le API private in processgroup/processgroup.h sono definite nella tabella:

Tipo API e definizione
bool SetTaskProfiles(int tid, const std::vector& profiles)
Applica i profili di attività specificati in profiles al thread specificato da un ID thread (tid) utilizzando il relativo parametro tid.
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles)
Applica i profili di attività specificati in profiles al processo specificato dai relativi ID utente e processo utilizzando i parametri uid e pid.
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
Restituisce se esiste un controller cgroup specificato da cgroup_name esiste; se true, imposta la variabile path sulla radice di questo cgroup.
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path)
Restituisce se esiste un attributo di profilo specificato da attr_name esiste; se true, imposta la variabile path sul percorso del file associato a questo attributo di profilo.
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)
Restituisce se esiste un attributo di profilo specificato da attr_name esiste; se true, imposta la variabile path sul percorso del file associato a questo attributo di profilo e sul thread specificato dal relativo ID thread utilizzando il parametro tid.
bool UsePerAppMemcg()
Restituisce se il sistema è configurato per utilizzare i cgroup di memoria per app.