Android 10 include Android Live-LocK Daemon ( llkd
), progettato per individuare e mitigare i deadlock del kernel. Il componente llkd
fornisce un'implementazione autonoma predefinita, ma in alternativa puoi integrare il codice llkd
in un altro servizio, come parte del ciclo 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 persistente
Se un thread è nello stato D (sospensione senza interruzioni) o Z (zombie) senza alcun avanzamento per un periodo superiore a ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
, llkd
termina il processo (o il processo genitore ). Se una scansione successiva mostra che lo stesso processo continua a esistere, llkd
conferma una condizione di live-lock e manda in panico il kernel in modo da fornire la segnalazione di bug più dettagliata per la condizione.
llkd
include un sistema di autocontrollo che attiva l'allarme se llkd
si blocca; watchdog è il doppio del tempo previsto per scorrere attraverso il ciclo principale e il campionamento è ogni ro.llk_sample_ms
.
Firma dello stack persistente
Per i rilasci di userdebug, llkd
può rilevare i live-lock del kernel utilizzando il controllo persistente della firma dello stack. Se un thread in qualsiasi stato tranne Z ha un simbolo del kernel ro.llk.stack
elencato persistente che viene segnalato per un periodo più lungo di ro.llk.timeout_ms
o ro.llk.stack.timeout_ms
, llkd
termina il processo (anche se c'è un forward avanzamento della programmazione). Se una scansione successiva mostra che lo stesso processo continua a esistere, llkd
conferma una condizione di live-lock e manda in panico il 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 live e cerca le stringhe composte " symbol+0x"
o " symbol.cfi+0x"
nel file /proc/pid/stack
su Linux. L'elenco dei 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 dovrebbero essere rari e di breve durata in modo che su un sistema tipico la funzione venga vista solo una volta in un campione durante il periodo di timeout di ro.llk.stack.timeout_ms
(i campioni si verificano ogni ro.llk.check_ms
). A causa della mancanza di protezione ABA, questo è l'unico modo per prevenire un falso trigger. La funzione simbolo deve comparire sotto la funzione che richiama la serratura che potrebbe contendersi. Se il blocco si trova sotto o nella funzione simbolo, il simbolo verrà visualizzato in tutti i processi interessati, non solo in quello che ha causato il blocco.
Copertura
L'implementazione predefinita di llkd
non monitora la generazione init
, [kthreadd]
o [kthreadd]
. Affinché llkd
copra i thread generati da [kthreadd]
:
- I conducenti non devono rimanere in uno stato D persistente,
O
- I driver devono disporre di meccanismi per ripristinare il thread nel caso in cui venga interrotto esternamente. Ad esempio, utilizza
wait_event_interruptible()
invece diwait_event()
.
Se una delle condizioni di cui sopra viene soddisfatta, la lista nera llkd
può essere modificata per coprire i componenti del kernel. Il controllo dei simboli dello stack implica un'ulteriore lista nera dei processi per prevenire violazioni della sepolicy sui servizi che bloccano le operazioni ptrace
.
Proprietà Android
llkd
risponde a diverse proprietà Android (elencate di seguito).
- Le proprietà denominate
prop_ms
sono espresse in millisecondi. - Le proprietà che utilizzano il separatore virgola (,) per gli elenchi utilizzano un separatore iniziale per preservare la voce predefinita, quindi aggiungono o sottraggono voci rispettivamente con i prefissi più (+) e meno (-) facoltativi. Per questi elenchi, la stringa "false" è sinonimo di un elenco vuoto e le voci vuote o mancanti ricorrono al valore predefinito specificato.
ro.config.low_ram
Il dispositivo è configurato con memoria limitata.
ro.debugable
Il dispositivo è configurato per userdebug o eng build.
ro.llk.sysrq_t
Se la proprietà è "eng", il valore predefinito non è ro.config.low_ram
o ro.debuggable
. Se vero, scarica tutti i thread ( sysrq t
).
ro.llk.enable
Consenti l'abilitazione del demone live-lock. L'impostazione predefinita è falsa.
llk.enable
Valutato per le build ingegneristiche. L'impostazione predefinita è ro.llk.enable
.
ro.khungtask.enable
Consenti l'abilitazione del demone [khungtask]
. L'impostazione predefinita è falsa.
khungtask.enable
Valutato per le build ingegneristiche. L'impostazione predefinita è ro.khungtask.enable
.
ro.llk.mlockall
Abilita la chiamata a mlockall()
. L'impostazione predefinita è falsa.
ro.khungtask.timeout
[khungtask]
limite di tempo massimo. L'impostazione predefinita è 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 dell'allarme per llkd
.
ro.llk.D.timeout_ms
D termine massimo. L'impostazione predefinita è ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Z limite di tempo massimo. L'impostazione predefinita è ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Controlla il limite di tempo massimo dei simboli dello stack persistente. L'impostazione predefinita è ro.llk.timeout_ms
. Attivo solo su userdebug o eng build .
ro.llk.check_ms
Esempi di thread per D o Z. L'impostazione predefinita è due minuti.
ro.llk.stack
Controlla i simboli dello stack del kernel che, se presenti in modo persistente, possono indicare che un sottosistema è bloccato. L'impostazione predefinita è cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
elenco separato da virgole di simboli del kernel. Il controllo non esegue la pianificazione ABA in avanti se non interrogando ogni ro.llk_check_ms
nel periodo ro.llk.stack.timeout_ms
, quindi i simboli dello stack dovrebbero essere eccezionalmente rari e fugaci (è altamente improbabile che un simbolo venga visualizzato in modo persistente in tutti campioni dello stack). Verifica la corrispondenza per " symbol+0x"
o " symbol.cfi+0x"
nell'espansione dello stack. Disponibile solo su userdebug o eng build ; i problemi di sicurezza sulle build degli utenti comportano privilegi limitati che impediscono questo controllo.
ro.llk.blacklist.process
llkd
non controlla i processi specificati. Il valore predefinito è 0,1,2
( kernel
, init
, e [kthreadd]
) più i nomi init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
. Un processo può essere un riferimento comm
, cmdline
o pid
. Un'impostazione predefinita automatizzata può essere maggiore della dimensione massima corrente della proprietà pari a 92.
ro.llk.blacklist.parent
llkd
non controlla i processi che hanno i genitori specificati. Il valore predefinito è 0,2,adbd&[setsid]
( kernel
, [kthreadd]
e adbd
solo per zombie setsid
). Un separatore e commerciale (&) specifica che il genitore viene ignorato solo in combinazione con il processo figlio di destinazione. La e commerciale è stata selezionata perché non fa mai parte del nome di un processo; tuttavia, un setprop
nella shell richiede che la e commerciale venga sottoposta a escape o virgolette, sebbene il file init rc
in cui questo è normalmente specificato non presenta questo problema. Un processo padre o di destinazione può essere un riferimento comm
, cmdline
o pid
.
ro.llk.blacklist.uid
llkd
non controlla i processi che corrispondono agli uid specificati. Elenco separato da virgole di numeri o nomi uid. L'impostazione predefinita è vuota o falsa.
ro.llk.blacklist.process.stack
llkd
non monitora il sottoinsieme specificato di processi per le firme dello stack di blocco in tempo reale. Il valore predefinito è il nome del processo init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. Previene la violazione della sepolicy associata ai processi che bloccano ptrace
(poiché questi non possono essere controllati). Attivo solo su userdebug ed eng build . Per dettagli sui tipi di build, fare riferimento a Creazione di Android .
Preoccupazioni architettoniche
- Le proprietà sono limitate a 92 caratteri (tuttavia, questo viene ignorato per i valori predefiniti definiti nel file
include/llkd.h
nei sorgenti). - Il demone
[khungtask]
integrato è troppo generico e inciampa troppo nel codice del driver che si trova nello stato D. Il passaggio a S renderebbe le attività uccidibili (e resuscitabili dai conducenti, se necessario).
Interfaccia della libreria (opzionale)
Puoi facoltativamente incorporare llkd
in un altro demone privilegiato utilizzando la seguente interfaccia C dal 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, un thread viene generato automaticamente, altrimenti il chiamante deve chiamare llkCheckMilliseconds
nel suo ciclo principale. La funzione restituisce il periodo di tempo prima della successiva chiamata prevista a questo gestore.