Android 10 enthält den Android Live-LocK Daemon ( llkd
), der darauf ausgelegt ist, Kernel-Deadlocks abzufangen und zu mildern. Die llkd
Komponente stellt eine standardmäßige eigenständige Implementierung bereit, Sie können den llkd
Code jedoch alternativ in einen anderen Dienst integrieren, entweder als Teil der Hauptschleife oder als separater Thread.
Erkennungsszenarien
Der llkd
verfügt über zwei Erkennungsszenarien: Persistenter D- oder Z-Status und persistente Stack-Signatur.
Permanenter D- oder Z-Zustand
Wenn sich ein Thread im Zustand D (unterbrechungsfreier Ruhezustand) oder Z (Zombie) befindet und länger als ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
keinen Vorwärtsfortschritt aufweist, beendet der llkd
den Prozess (oder den übergeordneten Prozess). ). Wenn ein nachfolgender Scan zeigt, dass derselbe Prozess weiterhin vorhanden ist, bestätigt der llkd
einen Live-Lock-Zustand und versetzt den Kernel auf eine Weise in Panik, die den detailliertesten Fehlerbericht für den Zustand liefert.
Der llkd
verfügt über einen Selbstüberwachungsmechanismus, der einen Alarm auslöst, wenn llkd
abstürzt. Der Watchdog dauert doppelt so lange wie erwartet, um durch die Hauptschleife zu fließen, und die Abtastung erfolgt alle ro.llk_sample_ms
.
Persistente Stack-Signatur
Bei Userdebug-Releases kann der llkd
Kernel-Live-Sperren mithilfe einer dauerhaften Stapelsignaturprüfung erkennen. Wenn ein Thread in einem beliebigen Status 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
gemeldet wird, bricht der llkd
den Prozess ab (auch wenn es eine Weiterleitung gibt). Planungsfortschritt). Wenn ein nachfolgender Scan zeigt, dass derselbe Prozess weiterhin vorhanden ist, bestätigt der llkd
einen Live-Lock-Zustand und versetzt den Kernel auf eine Weise in Panik, die den detailliertesten Fehlerbericht für den Zustand liefert.
Die lldk
Prüfung bleibt kontinuierlich bestehen, wenn die Live-Sperrbedingung vorliegt, und sucht unter Linux nach den zusammengesetzten Zeichenfolgen " symbol+0x"
oder " symbol.cfi+0x"
in der Datei /proc/pid/stack
. 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 so selten und kurzlebig sein, dass die Funktion auf einem typischen System während des Timeout-Zeitraums von ro.llk.stack.timeout_ms
nur einmal in einem Beispiel angezeigt wird (Beispiele treten alle ro.llk.check_ms
auf). Aufgrund des fehlenden ABA-Schutzes ist dies die einzige Möglichkeit, einen Fehlauslöser zu verhindern. Die Symbolfunktion muss unter der Funktion erscheinen, die die Sperre aufruft, die konkurrieren könnte. Befindet sich die Sperre unterhalb oder in der Symbolfunktion, erscheint das Symbol in allen betroffenen Prozessen, nicht nur in dem, der die Sperre verursacht hat.
Abdeckung
Die Standardimplementierung von llkd
überwacht die Spawns init
, [kthreadd]
oder [kthreadd]
nicht. Damit der llkd
[kthreadd]
-generierte Threads abdeckt:
- Treiber dürfen nicht in einem dauerhaften D-Zustand bleiben,
ODER
- Treiber müssen über Mechanismen verfügen, um den Thread wiederherzustellen, falls er extern beendet wird. 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 umfasst eine zusätzliche Prozess-Blacklist, um Sepolicy-Verstöße bei Diensten zu verhindern, die ptrace
Vorgänge 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 für Listen das Komma-Trennzeichen (,) verwenden, verwenden ein führendes Trennzeichen, um den Standardeintrag beizubehalten, und fügen dann Einträge mit optionalen Plus- (+) bzw. Minus-Präfixen (-) hinzu oder subtrahieren sie. Für diese Listen ist die Zeichenfolge „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
Das Gerät ist für Userdebug oder Eng Build konfiguriert.
ro.llk.sysrq_t
Wenn die Eigenschaft „eng“ ist, ist der Standardwert nicht ro.config.low_ram
oder ro.debuggable
. Wenn „true“, alle Threads sichern ( sysrq t
).
ro.llk.enable
Ermöglichen Sie die Aktivierung des Live-Lock-Daemons. Der Standardwert ist falsch.
llk.enable
Evaluiert für Motor-Builds. Der Standardwert ist ro.llk.enable
.
ro.khungtask.enable
Ermöglichen Sie die Aktivierung des [khungtask]
-Daemons. Der Standardwert ist falsch.
khungtask.enable
Evaluiert für Motor-Builds. Der Standardwert ist ro.khungtask.enable
.
ro.llk.mlockall
Aufruf von mlockall()
aktivieren. Der Standardwert ist falsch.
ro.khungtask.timeout
[khungtask]
maximales Zeitlimit. Der Standardwert beträgt 12 Minuten.
ro.llk.timeout_ms
Maximale Zeitbegrenzung D oder Z. Der Standardwert beträgt 10 Minuten. Verdoppeln Sie diesen Wert, um den Alarm-Watchdog für llkd
festzulegen.
ro.llk.D.timeout_ms
D maximale Zeitbegrenzung. Der Standardwert ist ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Z maximales Zeitlimit. Der Standardwert ist ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Überprüft das maximale Zeitlimit für persistente Stapelsymbole. Der Standardwert ist ro.llk.timeout_ms
. Nur bei Userdebug- oder Eng-Builds aktiv .
ro.llk.check_ms
Beispiele für Threads für D oder Z. Der Standardwert beträgt zwei Minuten.
ro.llk.stack
Prüft auf Kernel-Stack-Symbole, die, wenn sie dauerhaft vorhanden sind, darauf hinweisen können, dass ein Subsystem blockiert ist. Der Standardwert ist cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
durch Kommas getrennte Liste von Kernelsymbolen. Bei der Prüfung wird kein Forward Scheduling ABA durchgeführt, es sei denn, es werden alle ro.llk_check_ms
über den Zeitraum ro.llk.stack.timeout_ms
abgefragt. Stapelsymbole sollten daher außergewöhnlich selten und flüchtig sein (es ist höchst unwahrscheinlich, dass ein Symbol insgesamt dauerhaft angezeigt wird). Proben des Stapels). Prüft, ob in der Stack-Erweiterung eine Übereinstimmung für " symbol+0x"
oder " symbol.cfi+0x"
vorliegt. Nur für Userdebug- oder Eng-Builds verfügbar ; Sicherheitsbedenken bei Benutzer-Builds führen zu eingeschränkten Berechtigungen, die diese Überprüfung verhindern.
ro.llk.blacklist.process
Der llkd
überwacht die angegebenen Prozesse nicht. Der Standardwert 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 automatisierter Standardwert kann größer als die aktuelle maximale Eigenschaftsgröße von 92 sein.
ro.llk.blacklist.parent
Der llkd
überwacht keine Prozesse, die die angegebenen übergeordneten Elemente 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 übergeordnete Prozess nur in Kombination mit dem untergeordneten Zielprozess ignoriert wird. Das kaufmännische Und wurde ausgewählt, da es niemals Teil eines Prozessnamens ist. Allerdings erfordert ein setprop
in der Shell, dass das kaufmännische Und-Zeichen maskiert oder in Anführungszeichen gesetzt wird, obwohl die init rc
Datei, in der dies normalerweise angegeben wird, dieses Problem nicht aufweist. Ein übergeordneter oder Zielprozess kann eine comm
, cmdline
oder pid
Referenz sein.
ro.llk.blacklist.uid
Der llkd
überwacht keine Prozesse, die mit der/den angegebenen UID(s) übereinstimmen. Durch Kommas getrennte Liste von UID-Nummern oder -Namen. Der Standardwert ist leer oder falsch.
ro.llk.blacklist.process.stack
Der llkd
überwacht die angegebene Teilmenge der Prozesse nicht auf Live-Lock-Stack-Signaturen. Standard sind die 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 beschränkt (dies wird jedoch für Standardwerte ignoriert, die in der Datei
include/llkd.h
in den Quellen definiert sind). - Der integrierte
[khungtask]
-Daemon ist zu allgemein und greift zu oft auf Treibercode zurück, der im D-Zustand herumliegt. Durch den Wechsel zu S könnten Aufgaben beendet werden (und bei Bedarf von Treibern wiederbelebt werden).
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 den Zeitraum vor dem nächsten erwarteten Aufruf dieses Handlers zurück.