Android 10 include il demone live-lock di Android
(llkd
), progettato per rilevare e attenuare i deadlock del kernel. Il componente llkd
fornisce un'implementazione autonoma predefinita, ma in alternativa puoi integrare il codice llkd
in un altro servizio, all'interno del loop principale o come thread separato.
Scenari di rilevamento
llkd
ha due scenari di rilevamento: stato D o Z persistente e firma dello stack persistente.
Stato D o Z permanente
Se un thread è in stato D (sonno senza interruzioni) o Z (zombie) senza
avanzamento per più di ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
, llkd
interrompe il processo (o processo padre). Se una scansione successiva mostra che lo stesso processo continua a esistere, llkd
conferma una condizione di blocco in tempo reale e genera un panico nel kernel in modo da fornire la segnalazione di bug più dettagliata per la condizione.
llkd
include un watchdog autonomo che emette un avviso se llkd
si blocca. Il watchdog è il doppio del tempo previsto per il flusso nel ciclo principale e il campionamento avviene ogni ro.llk_sample_ms
.
Firma stack permanente
Per le release userdebug, llkd
può rilevare i blocchi attivi del kernel utilizzando il controllo delle firme dello stack permanente. Se un thread in qualsiasi stato tranne Z ha un simbolo del kernel ro.llk.stack
elencato in modo persistente che viene segnalato per più di ro.llk.timeout_ms
o ro.llk.stack.timeout_ms
, llkd
termina il processo (anche se è presente un avanzamento della pianificazione in avanti). Se una scansione successiva mostra che lo stesso processo continua a esistere, llkd
conferma una condizione di blocco in tempo reale e genera un panico nel kernel in modo da fornire la segnalazione di bug più dettagliata per la condizione.
Il controllo lldk
persiste continuamente quando esiste la condizione di blocco in tempo reale e cerca le stringhe composte symbol+0x
o symbol.cfi+0x
nel file /proc/pid/stack
su Linux. L'elenco di simboli è in ro.llk.stack
e per impostazione predefinita è l'elenco separato da virgole di cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
.
I simboli devono essere rari e di durata sufficientemente breve in modo che, in un sistema tipico, la funzione venga rilevata una sola volta in un campione durante il periodo di timeout di ro.llk.stack.timeout_ms
(i campioni vengono eseguiti ogni ro.llk.check_ms
). A causa della mancanza di protezione ABA, questo è l'unico modo per evitare un falso trigger. La funzione simbolo deve apparire sotto la funzione che chiama la serratura che potrebbe essere in conflitto. Se il blocco si trova sotto o nella funzione del simbolo, il simbolo viene visualizzato in tutte le procedure interessate, non solo in quella che ha causato il blocco.
Copertura
L'implementazione predefinita di llkd
non monitora le attivazioni di init
, [kthreadd]
o
[kthreadd]
. Per consentire a llkd
di coprire [kthreadd]
thread visualizzati:
- I conducenti non devono rimanere in uno stato D persistente,
O
- I driver devono disporre di meccanismi per recuperare il thread qualora venga interrotto esternamente. Ad esempio, utilizza
wait_event_interruptible()
anzichéwait_event()
.
Se una delle condizioni sopra indicate è soddisfatta, la lista di rifiuto llkd
può essere modificata in modo da coprire i componenti del kernel. Il controllo dei simboli dello stack prevede un elenco di deny aggiuntivo per i processi per evitare violazioni delle norme di sicurezza nei servizi che bloccano le operazioni ptrace
.
Proprietà Android
llkd
risponde a diverse proprietà Android (elencate di seguito).
- Le proprietà denominate
prop_ms
sono in millisecondi. - Le proprietà che utilizzano una virgola (,) come separatore per gli elenchi utilizzano un separatore iniziale per
conservare la voce predefinita, quindi aggiungono o sottrai voci con rispettivamente i prefissi più
(+) e meno (-) facoltativi. Per questi elenchi, la stringa
false
è sinonimo di un elenco vuoto e le voci vuote o mancanti fanno ricorso al valore predefinito specificato.
ro.config.low_ram
Il dispositivo è configurato con una memoria limitata.
ro.debuggable
Il dispositivo è configurato per il debug dell'utente o la build coinvolta.
ro.llk.sysrq_t
Se la proprietà è eng
, il valore predefinito non è ro.config.low_ram
o ro.debuggable
.
Se true
, esegui il dump di tutti i thread (sysrq t
).
ro.llk.enable
Consenti l'attivazione del daemon live-lock. Il valore predefinito è false
.
llk.enable
Valutato per le build eng. Il valore predefinito è ro.llk.enable
.
ro.khungtask.enable
Consenti l'abilitazione del daemon [khungtask]
. Il valore predefinito è false
.
khungtask.enable
Valutato per le build eng. Il valore predefinito è ro.khungtask.enable
.
ro.llk.mlockall
Attiva la chiamata a mlockall()
. Il valore predefinito è false
.
ro.khungtask.timeout
Limite di tempo massimo: [khungtask]
. Il valore predefinito è 12 minuti.
ro.llk.timeout_ms
Limite di tempo massimo D o Z. L'impostazione predefinita è 10 minuti. Raddoppia questo valore per impostare il watchdog di avviso su llkd
.
ro.llk.D.timeout_ms
Limite di tempo massimo di D. Il valore predefinito è ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Limite di tempo massimo Z. Il valore predefinito è ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Controlla il limite di tempo massimo per i simboli di stack permanenti. Il valore predefinito è
ro.llk.timeout_ms
. Attivo solo su build di userdebug o build.
ro.llk.check_ms
Campioni di fili per D o Z. Il valore predefinito è 2 minuti.
ro.llk.stack
Controlla la presenza di simboli dello stack del kernel che, se presenti in modo persistente, possono indicare che un sottosistema è bloccato. Il valore predefinito è
cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
l'elenco di simboli del kernel separati da virgole. Il controllo non esegue la pianificazione in avanti
ABA, tranne tramite polling ogni ro.llk_check_ms
nel periodo
ro.llk.stack.timeout_ms
, pertanto i simboli dello stack dovrebbero essere eccezionalmente rari e
fugaci (è altamente improbabile che un simbolo venga visualizzato in modo persistente in tutti
i campioni dello stack). Consente di cercare una corrispondenza per symbol+0x
o
symbol.cfi+0x
nell'espansione dello stack. Disponibile solo nelle build userdebug o eng; i problemi di sicurezza nelle build utente comportano privilegi limitati che impediscono questo controllo.
ro.llk.blacklist.process
llkd
non monitora i processi specificati. Il valore predefinito è 0,1,2
(kernel
,
init
e [kthreadd]
) più i nomi dei processi
init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
.
Un processo può essere un riferimento comm
, cmdline
o pid
. Un valore predefinito automatico può essere più grande delle dimensioni massime attuali delle proprietà, pari a 92.
ro.llk.blacklist.parente
L'elemento llkd
non controlla i processi per cui sono stati specificati gli elementi principali. Il valore predefinito è 0,2,adbd&[setsid]
(kernel
, [kthreadd]
e adbd
solo per i processi zombiesetsid
). Un separatore e commerciale (&) specifica che il processo principale viene ignorato solo in combinazione con il processo secondario di destinazione. Il simbolo & è stato selezionato perché non fa mai parte del nome di un processo. Tuttavia, un setprop
nella shell richiede che il simbolo & venga inserito tra virgolette o tra barre di fuga, anche se il file init rc
in cui viene specificato normalmente non presenta questo problema. Un processo padre o target può essere un riferimento comm
, cmdline
o pid
.
ro.llk.blacklist.uid
llkd
non monitora i processi corrispondenti agli UID specificati.
Elenco separato da virgole di numeri o nomi UIS. Il valore predefinito è vuoto o false
.
ro.llk.blacklist.process.stack
llkd
non monitora il sottoinsieme specificato di processi per le firme della pila di blocco in tempo reale. Il valore predefinito è i nomi di processo
init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. Impedisce la violazione di sepolicy associata ai processi che bloccano ptrace
(in quanto non possono essere controllati). Attivo solo nelle build userdebug ed eng. Per maggiori dettagli sui tipi di build, consulta la pagina relativa alla creazione di Android.
Problemi di architettura
- Le proprietà sono limitate a 92 caratteri (questo valore viene ignorato per i valori predefiniti
definiti nel file
include/llkd.h
nelle origini). - Il daemon
[khungtask]
integrato è troppo generico e si attiva sul codice del driver che rimane troppo a lungo nello stato D. Il passaggio a S renderebbe le attività killable (e resuscitabili dai driver, se necessario).
Interfaccia della libreria (facoltativa)
Se vuoi, puoi incorporare llkd
in un altro demone con privilegi utilizzando
la seguente interfaccia C del componente libllkd
:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
Se viene fornito un nome thread, viene generato automaticamente un thread, altrimenti il chiamante deve chiamare llkCheckMilliseconds
nel suo loop principale. La funzione restituisce il
periodo di tempo che precede la successiva chiamata prevista a questo gestore.