Livello di astrazione Cgroup

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

Informazioni sui cgroup

I cgroup forniscono un meccanismo per aggregare e partizionare insiemi di attività (che consistono in processi, thread e tutti i loro elementi secondari futuri) in gruppi gerarchici con un comportamento specializzato. Android utilizza cgroups per controllare e contabilizzare le risorse di sistema come l'utilizzo e l'allocazione di CPU e memoria, con supporto per cgroups v1 e cgroups 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. Anche se questi potrebbero essere modificati, il framework Android prevedeva che esistesse un insieme specifico di cgroup in posizioni specifiche con una versione e una gerarchia di sottogruppi specifiche, in base allo script. Ciò ha limitato la possibilità di scegliere la successiva versione di cgroup 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 delle attività:

  • Configurazione del gruppo di controllo. Gli sviluppatori descrivono la configurazione dei cgroup nel file cgroups.json per definire i set 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 delle attività. Questi forniscono un'astrazione che disaccoppia la funzionalità richiesta dai dettagli della sua implementazione. Il framework Android applica i profili delle attività come descritto nel file task_profiles.json a un processo o thread 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 delle attività. Per i nuovi casi d'uso, AOSP consiglia di utilizzare le nuove API dei profili delle attività anziché la funzione set_sched_policy legacy.

File di descrizione dei cgroup

I cgroup sono descritti nel file cgroups.json 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 Percorso.
  • Mode, 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 facoltativo, 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 cgroups 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 Percorso per Controller in Cgroups2 è relativo a quel 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 nell'ambito 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 del cgroup, utilizza la funzione API CgroupGetControllerPath.

File dei profili delle attività

Il file task_profiles.json 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 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 Attributi. Ogni voce contiene quanto segue:

  • Il campo Nome 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 indica un file specifico in questo controller.

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

La sezione Profili contiene le definizioni dei profili delle attività con quanto segue:

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

    • Il campo Nome 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 Timer slack in ns
SetAttribute Name Un nome che fa riferimento a un attributo della sezione Attributi
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 del 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 di profilo aggregate sono costituite da:

  • Il campo Nome specifica il nome del profilo aggregato.
  • Il campo Profili 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).

task_profiles init language command

Un comando task_profiles nel linguaggio di inizializzazione di Android è disponibile per Android 12 e versioni successive per facilitare l'attivazione del profilo attività per un processo specifico. Sostituisce il comando writepid (deprecato in Android 12) utilizzato per eseguire la migrazione di un processo tra i cgroup. Il comando task_profiles offre flessibilità per modificare le implementazioni sottostanti senza influire sui livelli superiori. Nell'esempio che segue, questi due comandi eseguono effettivamente la stessa operazione:

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

    Deprecato in Android 12, questo valore 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 di app principali 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.

Per profili di attività a livello di API

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

Per eseguire l'override delle definizioni in base al livello API, i seguenti file devono essere presenti sul dispositivo:

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

    Utilizza questa opzione per i cgroup specifici per un livello API.

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

    Utilizza questo campo per i profili specifici per un livello API.

Per eseguire l'override delle definizioni della 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 fornitore) sostituisce la definizione precedente. Tieni presente inoltre che le definizioni a livello di fornitore sostituiscono quelle 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 per il livello API, se presenti.
  3. File di 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à relative ai cgroup.

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

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

API dei profili delle 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 delle attività specificati in profiles al thread specificato da un ID thread (tid) utilizzando il parametro tid.
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles)
Applica i profili delle 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 un valore che indica se esiste un controller cgroup specificato da cgroup_name; se true, imposta la variabile path sulla radice del cgroup
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path)
Restituisce un valore che indica se esiste un attributo del profilo specificato da attr_name; se true, imposta la variabile path sul percorso del file associato a quell'attributo del profilo.
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)
Restituisce un valore che indica se esiste un attributo del profilo specificato da attr_name; se true, imposta la variabile path sul percorso del file associato a quell'attributo del profilo e al thread specificato dal relativo ID thread utilizzando il parametro tid.
bool UsePerAppMemcg()
Restituisce un valore che indica se il sistema è configurato per utilizzare i cgroup di memoria per app.