Android 10 incluye Android Live-LocK Daemon ( llkd
), que está diseñado para detectar y mitigar los bloqueos del kernel. El componente llkd
proporciona una implementación independiente predeterminada, pero alternativamente puedes integrar el código llkd
en otro servicio, ya sea como parte del bucle principal o como un hilo separado.
Escenarios de detección
El llkd
tiene dos escenarios de detección: estado D o Z persistente y firma de pila persistente.
Estado D o Z persistente
Si un subproceso está en estado D (suspensión ininterrumpida) o Z (zombi) sin progreso hacia adelante durante más de ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
, el llkd
mata el proceso (o el proceso principal). ). Si un escaneo posterior muestra que el mismo proceso continúa existiendo, el llkd
confirma una condición de bloqueo activo y hace entrar en pánico al kernel de una manera que proporciona el informe de error más detallado para la condición.
El llkd
incluye un dispositivo de vigilancia automático que emite una alarma si llkd
se bloquea; El perro guardián es el doble del tiempo esperado para fluir a través del bucle principal y el muestreo es cada ro.llk_sample_ms
.
Firma de pila persistente
Para las versiones de depuración de usuario, llkd
puede detectar bloqueos activos del kernel mediante la verificación persistente de firmas de pila. Si un subproceso en cualquier estado excepto Z tiene un símbolo del kernel ro.llk.stack
persistente en la lista que se informa por más tiempo que ro.llk.timeout_ms
o ro.llk.stack.timeout_ms
, el llkd
finaliza el proceso (incluso si hay reenvío). avance de la programación). Si un escaneo posterior muestra que el mismo proceso continúa existiendo, el llkd
confirma una condición de bloqueo activo y hace entrar en pánico al kernel de una manera que proporciona el informe de error más detallado para la condición.
La verificación lldk
persiste continuamente cuando existe la condición de bloqueo activo y busca las cadenas compuestas " symbol+0x"
o " symbol.cfi+0x"
en el archivo /proc/pid/stack
en Linux. La lista de símbolos está en ro.llk.stack
y de forma predeterminada es la lista separada por comas de " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
".
Los símbolos deben ser lo suficientemente raros y de corta duración como para que en un sistema típico la función se vea solo una vez en una muestra durante el período de tiempo de espera de ro.llk.stack.timeout_ms
(las muestras ocurren cada ro.llk.check_ms
). Debido a la falta de protección ABA, esta es la única forma de evitar un disparo falso. La función de símbolo debe aparecer debajo de la función que llama al bloqueo que podría competir. Si el bloqueo está debajo o en la función de símbolo, el símbolo aparece en todos los procesos afectados, no solo en el que causó el bloqueo.
Cobertura
La implementación predeterminada de llkd
no monitorea las apariciones init
, [kthreadd]
o [kthreadd]
. Para que el llkd
cubra los hilos generados por [kthreadd]
:
- Los conductores no deben permanecer en un estado D persistente,
O
- Los controladores deben tener mecanismos para recuperar el hilo en caso de que se cierre externamente. Por ejemplo, utilice
wait_event_interruptible()
en lugar dewait_event()
.
Si se cumple una de las condiciones anteriores, la lista negra llkd
se puede ajustar para cubrir los componentes del kernel. La verificación de símbolos de pila implica una lista negra de procesos adicional para evitar violaciones de la política de seguridad en los servicios que bloquean las operaciones ptrace
.
Propiedades de Android
El llkd
responde a varias propiedades de Android (enumeradas a continuación).
- Las propiedades denominadas
prop_ms
están en milisegundos. - Las propiedades que utilizan el separador de coma (,) para las listas utilizan un separador inicial para conservar la entrada predeterminada y luego suman o restan entradas con prefijos opcionales más (+) y menos (-) respectivamente. Para estas listas, la cadena "falso" es sinónimo de una lista vacía, y las entradas en blanco o faltantes recurren al valor predeterminado especificado.
ro.config.low_ram
El dispositivo está configurado con memoria limitada.
ro.depurable
El dispositivo está configurado para depuración de usuario o compilación de ingeniería.
ro.llk.sysrq_t
Si la propiedad es "eng", el valor predeterminado no es ro.config.low_ram
o ro.debuggable
. Si es verdadero, descarte todos los subprocesos ( sysrq t
).
habilitar.rollk
Permitir que se habilite el demonio de bloqueo en vivo. El valor predeterminado es falso.
llk.enable
Evaluado para construcciones inglesas. El valor predeterminado es ro.llk.enable
.
ro.khungtask.enable
Permitir que se habilite el demonio [khungtask]
. El valor predeterminado es falso.
khungtask.enable
Evaluado para construcciones inglesas. El valor predeterminado es ro.khungtask.enable
.
ro.llk.mlockall
Habilite la llamada a mlockall()
. El valor predeterminado es falso.
ro.khungtask.tiempo de espera
[khungtask]
límite de tiempo máximo. El valor predeterminado es 12 minutos.
ro.llk.timeout_ms
Plazo máximo D o Z. El valor predeterminado es 10 minutos. Duplique este valor para configurar el mecanismo de vigilancia de alarma para llkd
.
ro.llk.D.timeout_ms
D plazo máximo. El valor predeterminado es ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Límite de tiempo máximo Z. El valor predeterminado es ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Comprueba el límite de tiempo máximo de símbolos de pila persistentes. El valor predeterminado es ro.llk.timeout_ms
. Activo solo en compilaciones userdebug o eng .
ro.llk.check_ms
Muestras de subprocesos para D o Z. El valor predeterminado es dos minutos.
pila.rollk
Comprueba los símbolos de la pila del kernel que, si están presentes de forma persistente, pueden indicar que un subsistema está bloqueado. El valor predeterminado es cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
lista de símbolos del kernel separados por comas. La verificación no programa ABA hacia adelante, excepto sondeando cada ro.llk_check_ms
durante el período ro.llk.stack.timeout_ms
, por lo que los símbolos de la pila deben ser excepcionalmente raros y fugaces (es muy poco probable que un símbolo aparezca de manera persistente en todos muestras de la pila). Comprueba si hay una coincidencia para " symbol+0x"
o " symbol.cfi+0x"
en la expansión de la pila. Disponible solo en compilaciones userdebug o eng ; Los problemas de seguridad en las compilaciones de usuarios dan como resultado privilegios limitados que impiden esta verificación.
proceso.ro.llk.lista.negra.
El llkd
no supervisa los procesos especificados. El valor predeterminado es 0,1,2
( kernel
, init
y [kthreadd]
) más los nombres de proceso init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
. Un proceso puede ser una referencia comm
, cmdline
o pid
. Un valor predeterminado automatizado puede ser mayor que el tamaño máximo actual de propiedad de 92.
ro.llk.lista negra.padre
El llkd
no supervisa los procesos que tienen los padres especificados. El valor predeterminado es 0,2,adbd&[setsid]
( kernel
, [kthreadd]
y adbd
solo para zombie setsid
). Un separador comercial (&) especifica que el padre se ignora solo en combinación con el proceso hijo de destino. Se seleccionó el signo comercial porque nunca forma parte del nombre de un proceso; sin embargo, un setprop
en el shell requiere que el signo comercial esté entre comillas o escape, aunque el archivo init rc
donde normalmente se especifica esto no tiene este problema. Un proceso principal o de destino puede ser una referencia comm
, cmdline
o pid
.
ro.llk.listanegra.uid
El llkd
no supervisa los procesos que coinciden con los uid especificados. Lista separada por comas de números o nombres de uid. El valor predeterminado es vacío o falso.
pila.de.procesos.de.lista.negra.ro.llk
El llkd
no monitorea el subconjunto de procesos especificado para buscar firmas de pila de bloqueo en vivo. El valor predeterminado son los nombres de proceso init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. Previene la violación de la política de seguridad asociada con procesos que bloquean ptrace
(ya que no se pueden verificar). Activo solo en compilaciones userdebug y eng . Para obtener detalles sobre los tipos de compilación, consulte Compilación de Android .
Preocupaciones arquitectónicas
- Las propiedades están limitadas a 92 caracteres (sin embargo, esto se ignora para los valores predeterminados definidos en el archivo
include/llkd.h
en las fuentes). - El demonio incorporado
[khungtask]
es demasiado genérico y se activa demasiado con el código del controlador que se encuentra en el estado D. Cambiar a S haría que las tareas se pudieran eliminar (y que los conductores pudieran resucitar si fuera necesario).
Interfaz de biblioteca (opcional)
Opcionalmente, puede incorporar llkd
a otro demonio privilegiado utilizando la siguiente interfaz 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 */
Si se proporciona un nombre de hilo, se genera un hilo automáticamente; de lo contrario, la persona que llama debe llamar llkCheckMilliseconds
en su bucle principal. La función devuelve el período de tiempo antes de la próxima llamada esperada a este controlador.