Android 10 zawiera demona Android Live-Lock ( llkd
), który ma na celu wyłapywanie i łagodzenie zakleszczeń jądra. Komponent llkd
zapewnia domyślną samodzielną implementację, ale możesz alternatywnie zintegrować kod llkd
z inną usługą, jako część głównej pętli lub jako oddzielny wątek.
Scenariusze wykrywania
llkd
ma dwa scenariusze wykrywania: trwały stan D lub Z oraz trwały podpis stosu.
Trwały stan D lub Z
Jeśli wątek znajduje się w stanie D (bezprzerwowego uśpienia) lub Z (zombie) bez postępu w przód przez czas dłuższy niż ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
, llkd
zabija proces (lub proces nadrzędny ). Jeśli kolejne skanowanie wykaże, że ten sam proces nadal istnieje, llkd
potwierdza stan blokady na żywo i panikuje jądro w sposób, który zapewnia najbardziej szczegółowy raport o błędzie dla tego stanu.
llkd
zawiera własny watchdog, który alarmuje, jeśli llkd
się zablokuje; watchdog jest dwukrotnie dłuższy niż oczekiwany czas przepływu przez pętlę główną, a próbkowanie odbywa się co ro.llk_sample_ms
.
Trwała sygnatura stosu
W wydaniach userdebug, llkd
może wykrywać blokady na żywo jądra za pomocą trwałego sprawdzania sygnatur stosu. Jeśli wątek w dowolnym stanie z wyjątkiem Z ma trwały wymieniony symbol jądra ro.llk.stack
, który jest zgłaszany przez czas dłuższy niż ro.llk.timeout_ms
lub ro.llk.stack.timeout_ms
, llkd
zabija proces (nawet jeśli istnieje postęp planowania). Jeśli kolejne skanowanie wykaże, że ten sam proces nadal istnieje, llkd
potwierdza stan blokady na żywo i panikuje jądro w sposób, który zapewnia najbardziej szczegółowy raport o błędzie dla tego stanu.
Sprawdzanie lldk
trwa nieprzerwanie, gdy istnieje warunek blokady na żywo i szuka złożonych ciągów " symbol+0x"
lub " symbol.cfi+0x"
w /proc/pid/stack
w systemie Linux. Lista symboli znajduje się w ro.llk.stack
i domyślnie jest to rozdzielana przecinkami lista „ cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
”.
Symbole powinny być rzadkie i na tyle krótkotrwałe, aby w typowym systemie funkcja była widoczna tylko raz w próbce w okresie czasu ro.llk.stack.timeout_ms
(próbki występują co ro.llk.check_ms
). Ze względu na brak ochrony ABA jest to jedyny sposób, aby zapobiec fałszywemu wyzwalaniu. Funkcja symbolu musi pojawić się poniżej funkcji wywołującej blokadę, która mogłaby rywalizować. Jeśli blokada jest poniżej lub w funkcji symbolu, symbol pojawia się we wszystkich procesach, których to dotyczy, a nie tylko w tym, który spowodował blokadę.
Zasięg
Domyślna implementacja llkd
nie monitoruje spawnów init
, [kthreadd]
ani [kthreadd]
. Aby llkd
[kthreadd]
-powstałe wątki:
- Kierowcy nie mogą pozostawać w stałym stanie D,
LUB
- Sterowniki muszą mieć mechanizmy do odzyskania wątku, jeśli zostanie on zabity zewnętrznie. Na przykład użyj
wait_event_interruptible()
zamiastwait_event()
.
Jeśli spełniony jest jeden z powyższych warunków, czarną listę llkd
można dostosować, aby obejmowała składniki jądra. Sprawdzanie symboli stosu obejmuje dodatkową czarną listę procesów, aby zapobiec naruszeniom sepolityki w usługach, które blokują operacje ptrace
.
Właściwości Androida
llkd
odpowiada na kilka właściwości systemu Android (wymienionych poniżej).
- Właściwości o nazwie
prop_ms
są podawane w milisekundach. - Właściwości, które używają separatora przecinkowego (,) dla list, używają wiodącego separatora, aby zachować domyślny wpis, a następnie dodają lub odejmują wpisy z opcjonalnymi odpowiednio przedrostkami plus (+) i minus (-). W przypadku tych list ciąg „false” jest równoznaczny z pustą listą, a puste lub brakujące wpisy odnoszą się do określonej wartości domyślnej.
ro.config.low_ram
Urządzenie jest skonfigurowane z ograniczoną pamięcią.
ro.debuggable
Urządzenie jest skonfigurowane do kompilacji userdebug lub eng.
ro.llk.sysrq_t
Jeśli właściwość to „eng”, wartością domyślną nie jest ro.config.low_ram
ani ro.debuggable
. Jeśli prawda, zrzuć wszystkie wątki ( sysrq t
).
ro.llk.włącz
Zezwól na włączenie demona blokady na żywo. Wartość domyślna to fałsz.
llk.włącz
Oceniane pod kątem kompilacji inżynierskich. Domyślnie jest to ro.llk.enable
.
ro.khungtask.enable
Zezwól na włączenie demona [khungtask]
. Wartość domyślna to fałsz.
chungtask.włącz
Oceniane pod kątem kompilacji inżynierskich. Wartość domyślna to ro.khungtask.enable
.
ro.llk.mlockall
Włącz wywołanie mlockall()
. Wartość domyślna to fałsz.
ro.khungtask.timeout
[khungtask]
maksymalny limit czasu. Wartość domyślna to 12 minut.
ro.llk.timeout_ms
D lub Z maksymalny limit czasu. Wartość domyślna to 10 minut. Podwój tę wartość, aby ustawić alarm alarmowy dla llkd
.
ro.llk.D.timeout_ms
D maksymalny limit czasu. Wartość domyślna to ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Z maksymalny limit czasu. Wartość domyślna to ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Sprawdza maksymalny czas trwania symboli stosu. Wartość domyślna to ro.llk.timeout_ms
. Aktywne tylko w przypadku kompilacji userdebug lub eng .
ro.llk.check_ms
Próbki wątków dla D lub Z. Domyślnie dwie minuty.
ro.llk.stack
Sprawdza symbole stosu jądra, które jeśli są stale obecne, mogą wskazywać, że podsystem jest zablokowany. Domyślnie cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
lista oddzielonych przecinkami symboli jądra. Sprawdzenie nie wykonuje harmonogramu ABA w przód, z wyjątkiem odpytywania każdego ro.llk_check_ms
w okresie ro.llk.stack.timeout_ms
, więc symbole stosu powinny być wyjątkowo rzadkie i ulotne (jest wysoce nieprawdopodobne, aby symbol był stale wyświetlany we wszystkich próbki stosu). Sprawdza dopasowanie " symbol+0x"
lub " symbol.cfi+0x"
w rozwinięciu stosu. Dostępne tylko w kompilacjach userdebug lub eng ; obawy dotyczące bezpieczeństwa w kompilacjach użytkownika skutkują ograniczonymi uprawnieniami, które uniemożliwiają to sprawdzenie.
ro.llk.proces.czarnej listy
llkd
nie obserwuje określonych procesów. Wartość domyślna to 0,1,2
( kernel
, init
, i [kthreadd]
) plus nazwy procesów init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
. Proces może być referencją comm
, cmdline
lub pid
. Zautomatyzowana wartość domyślna może być większa niż bieżący maksymalny rozmiar właściwości wynoszący 92.
ro.llk.czarna lista.rodzic
llkd
nie obserwuje procesów, które mają określonego rodzica(ów). Wartość domyślna to 0,2,adbd&[setsid]
( kernel
, [kthreadd]
i adbd
tylko dla setsid
zombie ). Separator ampersand (&) określa, że rodzic jest ignorowany tylko w połączeniu z docelowym procesem potomnym. Ampersand został wybrany, ponieważ nigdy nie jest częścią nazwy procesu; jednakże setprop
w powłoce wymaga znaku &, aby był chroniony lub cytowany, chociaż plik init rc
, w którym jest to zwykle określone, nie ma tego problemu. Proces nadrzędny lub docelowy może być referencją comm
, cmdline
lub pid
.
ro.llk.czarna lista.uid
llkd
nie obserwuje procesów, które pasują do podanego(ych) identyfikatora(ów). Lista numerów UID lub nazw rozdzielonych przecinkami. Wartość domyślna to pusta lub fałsz.
ro.llk.czarna lista.stos.procesów
llkd
nie monitoruje określonego podzbioru procesów pod kątem sygnatur stosu blokad na żywo. Domyślnie są to nazwy procesów init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. Zapobiega naruszeniom sepolityki związanym z procesami blokującymi ptrace
(ponieważ nie można ich sprawdzić). Aktywny tylko w przypadku kompilacji userdebug i eng . Aby uzyskać szczegółowe informacje na temat typów kompilacji, zobacz Budowanie systemu Android .
Obawy architektoniczne
- Właściwości są ograniczone do 92 znaków (jednak jest to ignorowane w przypadku wartości domyślnych zdefiniowanych w pliku
include/llkd.h
w źródłach). - Wbudowany demon
[khungtask]
jest zbyt ogólny i zbyt często uruchamia kod sterownika, który znajduje się w stanie D. Przełączenie na S sprawiłoby, że zadanie (zadania) byłoby możliwe do zabicia (i w razie potrzeby wskrzeszone przez kierowców).
Interfejs biblioteki (opcjonalnie)
Możesz opcjonalnie włączyć llkd
do innego uprzywilejowanego demona, używając następującego interfejsu C z komponentu libllkd
:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
Jeśli podano nazwę wątku, wątek automatycznie się odradza, w przeciwnym razie wywołujący musi wywołać llkCheckMilliseconds
w swojej pętli głównej. Funkcja zwraca okres czasu przed następnym oczekiwanym wywołaniem tego modułu obsługi.