Android 10 enthält den Android Live-LocK Daemon ( llkd
), der entwickelt wurde, um Kernel-Deadlocks abzufangen und abzumildern. Die llkd
Komponente bietet eine standardmäßige eigenständige Implementierung, aber Sie können den llkd
-Code alternativ in einen anderen Dienst integrieren, entweder als Teil der Hauptschleife oder als separater Thread.
Erkennungsszenarien
Der llkd
hat zwei Erkennungsszenarien: Persistenter D- oder Z-Zustand und persistente Stack-Signatur.
Dauerhafter D- oder Z-Zustand
Wenn ein Thread länger als ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
im Zustand D (unterbrechungsfreier Ruhezustand) oder Z (Zombie) ohne Vorwärtsfortschritt ist, llkd
den Prozess (oder den Elternprozess ). Wenn ein nachfolgender Scan zeigt, dass derselbe Prozess weiterhin existiert, bestätigt der llkd
eine Live-Lock-Bedingung und bringt den Kernel auf eine Weise in Panik, die den detailliertesten Fehlerbericht für die Bedingung liefert.
Der llkd
enthält einen Selbstwächter, der alarmiert, wenn der llkd
; watchdog ist doppelt so lang wie die erwartete Zeit, um durch die Hauptschleife zu fließen, und die Abtastung erfolgt alle ro.llk_sample_ms
.
Persistente Stack-Signatur
Für Userdebug-Releases kann der llkd
Kernel-Live-Locks erkennen, indem er eine permanente Stack-Signaturprüfung verwendet. Wenn ein Thread in irgendeinem Zustand außer Z ein dauerhaft aufgelistetes ro.llk.stack
-Kernelsymbol hat, das länger als ro.llk.timeout_ms
oder ro.llk.stack.timeout_ms
wird, llkd
den Prozess (selbst wenn es forward Planungsfortschritt). Wenn ein nachfolgender Scan zeigt, dass derselbe Prozess weiterhin existiert, bestätigt der llkd
eine Live-Lock-Bedingung und bringt den Kernel auf eine Weise in Panik, die den detailliertesten Fehlerbericht für die Bedingung liefert.
Die lldk
Prüfung bleibt kontinuierlich bestehen, wenn die Live-Lock-Bedingung besteht, und sucht nach den zusammengesetzten Zeichenfolgen " symbol+0x"
oder " symbol.cfi+0x"
in der Datei /proc/pid/stack
unter Linux. Die Liste der Symbole befindet sich in ro.llk.stack
und ist standardmäßig die durch Kommas getrennte Liste von „ cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
“.
Symbole sollten selten und kurzlebig genug sein, dass die Funktion auf einem typischen System nur einmal in einem Sample über den Timeout-Zeitraum von ro.llk.stack.timeout_ms
(Samples treten alle ro.llk.check_ms
auf). Aufgrund des fehlenden ABA-Schutzes ist dies die einzige Möglichkeit, eine Fehlauslösung zu verhindern. Die Symbolfunktion muss unterhalb der Funktion erscheinen, die die Sperre aufruft, die konkurrieren könnte. Wenn die Sperre unter oder in der Symbolfunktion ist, erscheint das Symbol in allen betroffenen Prozessen, nicht nur in dem, der die Sperre verursacht hat.
Abdeckung
Die Standardimplementierung von llkd
überwacht keine init
-, [kthreadd]
- oder [kthreadd]
. Damit der llkd
[kthreadd]
erzeugte Threads abdeckt:
- Treiber dürfen nicht in einem dauerhaften D-Zustand verbleiben,
ODER
- Treiber müssen über Mechanismen verfügen, um den Thread wiederherzustellen, falls er extern beendet werden sollte. Verwenden Sie beispielsweise
wait_event_interruptible()
anstelle vonwait_event()
.
Wenn eine der oben genannten Bedingungen erfüllt ist, kann die llkd
Blacklist angepasst werden, um Kernel-Komponenten abzudecken. Die Stapelsymbolprüfung beinhaltet eine zusätzliche Prozess-Blacklist, um Separationsverletzungen bei Diensten zu verhindern, die ptrace
Operationen blockieren.
Android-Eigenschaften
Der llkd
reagiert auf mehrere Android-Eigenschaften (unten aufgeführt).
- Eigenschaften mit dem Namen
prop_ms
werden in Millisekunden angegeben. - Eigenschaften, die Kommas (,) als Trennzeichen für Listen verwenden, verwenden ein führendes Trennzeichen, um den Standardeintrag beizubehalten, und addieren oder subtrahieren dann Einträge mit optionalen Plus- (+) bzw. Minus-Präfixen (-). Für diese Listen ist der String „false“ gleichbedeutend mit einer leeren Liste, und leere oder fehlende Einträge greifen auf den angegebenen Standardwert zurück.
ro.config.low_ram
Das Gerät ist mit begrenztem Speicher konfiguriert.
ro.debuggable
Gerät ist für Userdebug oder Eng Build konfiguriert.
ro.llk.sysrq_t
Wenn Eigenschaft "eng" ist, ist der Standard nicht ro.config.low_ram
oder ro.debuggable
. Wenn wahr, alle Threads ausgeben ( sysrq t
).
ro.llk.enable
Aktivieren des Live-Lock-Daemons zulassen. Standard ist falsch.
llk.enable
Ausgewertet für Eng-Builds. Standard ist ro.llk.enable
.
ro.khungtask.enable
Ermöglicht die Aktivierung des [khungtask]
. Standard ist falsch.
khungtask.enable
Ausgewertet für Eng-Builds. Standard ist ro.khungtask.enable
.
ro.llk.mlockall
Aufruf von mlockall()
. Standard ist falsch.
ro.khungtask.timeout
[khungtask]
maximales Zeitlimit. Der Standardwert ist 12 Minuten.
ro.llk.timeout_ms
D oder Z maximales Zeitlimit. Der Standardwert ist 10 Minuten. Verdoppeln Sie diesen Wert, um den Alarm-Watchdog für llkd
.
ro.llk.D.timeout_ms
D maximale Zeitbegrenzung. Standard ist ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Z maximale Zeitbegrenzung. Standard ist ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Überprüft das maximale Zeitlimit für persistente Stack-Symbole. Standard ist ro.llk.timeout_ms
. Nur bei Userdebug- oder Eng-Builds aktiv .
ro.llk.check_ms
Beispiele von Threads für D oder Z. Der Standardwert ist zwei Minuten.
ro.llk.stack
Prüft auf Kernel-Stack-Symbole, die, wenn sie dauerhaft vorhanden sind, anzeigen können, dass ein Subsystem gesperrt ist. Standard ist cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
kommagetrennte Liste von Kernel-Symbolen. Die Prüfung führt keine ABA-Vorwärtsplanung durch, außer indem sie alle ro.llk_check_ms
über den Zeitraum ro.llk.stack.timeout_ms
, daher sollten Stapelsymbole außergewöhnlich selten und flüchtig sein (es ist höchst unwahrscheinlich, dass ein Symbol dauerhaft in allen auftaucht Proben des Stapels). Sucht nach einer Übereinstimmung für " symbol+0x"
oder " symbol.cfi+0x"
in der Stapelerweiterung. Nur bei Userdebug- oder Eng-Builds verfügbar ; Sicherheitsbedenken bei Benutzer-Builds führen zu eingeschränkten Berechtigungen, die diese Prüfung verhindern.
ro.llk.blacklist.prozess
Der llkd
überwacht die angegebenen Prozesse nicht. Standard ist 0,1,2
( kernel
, init
und [kthreadd]
) plus Prozessnamen init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
. Ein Prozess kann eine comm
-, cmdline
- oder pid
-Referenz sein. Ein automatischer Standardwert kann größer als die aktuelle maximale Eigenschaftsgröße von 92 sein.
ro.llk.blacklist.parent
Der llkd
keine Prozesse, die die angegebenen Eltern haben. Der Standardwert ist 0,2,adbd&[setsid]
( kernel
, [kthreadd]
und adbd
nur für Zombie setsid
). Ein kaufmännisches Und-Trennzeichen (&) gibt an, dass der Elternprozess nur in Kombination mit dem untergeordneten Zielprozess ignoriert wird. Kaufmännisches Und wurde ausgewählt, weil es nie Teil eines Prozessnamens ist; Ein setprop
in der Shell erfordert jedoch, dass das kaufmännische Und-Zeichen maskiert oder in Anführungszeichen gesetzt wird, obwohl die init rc
-RC-Datei, in der dies normalerweise angegeben ist, dieses Problem nicht aufweist. Ein Eltern- oder Zielprozess kann eine comm
-, cmdline
- oder pid
-Referenz sein.
ro.llk.blacklist.uid
Der llkd
keine Prozesse, die mit der/den angegebenen UID(s) übereinstimmen. Durch Kommas getrennte Liste von UID-Nummern oder Namen. Standard ist leer oder falsch.
ro.llk.blacklist.process.stack
Der llkd
überwacht die angegebene Teilmenge von Prozessen nicht auf Live-Lock-Stack-Signaturen. Standard ist Prozessnamen init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. Verhindert die sepolicy-Verletzung im Zusammenhang mit Prozessen, die ptrace
blockieren (da diese nicht überprüft werden können). Nur bei Userdebug- und Eng-Builds aktiv . Einzelheiten zu Build-Typen finden Sie unter Erstellen von Android .
Architektonische Bedenken
- Eigenschaften sind auf 92 Zeichen begrenzt (dies wird jedoch für Standardwerte ignoriert, die in der Datei
include/llkd.h
in den Quellen definiert sind). - Der eingebaute
[khungtask]
ist zu generisch und löst zu viel Treibercode aus, der sich im D-Zustand befindet. Der Wechsel zu S würde Aufgabe(n) töten (und bei Bedarf von Fahrern wiederbeleben).
Bibliotheksschnittstelle (optional)
Sie können den llkd
optional in einen anderen privilegierten Daemon integrieren, indem Sie die folgende C-Schnittstelle der libllkd
Komponente verwenden:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
Wenn ein Threadname angegeben wird, wird automatisch ein Thread erzeugt, andernfalls muss der Aufrufer llkCheckMilliseconds
in seiner Hauptschleife aufrufen. Die Funktion gibt die Zeitspanne vor dem nächsten erwarteten Aufruf dieses Handlers zurück.