Android 10 et les versions ultérieures utilisent une couche d'abstraction de groupe de contrôle (cgroup) avec des profils de tâches, que les développeurs peuvent utiliser pour décrire un ou plusieurs ensembles de restrictions à appliquer à un thread ou à un processus. Le système suit ensuite les actions prescrites des profils de tâches pour sélectionner un ou plusieurs cgroups appropriés, par le biais desquels les restrictions sont appliquées. Les modifications apportées à l'ensemble de fonctionnalités de cgroup sous-jacent peuvent être effectuées sans affecter les couches logicielles supérieures.
À propos des cgroups
Les cgroups fournissent un mécanisme permettant d'agréger et de partitionner des ensembles de tâches (qui se composent de processus, de threads et de tous leurs futurs enfants) en groupes hiérarchiques avec un comportement spécialisé. Android utilise des cgroups pour contrôler et comptabiliser les ressources système telles que l'utilisation et l'allocation du processeur et de la mémoire, avec la prise en charge des cgroups v1 et des cgroups v2 du noyau Linux.
Android 9 et versions antérieures
Sous Android 9 ou une version antérieure, le script d'initialisation init.rc
contenait l'ensemble des cgroups disponibles, leurs points de montage et leurs versions. Bien que ces éléments puissent être modifiés, le framework Android s'attendait à ce qu'un ensemble spécifique de cgroups existe à des emplacements spécifiques avec une version et une hiérarchie de sous-groupes spécifiques, en fonction du script. Cela limitait la possibilité de choisir la prochaine version de cgroup à utiliser ou de modifier la hiérarchie de cgroup pour utiliser de nouvelles fonctionnalités.
Android 10 ou version ultérieure
Android 10 et versions ultérieures utilisent des cgroups avec des profils de tâches :
- Configuration des cgroups. Les développeurs décrivent la configuration des cgroups dans leur fichier
cgroups.json
pour définir des ensembles de cgroups, ainsi que leurs points de montage et leurs attributs. Tous les cgroups sont montés lors de la phase d'initialisation précoce du processus d'initialisation. - Profils de tâches : Elles fournissent une abstraction qui dissocie la fonctionnalité requise des détails de son implémentation. L'application du framework Android applique les profils de tâches décrits dans le fichier
task_profiles.json
à un processus ou un thread à l'aide des APISetTaskProfiles
etSetProcessProfiles
. (Ces API sont propres à Android 11 et versions ultérieures.)
Pour assurer la rétrocompatibilité, les anciennes fonctions set_cpuset_policy
, set_sched_policy
et get_sched_policy
fournissent la même API et la même fonctionnalité, mais leur implémentation a été modifiée pour utiliser des profils de tâches. Pour les nouveaux cas d'utilisation, AOSP recommande d'utiliser les nouvelles API de profils de tâches au lieu de l'ancienne fonction set_sched_policy
.
Fichier de description des cgroups
Les cgroups sont décrits dans le fichier cgroups.json
situé sous <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
.
Chaque contrôleur est décrit dans une sous-section et doit comporter au moins les éléments suivants :
- Nom, défini par le champ Contrôleur.
- Chemin d'installation, défini par le champ Chemin d'accès.
- Mode, UID (ID utilisateur) et GID (ID de groupe) décrivant le propriétaire et les modes d'accès pour les fichiers sous ce chemin d'accès (tous facultatifs).
- Attribut facultatif. Définissez-le sur true pour que le système ignore l'erreur de montage causée par un contrôleur cgroup que le noyau ne prend pas en charge.
Exemple de fichier cgroups.json
L'exemple ci-dessous montre les descriptions des contrôleurs cgroup v1 (Cgroups
) et cgroup v2 (Cgroups2
) avec leurs chemins d'accès respectifs.
{
"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"
}
]
}
}
Cet exemple de fichier contient deux sections : Cgroups (décrivant les contrôleurs cgroup v1) et Cgroups2 (décrivant les contrôleurs cgroup v2). Tous les contrôleurs de la hiérarchie cgroups v2 sont montés au même emplacement.
Par conséquent, la section Cgroups2 possède ses propres attributs Path, Mode, UID et GID pour décrire l'emplacement et les attributs de la racine de la hiérarchie. L'attribut Path (Chemin d'accès) pour Controllers (Contrôleurs) sous Cgroups2 est relatif à ce chemin d'accès racine. Dans Android 12 et versions ultérieures, vous pouvez définir un contrôleur cgroup spécifié avec le chemin d'accès et le mode "Optional"
en le définissant sur true
.
Le fichier cgroups.json
est analysé lors du processus d'initialisation, au cours de l'étape d'initialisation précoce, et les cgroups sont montés aux emplacements spécifiés. Pour obtenir ultérieurement les emplacements de montage des cgroups, utilisez la fonction d'API CgroupGetControllerPath
.
Fichier des profils de tâches
Le fichier task_profiles.json
se trouve sous <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/
.
Utilisez-le pour décrire un ensemble spécifique d'actions à appliquer à un processus ou à un thread. Un ensemble d'actions est associé à un nom de profil, qui est utilisé dans les appels SetTaskProfiles
et SetProcessProfiles
pour appeler les actions de profil.
Exemple de fichier 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" ]
}
}
Attribuez des noms à des fichiers cgroup spécifiques en tant qu'entrées dans votre liste Attributs. Chaque entrée contient les éléments suivants :
- Le champ Name (Nom) spécifie le nom de l'attribut.
- Le champ Controller fait référence à un contrôleur cgroup du fichier
cgroups.json
, par son nom. - Les noms de champs File désignent un fichier spécifique sous ce contrôleur.
Les attributs sont des références dans les définitions de profil de tâche. En dehors des profils de tâches, utilisez-les uniquement lorsque le framework nécessite un accès direct à ces fichiers et que l'accès ne peut pas être abstrait à l'aide de profils de tâches. Dans tous les autres cas, utilisez des profils de tâches. Ils permettent un meilleur découplage entre le comportement requis et les détails de son implémentation.
La section Profiles (Profils) contient des définitions de profil de tâche avec les éléments suivants :
- Le champ Nom définit le nom du profil.
La section Actions liste un ensemble d'actions effectuées lorsque le profil est appliqué. Chaque action comporte les éléments suivants :
- Le champ Name (Nom) spécifie l'action.
- La section Params spécifie un ensemble de paramètres pour l'action.
Les actions compatibles sont listées dans le tableau :
Action | Paramètre | Description |
---|---|---|
SetTimerSlack |
Slack |
Délai de latence du minuteur en ns |
SetAttribute |
Name |
Nom faisant référence à un attribut de la section Attributs |
Value |
Valeur à écrire dans le fichier représenté par l'attribut nommé | |
WriteFile | FilePath | chemin d'accès au fichier |
Value | une valeur à écrire dans le fichier. | |
JoinCgroup |
Controller |
Nom du contrôleur cgroup à partir de cgroups.json |
Path |
Chemin d'un sous-groupe dans la hiérarchie du contrôleur cgroup |
Android 12 et versions ultérieures comportent une section AggregateProfiles qui contient des profils agrégés, chacun étant un alias pour un ensemble d'un ou plusieurs profils. Les définitions de profil agrégées se composent des éléments suivants :
- Le champ Nom spécifie le nom du profil agrégé.
- Le champ Profils liste les noms des profils inclus dans le profil agrégé.
Lorsqu'un profil agrégé est appliqué, tous les profils qu'il contient le sont également automatiquement. Les profils agrégés peuvent contenir des profils individuels ou d'autres profils agrégés, à condition qu'il n'y ait pas de récursions (un profil qui s'inclut lui-même).
Commande task_profiles init language
Une commande task_profiles
dans le langage d'initialisation Android est disponible pour Android 12 et versions ultérieures afin de faciliter l'activation du profil de tâche pour un processus spécifique. Il remplace la commande writepid
(obsolète dans Android 12) qui était utilisée pour migrer un processus entre des cgroups. La commande task_profiles
offre la possibilité de modifier les implémentations sous-jacentes sans affecter les couches supérieures. Dans l'exemple ci-dessous, ces deux commandes effectuent la même opération :
writepid /dev/cpuctl/top-app/tasks
Obsolète dans Android 12, cette méthode était utilisée pour écrire le PID de la tâche actuelle dans le fichier
/dev/cpuctl/top-app/tasks
.task_profiles MaxPerformance
Joint le processus actuel au groupe d'applications en haut de la pile sous le contrôleur "cpu" (
cpuctl
), ce qui entraîne l'écriture du PID du processus dansdev/cpuctl/top-app/tasks
.
Utilisez toujours la commande task_profiles
pour migrer les tâches dans les hiérarchies cgroup sous Android 12 et versions ultérieures. Il accepte un ou plusieurs paramètres, qui représentent les noms des profils spécifiés dans le fichier task_profiles.json
.
Par profil de tâche au niveau de l'API
Dans Android 12 ou version ultérieure, vous pouvez modifier ou remplacer les définitions dans les fichiers cgroups.json
et task_profiles.json
par défaut, soit en basant votre modification sur le niveau d'API Android, soit en la faisant à partir de la partition du fournisseur.
Pour remplacer les définitions en fonction du niveau d'API, les fichiers suivants doivent être présents sur l'appareil :
/system/etc/task_profiles/cgroups_<API level>.json
Utilisez-le pour les cgroups spécifiques à un niveau d'API.
/system/etc/task_profiles/task_profiles_<API level>.json
Utilisez-le pour les profils spécifiques à un niveau d'API.
Pour remplacer les définitions de la partition du fournisseur, les fichiers suivants doivent être présents sur l'appareil :
/vendor/etc/cgroups.json
/vendor/etc/task_profiles.json
Si un attribut ou une définition de profil dans ces fichiers utilise le même nom que dans le fichier par défaut, la définition du fichier (au niveau de l'API ou du fournisseur) remplace la définition précédente. Notez également que les définitions au niveau du fournisseur remplacent celles au niveau de l'API. Si la nouvelle définition porte un nouveau nom, l'ensemble d'attributs ou de profils est modifié avec la nouvelle définition.
Le système Android charge les fichiers cgroup
et task_profile
dans l'ordre suivant :
- Fichiers
cgroups.json
ettask_profiles.json
par défaut. - Fichiers spécifiques au niveau de l'API, le cas échéant.
- Fichiers de partition du fournisseur, le cas échéant.
Modifications apportées à l'API existante
Android 10 et versions ultérieures conservent les fonctions set_cpuset_policy
, set_sched_policy
et get_sched_policy
sans modifier l'API.
Toutefois, Android 10 déplace ces fonctions dans libprocessgroup
, qui contient désormais toutes les fonctionnalités liées aux cgroups.
Bien que l'en-tête cutils/sched_policy.h
existe toujours, pour éviter de casser le code existant, assurez-vous que le nouveau code inclut un nouvel en-tête processgroup/sched_policy.h
.
Les modules qui utilisent l'une de ces fonctions doivent ajouter une dépendance à la bibliothèque libprocessgroup
dans leur fichier makefile. Si un module n'utilise aucune autre fonctionnalité libcutils
, supprimez la dépendance de la bibliothèque libcutils
du fichier makefile.
API des profils de tâches
Les API privées de processgroup/processgroup.h
sont définies dans le tableau suivant :
Saisie | API et définition |
---|---|
bool |
SetTaskProfiles(int tid, const std::vector
Applique les profils de tâches spécifiés dans profiles au thread spécifié par
un ID de thread (tid) à l'aide de son paramètre tid . |
bool |
SetProcessProfiles(uid_t uid, pid_t pid, const std::vector
Applique les profils de tâches spécifiés dans profiles au processus spécifié
par ses ID d'utilisateur et de processus à l'aide des paramètres uid et pid |
bool |
CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
Indique si un contrôleur cgroup spécifié par cgroup_name existe. Si true , définit la variable path sur la racine de ce cgroup. |
bool |
CgroupGetAttributePath(const std::string& attr_name, std::string* path)
Indique si un attribut de profil spécifié par attr_name existe. Si true , définit la variable path sur le chemin d'accès au fichier associé à cet attribut de profil. |
bool |
CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)
Indique si un attribut de profil spécifié par attr_name existe. Si true , définit la variable path sur le chemin d'accès du fichier associé à cet attribut de profil et sur le thread spécifié par son ID de thread à l'aide du paramètre tid . |
bool |
UsePerAppMemcg()
Indique si le système est configuré pour utiliser des cgroups de mémoire par application. |