Google is committed to advancing racial equity for Black communities. See how.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

Android Live-LocK Daemon (llkd)

O Android 10 inclui o Android Live- llkd Daemon ( llkd ), que é projetado para capturar e mitigar deadlocks do kernel. O componente llkd fornece uma implementação autônoma padrão, mas você pode integrar o código llkd em outro serviço, como parte do loop principal ou como um thread separado.

Cenários de detecção

O llkd tem dois cenários de detecção: estado D ou Z persistente e assinatura de pilha persistente.

Estado D ou Z persistente

Se um thread estiver no estado D (ininterrupto hibernação) ou Z (zumbi) sem progresso de encaminhamento por mais de ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms , o llkd mata o processo (ou processo pai ) Se uma varredura subsequente mostrar que o mesmo processo continua existindo, o llkd confirma uma condição de bloqueio ao vivo e pânico no kernel de uma maneira que fornece o relatório de bug mais detalhado para a condição.

O llkd inclui um self watchdog que llkd um alarme se o llkd travar; watchdog é o dobro do tempo esperado para fluir pelo mainloop e a amostragem é a cada ro.llk_sample_ms .

Assinatura de pilha persistente

Para versões userdebug, o llkd pode detectar live-locks do kernel usando a verificação persistente de assinatura de pilha. Se uma thread em qualquer estado exceto Z tiver um símbolo de kernel ro.llk.stack listado persistente que é relatado por mais de ro.llk.timeout_ms ou ro.llk.stack.timeout_ms , o llkd mata o processo (mesmo se houver encaminhamento progresso de programação). Se uma varredura subsequente mostrar que o mesmo processo continua existindo, o llkd confirma uma condição de bloqueio ao vivo e pânico no kernel de uma maneira que fornece o relatório de bug mais detalhado para a condição.

A verificação lldk persiste continuamente quando a condição de bloqueio lldk existe e procura as sequências compostas " symbol+0x" ou " symbol.cfi+0x" no arquivo /proc/pid/stack no Linux. A lista de símbolos está em ro.llk.stack e o padrão é a lista separada por vírgulas de " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable ".

Os símbolos devem ser raros e de vida curta o suficiente para que em um sistema típico a função seja vista apenas uma vez em uma amostra durante o período de tempo limite de ro.llk.stack.timeout_ms (as amostras ocorrem a cada ro.llk.check_ms ). Devido à falta de proteção ABA, esta é a única maneira de prevenir um falso gatilho. A função do símbolo deve aparecer abaixo da função que chama a fechadura que pode contender. Se o bloqueio estiver abaixo ou na função do símbolo, o símbolo aparecerá em todos os processos afetados, não apenas naquele que causou o bloqueio.

Cobertura

A implementação padrão do llkd não monitora os llkd init , [kthreadd] ou [kthreadd] . Para que o llkd cubra os tópicos gerados por [kthreadd] :

  • Os motoristas não devem permanecer em um estado D persistente,

OU

  • Os drivers devem ter mecanismos para recuperar o encadeamento caso ele seja encerrado externamente. Por exemplo, use wait_event_interruptible() vez de wait_event() .

Se uma das condições acima for atendida, a lista negra do llkd pode ser ajustada para cobrir os componentes do kernel. A verificação de símbolo de pilha envolve uma lista negra de processos adicional para evitar violações graves em serviços que bloqueiam operações de ptrace .

Propriedades Android

O llkd responde a várias propriedades do Android (listadas abaixo).

  • Propriedades chamadas prop_ms estão em milissegundos.
  • Propriedades que usam separador de vírgula (,) para listas usam um separador inicial para preservar a entrada padrão e, em seguida, adiciona ou subtrai entradas com prefixos opcionais de mais (+) e menos (-), respectivamente. Para essas listas, a string "false" é sinônimo de uma lista vazia e as entradas em branco ou ausentes recorrem ao valor padrão especificado.

ro.config.low_ram

O dispositivo está configurado com memória limitada.

ro.debuggable

O dispositivo está configurado para userdebug ou eng build.

ro.llk.sysrq_t

Se a propriedade for "eng", o padrão não será ro.config.low_ram ou ro.debuggable . Se verdadeiro, despeja todos os threads ( sysrq t ).

ro.llk.enable

Permitir que o daemon live-lock seja habilitado. O padrão é falso.

llk.enable

Avaliado para builds de eng. O padrão é ro.llk.enable .

ro.khungtask.enable

Permitir que o daemon [khungtask] seja ativado. O padrão é falso.

khungtask.enable

Avaliado para builds de eng. O padrão é ro.khungtask.enable .

ro.llk.mlockall

Habilite a chamada para mlockall() . O padrão é falso.

ro.khungtask.timeout

[khungtask] limite de tempo máximo. O padrão é 12 minutos.

ro.llk.timeout_ms

Limite de tempo máximo D ou Z. O padrão é 10 minutos. Dobre este valor para definir o watchdog de alarme para llkd .

ro.llk.D.timeout_ms

D limite de tempo máximo. O padrão é ro.llk.timeout_ms .

ro.llk.Z.timeout_ms

Limite máximo de tempo Z. O padrão é ro.llk.timeout_ms .

ro.llk.stack.timeout_ms

Verifica o limite de tempo máximo dos símbolos da pilha persistente. O padrão é ro.llk.timeout_ms . Ativo apenas em builds de userdebug ou eng .

ro.llk.check_ms

Amostras de threads para D ou Z. O padrão é dois minutos.

ro.llk.stack

Verifica os símbolos da pilha do kernel que, se persistentemente presentes, podem indicar que um subsistema está bloqueado. O padrão é cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable lista separada por vírgulas de símbolos do kernel. A verificação não faz o agendamento antecipado ABA, exceto ao pesquisar cada ro.llk_check_ms durante o período ro.llk.stack.timeout_ms , então os símbolos da pilha devem ser excepcionalmente raros e fugazes (é altamente improvável que um símbolo apareça persistentemente em todos amostras da pilha). Verifica se há uma correspondência para " symbol+0x" ou " symbol.cfi+0x" na expansão da pilha. Disponível apenas em builds userdebug ou eng ; preocupações de segurança em compilações de usuário resultam em privilégios limitados que evitam essa verificação.

ro.llk.blacklist.process

O llkd não observa os processos especificados. O padrão é 0,1,2 ( kernel , init e [kthreadd] ) mais os nomes dos processos init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1] . Um processo pode ser uma referência comm , cmdline ou pid . Um padrão automatizado pode ser maior do que o tamanho máximo de propriedade atual de 92.

ro.llk.blacklist.parent

O llkd não monitora processos que possuem o (s) pai (s) especificado (s). O padrão é 0,2,adbd&[setsid] ( kernel , [kthreadd] e adbd apenas para setsid zumbis). Um separador de e comercial (&) especifica que o pai é ignorado apenas em combinação com o processo filho de destino. O e comercial foi selecionado porque nunca faz parte do nome de um processo; entretanto, um setprop no shell requer que o "e" comercial seja escapado ou entre aspas, embora o arquivo init rc onde isso é normalmente especificado, não tenha esse problema. Um processo pai ou de destino pode ser uma referência comm , cmdline ou pid .

ro.llk.blacklist.uid

O llkd não observa os processos que correspondem aos uid (s) especificados. Lista separada por vírgulas de números ou nomes de uid. O padrão é vazio ou falso.

ro.llk.blacklist.process.stack

O llkd não monitora o subconjunto especificado de processos para assinaturas de pilha de bloqueio em tempo real. O padrão é nomes de processos init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . Impede a violação de sepolicy associada a processos que bloqueiam ptrace (pois estes não podem ser verificados). Ativo apenas em builds userdebug e eng . Para obter detalhes sobre os tipos de construção, consulte Construindo Android .

Preocupações arquitetônicas

  • As propriedades são limitadas a 92 caracteres (no entanto, isso é ignorado para padrões definidos no arquivo include/llkd.h nas fontes).
  • O daemon [khungtask] é muito genérico e desarma no código do driver que fica muito no estado D. Mudar para S tornaria a (s) tarefa (s) elimináveis ​​(e ressuscitáveis ​​pelos motoristas, se necessário).

Interface da biblioteca (opcional)

Você pode opcionalmente incorporar o llkd a outro daemon privilegiado usando a seguinte interface C do componente libllkd :

#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void)   /* ms to sleep for next check */

Se um threadname for fornecido, um thread é gerado automaticamente, caso contrário, o chamador deve chamar llkCheckMilliseconds em seu loop principal. A função retorna o período de tempo antes da próxima chamada esperada para este manipulador.