Android Live-Lock Daemon (llkd)

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 von wait_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.