Daemon Live-Lock Android (llkd)

Android 10 menyertakan Android Live-Lock Daemon ( llkd ), yang dirancang untuk menangkap dan mengurangi kebuntuan kernel. Komponen llkd menyediakan implementasi mandiri default, namun Anda juga dapat mengintegrasikan kode llkd ke layanan lain, baik sebagai bagian dari loop utama atau sebagai thread terpisah.

Skenario deteksi

llkd memiliki dua skenario deteksi: status D atau Z yang persisten, dan tanda tangan tumpukan yang persisten.

Status D atau Z yang persisten

Jika thread berada dalam status D (uninterruptible sleep) atau Z (zombie) tanpa progres lebih lama dari ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms , llkd akan menghentikan proses (atau proses induk ). Jika pemindaian berikutnya menunjukkan proses yang sama tetap ada, llkd mengonfirmasi kondisi live-lock dan membuat kernel panik dengan cara yang memberikan laporan bug paling detail untuk kondisi tersebut.

llkd mencakup pengawas mandiri yang memberi peringatan jika llkd terkunci; pengawas adalah dua kali lipat waktu yang diharapkan untuk mengalir melalui mainloop dan pengambilan sampel adalah setiap ro.llk_sample_ms .

Tanda tangan tumpukan yang persisten

Untuk rilis userdebug, llkd dapat mendeteksi live-lock kernel menggunakan pemeriksaan tanda tangan tumpukan yang persisten. Jika thread di negara bagian mana pun kecuali Z memiliki simbol kernel ro.llk.stack yang terdaftar secara persisten dan dilaporkan lebih lama dari ro.llk.timeout_ms atau ro.llk.stack.timeout_ms , llkd akan menghentikan proses (walaupun ada penerusan kemajuan penjadwalan). Jika pemindaian berikutnya menunjukkan proses yang sama tetap ada, llkd mengonfirmasi kondisi live-lock dan membuat kernel panik dengan cara yang memberikan laporan bug paling detail untuk kondisi tersebut.

Pemeriksaan lldk berlanjut terus menerus ketika kondisi live lock ada dan mencari string yang tersusun " symbol+0x" atau " symbol.cfi+0x" di file /proc/pid/stack di Linux. Daftar simbol ada di ro.llk.stack dan defaultnya adalah daftar " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable " yang dipisahkan koma.

Simbol harus langka dan berumur pendek sehingga pada sistem tipikal, fungsinya hanya terlihat sekali dalam sampel selama periode waktu habis ro.llk.stack.timeout_ms (sampel muncul setiap ro.llk.check_ms ). Karena kurangnya perlindungan ABA, ini adalah satu-satunya cara untuk mencegah pemicu palsu. Simbol fungsi harus muncul di bawah fungsi pemanggil kunci yang dapat bersaing. Jika kuncinya berada di bawah atau di dalam fungsi simbol, simbol tersebut akan muncul di semua proses yang terpengaruh, bukan hanya proses yang menyebabkan penguncian.

Cakupan

Implementasi default llkd tidak memantau init , [kthreadd] , atau [kthreadd] muncul. Agar llkd menutupi [kthreadd] - thread yang muncul:

  • Pengemudi tidak boleh terus-menerus berada dalam kondisi D,

ATAU

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

Jika salah satu kondisi di atas terpenuhi, daftar hitam llkd dapat disesuaikan untuk mencakup komponen kernel. Pemeriksaan simbol tumpukan melibatkan proses daftar hitam tambahan untuk mencegah pelanggaran sepolicy pada layanan yang memblokir operasi ptrace .

Properti Android

llkd merespons beberapa properti Android (tercantum di bawah).

  • Properti bernama prop_ms dalam milidetik.
  • Properti yang menggunakan pemisah koma (,) untuk daftar menggunakan pemisah di depan untuk mempertahankan entri default, lalu menambah atau mengurangi entri dengan awalan opsional plus (+) dan minus (-). Untuk daftar ini, string "false" identik dengan daftar kosong, dan entri kosong atau hilang menggunakan nilai default yang ditentukan.

ro.config.low_ram

Perangkat dikonfigurasi dengan memori terbatas.

ro.debuggable

Perangkat dikonfigurasi untuk userdebug atau eng build.

ro.llk.sysrq_t

Jika propertinya "eng", defaultnya bukan ro.config.low_ram atau ro.debuggable . Jika benar, buang semua thread ( sysrq t ).

ro.llk.enable

Izinkan daemon live-lock diaktifkan. Standarnya salah.

llk.enable

Dievaluasi untuk build bahasa Inggris. Standarnya adalah ro.llk.enable .

ro.khungtask.enable

Izinkan daemon [khungtask] diaktifkan. Standarnya salah.

khungtask.aktifkan

Dievaluasi untuk build bahasa Inggris. Standarnya adalah ro.khungtask.enable .

ro.llk.mlockall

Aktifkan panggilan ke mlockall() . Standarnya salah.

ro.khungtask.timeout

[khungtask] batas waktu maksimum. Standarnya adalah 12 menit.

ro.llk.timeout_ms

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

ro.llk.D.timeout_ms

D batas waktu maksimum. Standarnya adalah ro.llk.timeout_ms .

ro.llk.Z.timeout_ms

Z batas waktu maksimum. Standarnya adalah ro.llk.timeout_ms .

ro.llk.stack.timeout_ms

Memeriksa batas waktu maksimum simbol tumpukan yang persisten. Standarnya adalah ro.llk.timeout_ms . Hanya aktif di userdebug atau eng builds .

ro.llk.check_ms

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

ro.llk.stack

Memeriksa simbol tumpukan kernel yang jika terus ada dapat mengindikasikan subsistem terkunci. Defaultnya adalah cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable Daftar simbol kernel yang dipisahkan koma. Pemeriksaan tidak melakukan penjadwalan maju ABA kecuali dengan melakukan polling setiap ro.llk_check_ms selama periode ro.llk.stack.timeout_ms , jadi simbol tumpukan harus sangat jarang dan cepat berlalu (sangat tidak mungkin simbol muncul terus-menerus di semua sampel tumpukan). Memeriksa kecocokan untuk " symbol+0x" atau " symbol.cfi+0x" dalam perluasan tumpukan. Hanya tersedia di userdebug atau eng build ; masalah keamanan pada build pengguna mengakibatkan terbatasnya hak istimewa yang mencegah pemeriksaan ini.

ro.llk.blacklist.proses

llkd tidak memperhatikan 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] . Suatu 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 mengawasi proses yang memiliki induk tertentu. Defaultnya adalah 0,2,adbd&[setsid] ( kernel , [kthreadd] , dan adbd hanya untuk zombie setsid ). Pemisah ampersand (&) menetapkan bahwa induk diabaikan hanya jika dikombinasikan dengan proses anak target. Ampersand dipilih karena tidak pernah menjadi bagian dari nama proses; namun, setprop di shell mengharuskan ampersand di-escape atau dikutip, meskipun file init rc yang biasanya ditentukan tidak mengalami masalah ini. Proses induk atau target dapat berupa referensi comm , cmdline , atau pid .

ro.llk.blacklist.uid

llkd tidak mengawasi proses yang cocok dengan uid yang ditentukan. Daftar nomor atau nama uid yang dipisahkan koma. Defaultnya kosong atau salah.

ro.llk.blacklist.proses.stack

llkd tidak memantau subset proses yang ditentukan untuk tanda tangan tumpukan kunci langsung. Defaultnya adalah nama proses init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . Mencegah pelanggaran sepolicy yang terkait dengan proses yang memblokir ptrace (karena ini tidak dapat diperiksa). Hanya aktif di userdebug dan eng builds . Untuk mengetahui detail tentang tipe build, lihat Membangun Android .

Masalah arsitektur

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

Antarmuka perpustakaan (opsional)

Anda juga dapat memasukkan llkd ke dalam daemon istimewa lainnya 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 disediakan, thread otomatis muncul, jika tidak, pemanggil harus memanggil llkCheckMilliseconds di loop utamanya. Fungsi ini mengembalikan periode waktu sebelum panggilan berikutnya yang diharapkan ke pengendali ini.