Capa de abstracción de cgroup

Android 10 y versiones posteriores usan una capa de abstracción de grupo de control (cgroup) con perfiles de tareas, que los desarrolladores pueden usar para describir un conjunto de restricciones para aplicar a un subproceso o proceso. Luego, el sistema sigue las acciones prescritas de los perfiles de tareas para seleccionar uno o más grupos de control de grupos adecuados, a través de los cuales se aplican restricciones, y se pueden realizar cambios en el conjunto de funciones subyacentes del grupo de control de grupos sin afectar las capas de software superiores.

Información acerca de cgroups

Los grupos de control proporcionan un mecanismo para agregar y particionar conjuntos de tareas (que consisten en procesos, subprocesos y todos sus elementos secundarios futuros) en grupos jerárquicos con comportamiento especializado. Android usa cgroups para controlar y contabilizar los recursos del sistema, como el uso y la asignación de CPU y memoria, con compatibilidad con los cgroups v1 y cgroups v2 del kernel de Linux.

Android 9 y versiones anteriores

En Android 9 y versiones anteriores, la secuencia de comandos de inicialización init.rc contenía el conjunto de cgroups disponibles, sus puntos de activación y sus versiones. Si bien se podían cambiar, el framework de Android esperaba que existiera un conjunto específico de cgroups en ubicaciones específicas con una versión y una jerarquía de subgrupos específicas, según la secuencia de comandos. Esto limitaba la capacidad de elegir la siguiente versión de cgroup que se usaría o de cambiar la jerarquía de cgroup para usar funciones nuevas.

Android 10 y versiones posteriores

Android 10 y versiones posteriores usan cgroup con perfiles de tareas:

  • Configuración de cgroups. Los desarrolladores describen la configuración de cgroups en su archivo cgroups.json para definir conjuntos de cgroups, sus ubicaciones de activación y sus atributos. Todos los cgroups se activan durante la etapa de inicio inicial del proceso de inicialización.
  • Perfiles de tareas. Estos proporcionan una abstracción que separa la funcionalidad requerida de los detalles de su implementación. El framework de Android aplica los perfiles de tareas como se describe en el archivo task_profiles.json a un proceso o subproceso con las APIs de SetTaskProfiles y SetProcessProfiles. (Estas APIs son exclusivas de Android 11 y versiones posteriores).

Para proporcionar retrocompatibilidad, las funciones heredadas set_cpuset_policy, set_sched_policy y get_sched_policy proporcionan la misma API y funcionalidad, pero su implementación se modificó para usar perfiles de tareas. Para casos de uso nuevos, AOSP recomienda usar las nuevas APIs de perfiles de tareas en lugar de la función set_sched_policy heredada.

Archivo de descripción de cgroups

Los cgroups se describen en el archivo cgroups.json ubicado en <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Cada controlador se describe en una subsección y debe tener un mínimo de lo siguiente:

  • Nombre, definido por el campo Controller.
  • Es la ruta de activación, definida por el campo Path.
  • Modo, UID (ID de usuario) y GID (ID de grupo) que describen el propietario y los modos de acceso de los archivos de esta ruta de acceso (todos opcionales).
  • Opcional, configurado como true para permitir que el sistema ignore el error de activación causado por un controlador de cgroup que el kernel no admite ser activado.

Ejemplo de archivo cgroups.json

En el siguiente ejemplo, se muestran descripciones para los controladores cgroup v1 (Cgroups) y cgroup v2 (Cgroups2) con sus respectivas rutas de acceso.

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

Este archivo de ejemplo contiene dos secciones: Cgroups (que describe los controladores de cgroup v1) y Cgroups2 (que describe los controladores de cgroup v2). Todos los controladores de la jerarquía de cgroups v2 se activan en la misma ubicación. Por lo tanto, la sección Cgroups2 tiene sus propios atributos Path, Mode, UID y GID para describir la ubicación y los atributos de la raíz de la jerarquía. El atributo Path para Controladores en Cgroups2 es relativo a esa ruta de acceso raíz. En Android 12 y versiones posteriores, puedes definir un controlador de cgroup que se especifique con la ruta de acceso y el modo como "Optional" si lo estableces en true.

El archivo cgroups.json se analiza como parte del proceso de init, durante la etapa de inicio anticipado, y los cgroups se activan en las ubicaciones especificadas. Para obtener más adelante las ubicaciones de activación de cgroup, usa la función de la API de CgroupGetControllerPath.

Archivo de perfiles de tareas

El archivo task_profiles.json se encuentra en <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/. Úsalo para describir un conjunto específico de acciones que se aplicarán a un proceso o un subproceso. Un conjunto de acciones está asociado con un nombre de perfil, que se usa en las llamadas SetTaskProfiles y SetProcessProfiles para invocar acciones de perfil.

Ejemplo de archivo 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" ]
     }
}

Asigna nombres a archivos cgroup específicos como entradas en la lista Atributos. Cada entrada contiene lo siguiente:

  • El campo Name especifica el nombre del atributo.
  • El campo Controller hace referencia a un controlador de cgroup del archivo cgroups.json por su nombre.
  • El campo Archivo asigna un nombre a un archivo específico en este controlador.

Los atributos son referencias en las definiciones de perfiles de tareas. Fuera de los perfiles de tareas, úsalo solo cuando el framework requiera acceso directo a esos archivos y el acceso no se pueda abstraer con perfiles de tareas. En todos los demás casos, usa perfiles de tareas, ya que proporcionan una mejor desvinculación entre el comportamiento requerido y sus detalles de implementación.

La sección Profiles contiene definiciones de perfiles de tareas con lo siguiente:

  • El campo Name define el nombre del perfil.
  • En la sección Actions, se muestra un conjunto de acciones que se realizan cuando se aplica el perfil. Cada acción tiene lo siguiente:

    • El campo Name especifica la acción.
    • La sección Params especifica un conjunto de parámetros para la acción.

Las acciones admitidas se enumeran en la tabla:

Acción Parámetro Descripción
SetTimerSlack Slack Tiempo de inactividad del temporizador en ns
SetAttribute Name Un nombre que hace referencia a un atributo de la sección Atributos
Value Un valor que se escribirá en el archivo representado por el atributo nombrado
WriteFileFilePathruta de acceso al archivo
Valueun valor que se escribirá en el archivo
JoinCgroup Controller Un nombre del controlador de cgroup de cgroups.json
Path Es una ruta de acceso de subgrupo en la jerarquía del controlador de cgroup.

Android 12 y versiones posteriores incluyen una sección AggregateProfiles que contiene perfiles agregados, cada uno de los cuales es un alias para un conjunto de uno o más perfiles. Las definiciones de perfiles agregados constan de lo siguiente:

  • El campo Nombre especifica el nombre del perfil agregado.
  • En el campo Perfiles, se muestran los nombres de los perfiles incluidos en el perfil agregado.

Cuando se aplica un perfil agregado, también se aplican automáticamente todos los perfiles que lo contienen. Los perfiles agregados pueden contener perfiles individuales o bien otros perfiles agregados, siempre y cuando no haya recursión (un perfil que se incluye a sí mismo).

Comando de lenguaje de inicialización de task_profiles

Hay un comando task_profiles en el lenguaje de inicialización de Android disponible para Android 12 y versiones posteriores para facilitar la activación del perfil de tareas para un proceso específico. Reemplaza el comando writepid (obsoleto en Android 12) que se usó para migrar un proceso entre cgroups. El comando task_profiles proporciona flexibilidad para cambiar las implementaciones subyacentes sin afectar las capas superiores. En el siguiente ejemplo, estos dos comandos realizan la misma operación de manera efectiva:

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

    Dejó de estar disponible en Android 12, se usó para escribir el PID de la tarea actual en el archivo /dev/cpuctl/top-app/tasks.

  • task_profiles MaxPerformance

    Une el proceso actual en el grupo de la app principal en el controlador "cpu" (cpuctl), lo que genera la escritura del PID del proceso en dev/cpuctl/top-app/tasks.

Usa siempre el comando task_profiles para migrar tareas en jerarquías de cgroup en Android 12 y versiones posteriores. Acepta uno o más parámetros que representan los nombres de los perfiles especificados en el archivo task_profiles.json.

Perfiles de tareas por nivel de API

En Android 12 y versiones posteriores, puedes modificar o anular definiciones en los archivos cgroups.json y task_profiles.json predeterminados. Para ello, debes basar tu cambio en el nivel de API de Android o hacerlo desde la partición del proveedor.

Para anular las definiciones según el nivel de API, los siguientes archivos deben estar presentes en el dispositivo:

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

    Úsalo para cgroups específicos de un nivel de API.

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

    Úsalo para perfiles específicos de un nivel de API.

Para anular las definiciones de la partición del proveedor, los siguientes archivos deben estar presentes en el dispositivo:

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

Si un atributo o una definición de perfil en estos archivos usan el mismo nombre que el del archivo predeterminado, la definición del archivo (a nivel de la API o del proveedor) anula la definición anterior. Ten en cuenta también que las definiciones a nivel del proveedor anulan las definiciones a nivel de la API. Si la nueva definición tiene un nombre nuevo, el conjunto de atributos o perfiles se modifica con la nueva definición.

El sistema Android carga los archivos cgroup y task_profile en este orden:

  1. Archivos predeterminados cgroups.json y task_profiles.json.
  2. Archivos específicos del nivel de API, si están presentes
  3. Archivos de partición del proveedor, si están presentes

Cambios en la API existente

Android 10 y versiones posteriores conservan las funciones set_cpuset_policy, set_sched_policy y get_sched_policy sin cambios en la API. Sin embargo, Android 10 traslada estas funciones a libprocessgroup, que ahora contiene todas las funciones relacionadas con cgroup.

Si bien el encabezado cutils/sched_policy.h aún existe, para evitar romper el código existente, asegúrate de que el código nuevo incluya un encabezado processgroup/sched_policy.h nuevo.

Los módulos que usan cualquiera de estas funciones deben agregar una dependencia en la biblioteca libprocessgroup a su archivo makefile. Si un módulo no usa ninguna otra funcionalidad de libcutils, quita la dependencia de la biblioteca libcutils del archivo makefile.

APIs de perfiles de tareas

Las APIs privadas en processgroup/processgroup.h se definen en la tabla:

Tipo API y definición
bool SetTaskProfiles(int tid, const std::vector& profiles)
Aplica los perfiles de tareas especificados en profiles al subproceso especificado por un ID de subproceso (tid) con su parámetro tid.
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles)
Aplica los perfiles de tareas especificados en profiles al proceso que especifican los IDs de usuario y proceso con los parámetros uid y pid.
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)
Devuelve si existe un controlador de cgroup especificado por cgroup_name. Si es true, establece la variable path en la raíz de ese cgroup.
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path)
Devuelve si existe un atributo de perfil especificado por attr_name. Si es true, establece la variable path en la ruta de acceso del archivo asociado con ese atributo de perfil.
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)
Devuelve si existe un atributo de perfil especificado por attr_name. Si es true, establece la variable path en la ruta de acceso del archivo asociado con ese atributo de perfil y en el subproceso especificado por su ID de subproceso con el parámetro tid.
bool UsePerAppMemcg()
Devuelve si el sistema está configurado para usar cgroups de memoria por app.