Camada de Abstração do Cgroup

O Android 10 e superior usam uma camada de abstração de grupo de controle (cgroup) com perfis de tarefa, que os desenvolvedores podem usar para descrever um conjunto (ou conjuntos) de restrições a serem aplicadas a um thread ou processo. O sistema então segue as ações prescritas dos perfis de tarefa para selecionar um ou mais cgroups apropriados, por meio dos quais as restrições são aplicadas, e as alterações no conjunto de recursos do cgroup subjacente podem ser feitas sem afetar as camadas de software superiores.

Sobre cgroups

Os Cgroups fornecem um mecanismo para agregar e particionar conjuntos de tarefas (que consistem em processos, threads e todos os seus futuros filhos) em grupos hierárquicos com comportamento especializado. O Android usa cgroups para controlar e contabilizar recursos do sistema, como uso e alocação de CPU e memória, com suporte para cgroups v1 e cgroups v2 do kernel Linux.

Android 9 e inferior

No Android 9 e inferior, o script de inicialização init.rc continha o conjunto de cgroups disponíveis, seus pontos de montagem e versões. Embora isso possa ser alterado, a estrutura do Android esperava que um conjunto específico de cgroups existisse em locais específicos com uma versão específica e hierarquia de subgrupo, com base no script. Isso limitou a capacidade de escolher a próxima versão do cgroup a ser usada ou de alterar a hierarquia do cgroup para usar novos recursos.

Android 10 e superior

Android 10 e superior usam cgroups com perfis de tarefas:

  • Configuração de Cgroup - os desenvolvedores descrevem a configuração de cgroups em seu arquivo cgroups.json para definir conjuntos de cgroups e seus locais de montagem e atributos. Todos os cgroups são montados durante o estágio inicial do processo de inicialização.
  • Perfis de tarefas - fornecem uma abstração que separa a funcionalidade necessária dos detalhes de sua implementação. A estrutura do Android aplica os perfis de tarefa conforme descrito no arquivo task_profiles.json a um processo ou encadeamento usando as APIs SetTaskProfiles e SetProcessProfiles . (Essas APIs são exclusivas do Android 11 e superior.)

Para fornecer compatibilidade com versões anteriores, as funções legadas set_cpuset_policy , set_sched_policy e get_sched_policy fornecem a mesma API e funcionalidade, mas sua implementação foi modificada para usar perfis de tarefa. Para novos casos de uso, o AOSP recomenda o uso de novas APIs de perfis de tarefas em vez da função herdada set_sched_policy .

arquivo de descrição do Cgroups

Os Cgroups são descritos no arquivo cgroups.json localizado em <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ . Cada controlador é descrito em uma subseção e deve ter no mínimo o seguinte:

  • Nome, definido pelo campo Controlador .
  • Caminho de montagem, definido pelo campo Caminho .
  • Mode , UID (ID do usuário) e GID (ID do grupo) descrevendo o proprietário e os modos de acesso para os arquivos neste caminho (todos opcionais).
  • Atributo opcional , definido como true para permitir que o sistema ignore o erro de montagem causado por um controlador cgroup que o kernel não suporta ser montado.

Exemplo de arquivo cgroups.json

O exemplo abaixo mostra as descrições dos controladores cgroup v1 ( Cgroups ) e cgroup v2 ( Cgroups2 ) com seus respectivos caminhos.

{
  "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 arquivo de exemplo contém duas seções, Cgroups (descrevendo os controladores cgroup v1) e Cgroups2 (descrevendo os controladores cgroup v2). Todos os controladores na hierarquia do cgroups v2 são montados no mesmo local. Portanto, a seção Cgroups2 tem seus próprios atributos Path , Mode , UID e GID para descrever o local e os atributos da raiz da hierarquia. O atributo Path para Controllers em Cgroups2 é relativo a esse caminho raiz. No Android 12 e superior, você pode definir um controlador cgroup especificado com path e mode como "Optional" definindo-o como true .

O arquivo cgroups.json é analisado como parte do processo de inicialização, durante o estágio inicial, e os cgroups são montados nos locais especificados. Para obter posteriormente os locais de montagem do cgroup, use a função da API CgroupGetControllerPath .

Arquivo de perfis de tarefa

O arquivo task_profiles.json está localizado em <ANDROID_BUILD_TOP>/system/core/libprocessgroup/profiles/ . Use-o para descrever um conjunto específico de ações a serem aplicadas a um processo ou encadeamento. Um conjunto de ações é associado a um nome de perfil, que é usado em chamadas SetTaskProfiles e SetProcessProfiles para invocar ações de perfil.

Exemplo de arquivo 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" ]
     }
}

Atribua nomes a arquivos cgroup específicos como entradas em sua lista de atributos . Cada entrada contém o seguinte:

  • Campo Nome - especifica o nome do Atributo.
  • Campo Controller - referencia um controlador cgroup do arquivo cgroups.json , por seu nome.
  • Campo de arquivo - nomeia um arquivo específico sob este controlador.

Atributos são referências em definições de perfil de tarefa. Fora dos perfis de tarefa, use-os apenas quando a estrutura exigir acesso direto a esses arquivos e o acesso não puder ser abstraído usando perfis de tarefa. Em todos os outros casos, use perfis de tarefa; eles fornecem melhor desacoplamento entre o comportamento necessário e seus detalhes de implementação.

A seção Perfis contém definições de perfil de tarefa com o seguinte:

  • Campo Nome - define o nome do perfil.
  • Seção de ações - lista um conjunto de ações executadas quando o perfil é aplicado. Cada ação tem o seguinte:

    • Campo de nome que especifica a ação
    • Seção de parâmetros especificando um conjunto de parâmetros para a ação

As ações com suporte estão listadas na tabela abaixo.

Açao Parâmetro Descrição
SetTimerSlack Slack Folga do temporizador em ns
SetAttribute Name Um nome que faz referência a um atributo da seção Atributos
Value Um valor a ser gravado no arquivo representado pelo atributo nomeado
WriteFile FilePath caminho para o arquivo
Value um valor a ser gravado no arquivo
JoinCgroup Controller Um nome do controlador cgroup de cgroups.json
Path Um caminho de subgrupo na hierarquia do controlador cgroup

O Android 12 e superior apresentam uma seção AggregateProfiles que contém perfis agregados, cada um dos quais é um alias para um conjunto de um ou mais perfis. As definições de perfil agregadas consistem no seguinte:

  • Campo Nome - especifica o nome do perfil agregado.
  • Campo Perfis - lista os nomes dos perfis incluídos no perfil agregado.

Quando um perfil agregado é aplicado, todos os perfis contidos também são aplicados automaticamente. Os perfis agregados podem conter perfis individuais ou outros perfis agregados, desde que não haja recursões (um perfil que inclui a si mesmo).

comando de linguagem de inicialização task_profiles

Um comando task_profiles no Android Init Language está disponível para Android 12 e superior para facilitar a ativação do perfil de tarefa para um processo específico. Ele substitui o comando writepid (obsoleto no Android 12) que foi usado para migrar um processo entre cgroups. O comando task_profiles fornece flexibilidade para alterar implementações subjacentes sem nenhum efeito nas camadas superiores. No exemplo abaixo, esses dois comandos executam efetivamente a mesma operação:

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

    Obsoleto no Android 12 - Foi usado para gravar o PID da tarefa atual no /dev/cpuctl/top-app/tasks .

  • task_profiles MaxPerformance

    Junta o processo atual ao grupo top-app no ​​controlador "cpu" ( cpuctl ), o que resulta na gravação do PID do processo em dev/cpuctl/top-app/tasks .

Sempre use o comando task_profiles para migrar tarefas em hierarquias de cgroup no Android 12 e superior. Ele aceita um ou mais parâmetros, representando os nomes dos perfis especificados no arquivo task_profiles.json .

Por perfis de tarefa no nível da API

No Android 12 e superior, você pode alterar ou substituir as definições nos arquivos cgroups.json e task_profiles.json padrão, baseando sua alteração no nível da API do Android ou fazendo-a a partir da partição do fornecedor.

Para substituir as definições com base no nível da API, os seguintes arquivos devem estar presentes no dispositivo:

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

    Use isso para cgroups específicos para um nível de API.

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

    Use isso para perfis específicos para um nível de API.

Para substituir as definições da partição do fornecedor, os seguintes arquivos devem estar presentes no dispositivo:

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

Se um atributo ou uma definição de perfil nesses arquivos usar o mesmo nome que está no arquivo padrão, a definição do arquivo (nível de API ou nível de fornecedor) substituirá a definição anterior. Observe também que as definições no nível do fornecedor substituem as definições no nível da API. Se a nova definição tiver um novo nome, o conjunto de atributos ou perfis será alterado com a nova definição.

O sistema Android carrega os arquivos cgroup e task_profile nesta ordem:

  1. cgroups.json e task_profiles.json padrão.
  2. Arquivos específicos do nível da API, se presentes.
  3. Arquivos de partição do fornecedor, se houver.

Alterações na API existente

O Android 10 e superior mantém as funções set_cpuset_policy , set_sched_policy e get_sched_policy sem alterações na API. No entanto, o Android 10 move essas funções para libprocessgroup , que agora contém todas as funcionalidades relacionadas ao cgroup.

Embora o cabeçalho cutils/sched_policy.h ainda exista, para evitar quebrar o código existente, certifique-se de que o novo código inclua um novo cabeçalho processgroup/sched_policy.h .

Módulos que usam qualquer uma dessas funções devem adicionar dependência da biblioteca libprocessgroup em seu makefile. Se um módulo não usa nenhuma outra funcionalidade libcutils , elimine a dependência da biblioteca libcutils do makefile.

APIs de perfis de tarefas

As APIs privadas em processgroup/processgroup.h são definidas na tabela abaixo:

Tipo API e definição
bool SetTaskProfiles(int tid, const std::vector & profiles) SetTaskProfiles(int tid, const std::vector & profiles)

Aplica os perfis de tarefa especificados em profiles ao encadeamento especificado por um ID de encadeamento (tid) usando seu parâmetro tid .

bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector & profiles) SetProcessProfiles(uid_t uid, pid_t pid, const std::vector & profiles)

Aplica os perfis de tarefa especificados em profiles ao processo especificado por seus IDs de usuário e processo usando os parâmetros uid e pid

bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path)

Retorna se existe um controlador cgroup especificado por cgroup_name ; se true , define a variável de path para a raiz desse cgroup

bool CgroupGetAttributePath(const std::string& attr_name, std::string* path)

Retorna se existe um atributo de perfil especificado por attr_name ; se true , define a variável de path para o caminho do arquivo associado a esse atributo de perfil.

bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path)

Retorna se existe um atributo de perfil especificado por attr_name ; se true , define a variável de path para o caminho do arquivo associado a esse atributo de perfil e para o encadeamento especificado por seu ID de encadeamento usando o parâmetro tid .

bool UsePerAppMemcg()

Retorna se o sistema está configurado para usar cgroups de memória por aplicativo.