Android 10 menyertakan daemon live-lock Android
(llkd
), yang dirancang untuk menangkap dan mengurangi deadlock kernel. Komponen llkd
menyediakan implementasi mandiri default, tetapi Anda juga dapat
mengintegrasikan kode llkd
ke dalam layanan lain, baik sebagai bagian dari
loop utama atau sebagai thread terpisah.
Skenario deteksi
llkd
memiliki dua skenario deteksi: Status D atau Z persisten, dan tanda tangan
stack persisten.
Status D atau Z persisten
Jika thread berada dalam status D (uninterruptible sleep) atau Z (zombie) tanpa progres
maju selama lebih dari ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
, llkd
akan menghentikan proses (atau proses induk). Jika pemindaian berikutnya menunjukkan bahwa proses yang sama terus ada, llkd
akan mengonfirmasi kondisi live lock dan membuat kernel panik sedemikian rupa sehingga memberikan laporan bug paling mendetail untuk kondisi tersebut.
llkd
menyertakan watchdog mandiri yang berbunyi jika llkd
terkunci; watchdog
menggandakan waktu yang diharapkan untuk mengalir melalui mainloop dan pengambilan sampelnya adalah setiap
ro.llk_sample_ms
.
Tanda tangan stack persisten
Untuk rilis userdebug, llkd
dapat mendeteksi live-lock kernel menggunakan pemeriksaan
tanda tangan stack persisten. Jika thread dalam status apa pun kecuali Z memiliki simbol kernel ro.llk.stack
yang tercantum dan persisten yang dilaporkan lebih lama dari
ro.llk.timeout_ms
atau ro.llk.stack.timeout_ms
, llkd
akan menghentikan proses
(meskipun ada progres penjadwalan maju). Jika pemindaian berikutnya menunjukkan
proses yang sama terus ada, llkd
akan mengonfirmasi kondisi live-lock dan
membuatkan kernel panik dengan cara yang memberikan laporan bug paling mendetail untuk
kondisi tersebut.
Pemeriksaan lldk
terus berlanjut saat kondisi kunci aktif ada dan
mencari string gabungan symbol+0x
atau symbol.cfi+0x
dalam
file /proc/pid/stack
di Linux. Daftar simbol ada di ro.llk.stack
dan
secara default menggunakan daftar cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
yang dipisahkan koma.
Simbol harus jarang dan cukup singkat sehingga pada sistem biasa,
fungsi hanya terlihat sekali dalam sampel selama periode waktu tunggu
ro.llk.stack.timeout_ms
(sampel terjadi setiap ro.llk.check_ms
). Karena tidak adanya
perlindungan ABA, ini adalah satu-satunya cara untuk mencegah pemicu palsu. Fungsi
simbol harus muncul di bawah fungsi yang memanggil kunci yang dapat bersaing. Jika
kunci berada di bawah atau dalam fungsi simbol, simbol akan muncul di semua proses
yang terpengaruh, bukan hanya proses yang menyebabkan logo lengkap.
Cakupan
Implementasi default llkd
tidak memantau pembuatan init
, [kthreadd]
, atau
[kthreadd]
. Agar llkd
mencakup thread yang dihasilkan [kthreadd]
:
- Driver tidak boleh tetap dalam status D persisten,
ATAU
- Driver harus memiliki mekanisme untuk memulihkan thread jika dimatikan
secara eksternal. Misalnya, gunakan
wait_event_interruptible()
, bukanwait_event()
.
Jika salah satu kondisi di atas terpenuhi, daftar tolak llkd
dapat disesuaikan untuk
mencakup komponen kernel. Pemeriksaan simbol stack melibatkan daftar tolak proses tambahan untuk mencegah pelanggaran sepolicy pada layanan yang memblokir operasi ptrace
.
Properti Android
llkd
merespons beberapa properti Android (tercantum di bawah).
- Properti yang bernama
prop_ms
dalam milidetik. - Properti yang menggunakan pemisah koma (,) untuk daftar menggunakan pemisah awal untuk
mempertahankan entri default, lalu menambahkan atau mengurangi entri dengan awalan plus
(+) dan minus (-) opsional. Untuk daftar ini, string
false
sinonim dengan daftar kosong, dan entri kosong atau yang tidak ada akan menggunakan nilai default yang ditentukan.
{i>ro.config.low_ram<i}
Perangkat dikonfigurasi dengan memori terbatas.
ro.debuggable
Perangkat dikonfigurasi untuk build userdebug atau eng.
{i>ro.llk.sysrq_t<i}
Jika properti adalah eng
, defaultnya bukan ro.config.low_ram
atau ro.debuggable
.
Jika true
, dump semua thread (sysrq t
).
ro.llk.enable
Mengizinkan daemon live-lock diaktifkan. Default-nya adalah false
.
llk.enable
Dievaluasi untuk build eng. Default-nya adalah ro.llk.enable
.
ro.khungtask.enable
Mengizinkan daemon [khungtask]
diaktifkan. Default-nya adalah false
.
khungtask.enable
Dievaluasi untuk build teknis. Default-nya adalah ro.khungtask.enable
.
{i>ro.llk.mlockall<i}
Aktifkan panggilan ke mlockall()
. Default-nya adalah false
.
ro.khungtask.timeout
Batas waktu maksimum [khungtask]
. Waktu defaultnya adalah 12 menit.
ro.llk.timeout_ms
Batas waktu maksimum D atau Z. Waktu defaultnya adalah 10 menit. Gandakan nilai ini untuk menetapkan
watchdog alarm untuk llkd
.
ro.llk.D.timeout_ms
Batas waktu maksimum D. Defaultnya adalah ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Batas waktu maksimum Z. Defaultnya adalah ro.llk.timeout_ms
.
{i>ro.llk.stack.timeout_ms<i}
Memeriksa batas waktu maksimum simbol stack persisten. Defaultnya adalah
ro.llk.timeout_ms
. Hanya aktif di build userdebug atau eng.
ro.llk.check_ms
Contoh thread untuk D atau Z. Defaultnya adalah dua menit.
ro.llk.stack
Memeriksa simbol stack kernel yang jika terus-menerus ada dapat menunjukkan
subsistem terkunci. Defaultnya adalah
daftar simbol kernel yang dipisahkan koma
cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
. Pemeriksaan tidak melakukan penjadwalan maju
ABA kecuali dengan melakukan polling setiap ro.llk_check_ms
selama periode
ro.llk.stack.timeout_ms
, sehingga simbol stack seharusnya sangat jarang dan
selintas (simbol sangat tidak mungkin muncul secara terus-menerus di semua
sampel stack). Memeriksa kecocokan untuk symbol+0x
atau
symbol.cfi+0x
dalam perluasan stack. Hanya tersedia di build userdebug atau
eng; masalah keamanan pada build pengguna menghasilkan hak istimewa terbatas yang
mencegah pemeriksaan ini.
{i>ro.llk.blacklist.process<i}
llkd
tidak mengamati proses yang ditentukan. Defaultnya adalah 0,1,2
(kernel
,
init
, dan [kthreadd]
) ditambah nama proses
init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
.
Proses dapat berupa referensi comm
, cmdline
, atau pid
. Default otomatis bisa lebih besar dari ukuran properti maksimum saat ini, yaitu 92.
ro.llk.blacklist.parent
llkd
tidak memantau proses yang memiliki induk yang ditentukan. Defaultnya
adalah 0,2,adbd&[setsid]
(kernel
, [kthreadd]
, dan adbd
hanya untuk zombie
setsid
). Pemisah ampersand (&) menentukan bahwa induk hanya diabaikan
dalam kombinasi dengan proses turunan target. Ampersand dipilih karena
tidak pernah menjadi bagian dari nama proses; namun, setprop
dalam shell memerlukan
ampersand untuk di-escape atau diapit tanda kutip, meskipun file init rc
tempat hal ini
biasanya ditentukan tidak memiliki masalah ini. Proses induk atau target dapat berupa
referensi comm
, cmdline
, atau pid
.
ro.llk.blacklist.uid
llkd
tidak memantau proses yang cocok dengan UID yang ditentukan.
Daftar nama atau nomor UIS yang dipisahkan koma. Default-nya kosong atau false
.
ro.llk.blacklist.process.stack
llkd
tidak memantau subset proses yang ditentukan untuk tanda tangan tumpukan
kunci aktif. Defaultnya adalah nama proses
init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. Mencegah pelanggaran sepolicy
yang terkait dengan proses yang memblokir ptrace
(karena tidak dapat
diperiksa). Hanya aktif di build userdebug dan eng. Untuk mengetahui detail tentang jenis
build, lihat Building Android.
Masalah arsitektur
- Properti dibatasi hingga 92 karakter (tetapi, ini diabaikan untuk default
yang ditentukan dalam file
include/llkd.h
di sumber). - Daemon
[khungtask]
bawaan terlalu umum dan menempatkan kode driver yang terlalu lama berada dalam status D. Beralih ke S akan membuat tugas dapat dihentikan (dan dapat diaktifkan kembali oleh pengemudi jika perlu).
Antarmuka library (opsional)
Anda dapat menyertakan llkd
ke dalam daemon dengan hak istimewa lain secara opsional menggunakan
antarmuka C berikut dari komponen libllkd
:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
Jika nama thread diberikan, thread akan otomatis muncul. Jika tidak, pemanggil
harus memanggil llkCheckMilliseconds
dalam loop utamanya. Fungsi tersebut menampilkan jangka waktu sebelum panggilan yang diharapkan berikutnya ke pengendali ini.