Android 10 zawiera demona Androida do blokowania na żywo (llkd
), który ma za zadanie wykrywać i łagodzić blokady jądra. Komponent llkd
zapewnia domyślne samodzielne wdrożenie, ale możesz też zintegrować kod llkd
z inną usługą, np. jako część głównej pętli lub jako osobny wątek.
Scenariusze wykrywania
llkd
ma 2 scenariusze wykrywania: trwały stan D lub Z oraz trwały podpis stosu.
Stały stan D lub Z
Jeśli wątek jest w stanie D (nieprzerwany sen) lub Z (nieśmiertelny), a jego postęp nie zmienia się od dłuższego czasu (dłużej 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 występuje, llkd
potwierdzi zablokowanie i spowoduje panikę w jądrze, co spowoduje wygenerowanie najbardziej szczegółowego raportu o błędzie dla tego stanu.
llkd
zawiera mechanizm samokontroli, który ostrzega, jeśli llkd
się zawiesi. Czas działania mechanizmu jest podwojony w stosunku do oczekiwanego czasu przepływu przez główną pętlę, a próbkowanie odbywa się co ro.llk_sample_ms
.
Podpis trwałego stosu
W przypadku wersji userdebug może ona wykrywać blokady na żywo w jądrze za pomocą sprawdzania podpisu stosu.llkd
Jeśli wątek w dowolnym stanie innym niż Z ma trwały symbol jądra ro.llk.stack
, który jest zgłaszany dłużej niż ro.llk.timeout_ms
lub ro.llk.stack.timeout_ms
, llkd
zabija proces (nawet jeśli jest w drodze do przodu). Jeśli kolejne skanowanie wykaże, że ten sam proces nadal występuje, llkd
potwierdzi zablokowanie i spowoduje panikę w jądrze, co spowoduje wygenerowanie najbardziej szczegółowego raportu o błędzie dla tego stanu.
Sprawdzanie lldk
jest ciągłe, gdy istnieje warunek blokady na żywo, i szuka w pliku /proc/pid/stack
w systemie Linux ciągu znaków symbol+0x
lub symbol.cfi+0x
. Lista symboli jest w formacie ro.llk.stack
i domyślnie jest to lista rozdzielana przecinkami w formacie cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
.
Symbole powinny być rzadkie i wystarczająco krótkotrwałe, aby w typowym systemie funkcja była widoczna tylko raz w próbce w okresie limitu czasu ro.llk.stack.timeout_ms
(próbki występują co ro.llk.check_ms
). Z powodu braku ochrony ABA jest to jedyny sposób na zapobieganie fałszywym wyzwalczeniom. Pod funkcją wywołującą blokadę musi się pojawić funkcja symbolu. Jeśli kłódka znajduje się pod symbolem lub w funkcji symbolu, symbol pojawia się we wszystkich procesach, które zostały zablokowane, a nie tylko w tym, który spowodował zablokowanie.
Pokrycie
Domyślna implementacja llkd
nie monitoruje skoków init
, [kthreadd]
ani [kthreadd]
. Aby llkd
obejmowało wątki utworzone przez [kthreadd]
:
- Sterowniki nie mogą pozostawać w stanie D przez cały czas.
LUB
- Sterowniki muszą mieć mechanizmy umożliwiające przywrócenie wątku, jeśli zostanie on przerwany zewnętrznie. Na przykład użyj
wait_event_interruptible()
zamiastwait_event()
.
Jeśli spełniony jest jeden z powyższych warunków, listę odrzuconych llkd
można dostosować, aby obejmowała komponenty jądra. Sprawdzanie symboli stosu obejmuje dodatkową listę zablokowanych procesów, aby zapobiec naruszeniom zasad bezpieczeństwa w usługach, które blokują operacje ptrace
.
Właściwości Androida
llkd
reaguje na kilka właściwości Androida (wymienionych poniżej).
- Wartości właściwości o nazwie
prop_ms
są podawane w milisekundach. - Właściwości, które używają przecinka (,) jako separatora list, używają separatora na początku, aby zachować domyślny wpis, a następnie dodawać lub odejmować wpisy za pomocą opcjonalnych prefiksów plusa (+) i minusa (-). W przypadku tych list ciąg znaków
false
jest równoznaczny z pustą listą, a puste lub brakujące wpisy są zastępowane przez określoną wartość domyślną.
ro.config.low_ram
Urządzenie ma ograniczoną pamięć.
ro.debuggable
Urządzenie jest skonfigurowane pod kątem kompilacji userdebug lub eng.
ro.llk.sysrq_t,
Jeśli właściwość to eng
, wartość domyślna nie jest wartością ro.config.low_ram
ani ro.debuggable
.
Jeśli true
, zrzut wszystkich wątków (sysrq t
).
ro.llk.enable
Zezwól na włączenie demona aktywnej blokady. Domyślna wartość to false
.
llk.enable
Sprawdzane w przypadku kompilacji inżynierskich. Domyślna wartość to ro.llk.enable
.
ro.khungtask.enable
Zezwalaj na włączanie demona [khungtask]
. Wartość domyślna to false
.
khungtask.enable
Weryfikowane w przypadku kompilacji inżynierskich. Domyślna wartość to ro.khungtask.enable
.
ro.llk.mlockall
Włącz opcję mlockall()
. Wartość domyślna to false
.
ro.khungtask.timeout
Maksymalny limit czasu: [khungtask]
. Domyślnie jest to 12 minut.
ro.llk.timeout_ms
Maksymalny limit czasu D lub Z. Domyślnie jest to 10 minut. Podwójnie zwiększ tę wartość, aby ustawić watchdog alarmu na llkd
.
ro.llk.D.timeout_ms
D maksymalny limit czasu. Domyślna wartość to ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Z maksymalnym limitem czasu. Domyślna wartość to ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Sprawdzanie maksymalnego limitu czasu dla stałych symboli stosu. Wartość domyślna to ro.llk.timeout_ms
. Aktywna tylko w przypadku kompilacji userdebug lub eng.
ro.llk.check_ms
Przykłady wątków dla D lub Z. Domyślnie jest to 2 minuty.
ro.llk.stack
Sprawdza symbole stosu jądra, które w przypadku stałego występowania mogą wskazywać na zablokowanie podsystemu. Domyślnie jest to cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
lista symboli jądra rozdzielona przecinkami. Ta weryfikacja nie wykonuje przekierowania do planowania ABA, z wyjątkiem okresowego sprawdzania co ro.llk_check_ms
, więc symbole stosu powinny być wyjątkowo rzadkie i krótkotrwałe (bardzo mało prawdopodobne jest, aby symbol pojawiał się stale we wszystkich próbkach stosu).ro.llk.stack.timeout_ms
Sprawdza, czy w rozwiniętym stosie występuje dopasowanie do symbol+0x
lub symbol.cfi+0x
. Dostępne tylko w przypadku kompilacji userdebug lub eng; ze względów bezpieczeństwa kompilacje przeznaczone dla użytkowników mają ograniczone uprawnienia, które uniemożliwiają wykonanie tego sprawdzenia.
ro.llk.blacklist.process,
llkd
nie obserwuje określonych procesów. Wartość domyślna to 0,1,2
(kernel
, init
i [kthreadd]
) oraz nazwy procesów init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
.
Proces może być odwołaniem do comm
, cmdline
lub pid
. Automatyczny domyślny adres IP może być większy niż obecny maksymalny rozmiar usługi, który wynosi 92.
ro.llk.blacklist.parent,
llkd
nie monitoruje procesów, które mają określone elementy nadrzędne. Wartość domyślna to 0,2,adbd&[setsid]
(kernel
, [kthreadd]
i adbd
tylko w przypadku procesów zombiesetsid
). Znak ampersand (&) oznacza, że proces nadrzędny jest ignorowany tylko w połączeniu z docelowym procesem podrzędnym. Wybrano znak „&”, ponieważ nigdy nie występuje on w nazwie procesu. Jednak w powłoce znak „setprop
” wymaga ucieczki lub umieszczenia w cudzysłowie, podczas gdy plik setprop
, w którym jest on zwykle używany, nie ma tego problemu.init rc
Proces nadrzędny lub docelowy może być odwołaniem comm
, cmdline
lub pid
.
ro.llk.blacklist.uid
llkd
nie monitoruje procesów, które pasują do określonych identyfikatorów UID.
Lista numerów lub nazw UIS rozdzielona przecinkami. Wartość domyślna to pusty ciąg lub false
.
ro.llk.blacklist.process.stack
llkd
nie monitoruje określonego podzbioru procesów pod kątem podpisów stosu blokady na żywo. Wartość domyślna to nazwy procesów.init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
Zapobiega naruszeniu zasad bezpieczeństwa związanemu z procesami, które blokują ptrace
(ponieważ nie można ich sprawdzić). Aktywna tylko w przypadku kompilacji userdebug i eng. Szczegółowe informacje o typach kompilacji znajdziesz w artykule Kompilowanie aplikacji na Androida.
Kwestie architektoniczne
- Właściwości mogą zawierać maksymalnie 92 znaki (jest to jednak 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 za często wywołuje kod sterownika, który zbyt długo pozostaje w stanie D. Przejście na tryb S spowoduje, że zadania będą mogły zostać zakończone (i w razie potrzeby przywrócone przez kierowców).
Interfejs biblioteki (opcjonalnie)
Opcjonalnie możesz włączyć llkd
do innego demona z przywilejami, korzystając z tego 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 nazwa wątku zostanie podana, wątek pojawi się automatycznie. W przeciwnym razie element wywołujący musi wywołać funkcję llkCheckMilliseconds
w swojej głównej pętli. Funkcja zwraca okres czasu do następnego oczekiwanego wywołania tego modułu obsługi.