Daemon live-lock Android (llkd)

Android 10 menyertakan daemon live-lock Android (llkd), yang dirancang untuk menangkap dan mengurangi deadlock kernel. llkd menyediakan implementasi mandiri {i>default<i}, tetapi Anda juga dapat atau mengintegrasikan kode llkd ke layanan lain, baik sebagai bagian dari di loop utama atau sebagai thread terpisah.

Skenario deteksi

llkd memiliki dua skenario deteksi: status D atau Z persisten, dan status ciri khas{i> stack<i}.

Status D atau Z persisten

Jika thread berada dalam status D (tidur tanpa gangguan) atau Z (zombie) tanpa maju progres yang lebih lama dari ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms, llkd menghentikan proses (atau proses induk). Jika pemindaian berikutnya menunjukkan proses yang sama tetap ada, llkd mengonfirmasi kondisi {i>live-lock<i} dan panik {i>kernel<i} dengan cara yang dapat memberikan laporan {i>bug<i} paling rinci untuk .

llkd menyertakan watchdog mandiri yang melakukan alarm jika llkd terkunci; watchdog adalah menggandakan waktu yang diharapkan untuk mengalir melalui mainloop dan pengambilan sampel ro.llk_sample_ms.

Tanda tangan stack persisten

Untuk rilis debug pengguna, llkd dapat mendeteksi live-lock kernel menggunakan metode pemeriksaan tanda tangan tumpukan. Jika thread dalam status apa pun kecuali Z memiliki terdaftar simbol kernel ro.llk.stack yang dilaporkan lebih lama dari ro.llk.timeout_ms atau ro.llk.stack.timeout_ms, llkd akan menghentikan proses (meskipun ada progres penjadwalan yang diteruskan). Jika pemindaian berikutnya menunjukkan proses yang sama tetap ada, llkd mengonfirmasi kondisi {i>live-lock<i} dan panik {i>kernel<i} dengan cara yang dapat memberikan laporan {i>bug<i} paling rinci untuk .

Pemeriksaan lldk terus berlanjut saat kondisi live lock terjadi dan mencari string tersusun symbol+0x atau symbol.cfi+0x dalam File /proc/pid/stack di Linux. Daftar simbol ada di ro.llk.stack dan secara default adalah daftar yang dipisahkan koma, cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable.

Simbol harus langka dan berumur pendek sehingga pada sistem biasa hanya terlihat sekali dalam sampel selama periode waktu tunggu ro.llk.stack.timeout_ms (contoh terjadi setiap ro.llk.check_ms). Karena kurangnya perlindungan ABA, ini adalah satu-satunya cara untuk mencegah pemicu palsu. Simbol harus muncul di bawah fungsi yang memanggil gembok yang dapat bersaing. Jika gembok berada di bawah atau dalam fungsi simbol, simbol akan muncul di semua proses, bukan hanya yang menyebabkan {i>lockup<i}.

Cakupan

Implementasi default llkd tidak memantau init, [kthreadd], atau [kthreadd] muncul. Agar llkd dapat mencakup thread yang dibuat [kthreadd]:

  • Pengemudi tidak boleh tetap dalam status D persisten,

ATAU

  • Driver harus memiliki mekanisme untuk memulihkan thread jika thread tersebut dimatikan secara eksternal. Misalnya, gunakan wait_event_interruptible(), bukan wait_event().

Jika salah satu kondisi di atas terpenuhi, daftar tolak llkd dapat disesuaikan menjadi membahas komponen {i>kernel<i}. Pemeriksaan simbol {i>stack <i}melibatkan proses tambahan daftar tolak untuk mencegah pelanggaran sepolicy pada layanan yang memblokir ptrace operasional bisnis.

Properti Android

llkd merespons beberapa properti Android (tercantum di bawah).

  • Properti dengan nama prop_ms dalam milidetik.
  • Properti yang menggunakan pemisah koma (,) untuk daftar menggunakan pemisah di awal untuk mempertahankan entri {i>default<i}, lalu menambah atau mengurangi entri dengan tanda plus opsional Setiap awalan (+) dan minus (-). Untuk daftar ini, string false identik dengan daftar kosong, dan entri kosong atau tidak ada dimasukkan ke nilai default yang ditentukan.

{i>ro.config.low_ram<i}

Perangkat dikonfigurasi dengan memori terbatas.

dapat di-debug

Perangkat dikonfigurasi untuk userdebug atau build ing.

{i>ro.llk.sysrq_t<i}

Jika properti adalah eng, defaultnya bukan ro.config.low_ram atau ro.debuggable. Jika true, buang semua thread (sysrq t).

{i>ro.llk.enable<i}

Izinkan pengaktifan daemon live-lock. Defaultnya adalah false.

{i>llk.enable<i}

Dievaluasi untuk build teknis. Defaultnya adalah ro.llk.enable.

{i>ro.khungtask.enable<i}

Izinkan daemon [khungtask] diaktifkan. Defaultnya adalah false.

{i>khungtask.enable<i}

Dievaluasi untuk build teknis. Defaultnya adalah ro.khungtask.enable.

{i>ro.llk.mlockall<i}

Aktifkan panggilan ke mlockall(). Defaultnya adalah false.

{i>ro.khungtask.timeout<i}

Batas waktu maksimum [khungtask]. Defaultnya adalah 12 menit.

{i>ro.llk.timeout_ms<i}

Batas waktu maksimum D atau Z. Defaultnya adalah 10 menit. Gandakan nilai ini untuk menyetel watchdog alarm untuk llkd.

{i>ro.llk.D.timeout_ms<i}

Batas waktu maksimum D. Defaultnya adalah ro.llk.timeout_ms.

{i>ro.llk.Z.timeout_ms<i}

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 userdebug atau build ENG.

{i>ro.llk.check_ms<i}

Contoh thread untuk D atau Z. Defaultnya adalah dua menit.

{i>ro.llk.stack<i}

Pemeriksaan simbol tumpukan kernel yang jika ada secara terus-menerus dapat menunjukkan subsistem terkunci. Defaultnya adalah cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable simbol {i>kernel<i} yang dipisahkan koma. Pemeriksaan ini tidak melakukan penjadwalan penerusan ABA kecuali dengan polling setiap ro.llk_check_ms selama periode yang dipilih ro.llk.stack.timeout_ms, jadi simbol stack akan sangat jarang dan sekilas (sangat tidak mungkin simbol muncul terus-menerus di semua contoh stack). Memeriksa kecocokan untuk symbol+0x atau symbol.cfi+0x dalam perluasan tumpukan. Hanya tersedia di userdebug atau Inggris build; masalah keamanan pada build pengguna mengakibatkan keterbatasan hak istimewa 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]) plus 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.

{i>ro.llk.blacklist.parent<i}

llkd tidak mengamati proses yang memiliki induk yang ditentukan. Default adalah 0,2,adbd&[setsid] (kernel, [kthreadd], dan adbd hanya untuk zombie setsid). Pemisah dan (&) menentukan bahwa induk hanya diabaikan dalam kombinasi dengan proses turunan target. Ampersand dipilih karena bukan pernah menjadi bagian dari nama proses; namun, setprop dalam shell memerlukan ampersand untuk di-escape atau diberi tanda kutip, meskipun dalam file init rc tempatnya berada biasanya tidak memiliki masalah ini. Proses induk atau target dapat berupa Referensi comm, cmdline, atau pid.

{i>ro.llk.blacklist.uid<i}

llkd tidak mengamati proses yang cocok dengan UID yang ditentukan. Daftar nomor atau nama UIS yang dipisahkan koma. Defaultnya adalah kosong atau false.

{i>ro.llk.blacklist.process.stack<i}

llkd tidak memantau subset proses yang ditentukan untuk stack live lock tanda tangan. Defaultnya adalah nama proses init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd. Mencegah sepolicy pelanggaran yang terkait dengan proses yang memblokir ptrace (karena tidak dapat dicentang). Hanya aktif di userdebug dan build ing. Untuk mengetahui detail tentang build jenis, lihat Building Android.

Masalah arsitektur

  • Properti dibatasi hingga 92 karakter (tetapi akan diabaikan untuk default yang ditentukan dalam file include/llkd.h dalam sumber).
  • Daemon [khungtask] bawaan terlalu umum dan melakukan perjalanan pada kode pengemudi yang terlalu banyak berada di status D. Beralih ke S akan membuat tugas selesai (dan dapat dihidupkan kembali oleh pengemudi jika diperlukan).

Antarmuka library (opsional)

Secara opsional, Anda dapat menggabungkan llkd ke daemon dengan hak istimewa lain 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 akan muncul harus memanggil llkCheckMilliseconds di loop utamanya. Fungsi tersebut mengembalikan periode waktu sebelum panggilan yang diharapkan berikutnya ke pengendali ini.