Android 10 ประกอบด้วย Android Live-LocK Daemon ( llkd
) ซึ่งออกแบบมาเพื่อตรวจจับและลดปัญหาการหยุดชะงักของเคอร์เนล คอมโพเนนต์ llkd
จัดเตรียมการใช้งานแบบสแตนด์อโลนที่เป็นค่าเริ่มต้น แต่คุณสามารถรวมโค้ด llkd
เข้ากับบริการอื่นได้ ไม่ว่าจะเป็นส่วนหนึ่งของลูปหลักหรือแยกเป็นเธรด
สถานการณ์การตรวจจับ
llkd
มีสองสถานการณ์การตรวจจับ: สถานะ D หรือ Z ถาวร และลายเซ็นสแต็กถาวร
สถานะ D หรือ Z ถาวร
หากเธรดอยู่ในสถานะ D (uninterruptible sleep) หรือ Z (zombie) โดยไม่มีความคืบหน้านานกว่า ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
llkd
จะฆ่ากระบวนการ (หรือกระบวนการหลัก) ). หากการสแกนที่ตามมาแสดงกระบวนการเดิมที่ยังคงมีอยู่ llkd
ยืนยันเงื่อนไขการล็อกแบบสด และทำให้เคอร์เนลตื่นตระหนกในลักษณะที่ให้รายงานจุดบกพร่องที่มีรายละเอียดมากที่สุดสำหรับเงื่อนไข
llkd
รวมถึงสุนัขเฝ้าบ้านที่เตือนถ้า llkd
ล็อก; watchdog เพิ่มขึ้นเป็นสองเท่าของเวลาที่คาดว่าจะไหลผ่าน mainloop และการสุ่มตัวอย่างคือทุกๆ ro.llk_sample_ms
ลายเซ็นสแต็กถาวร
สำหรับ userdebug release นั้น llkd
สามารถตรวจจับเคอร์เนล live-locks ได้โดยใช้การตรวจสอบลายเซ็นสแต็กแบบถาวร หากเธรดในสถานะใดๆ ยกเว้น Z มีสัญลักษณ์เคอร์เนล ro.llk.stack
ที่แสดงอยู่ถาวรซึ่งรายงานนานกว่า ro.llk.timeout_ms
หรือ ro.llk.stack.timeout_ms
llkd
จะฆ่ากระบวนการ (แม้ว่าจะมีการส่งต่อ ความคืบหน้าการจัดกำหนดการ) หากการสแกนที่ตามมาแสดงกระบวนการเดิมที่ยังคงมีอยู่ llkd
ยืนยันเงื่อนไขการล็อกแบบสด และทำให้เคอร์เนลตื่นตระหนกในลักษณะที่ให้รายงานจุดบกพร่องที่มีรายละเอียดมากที่สุดสำหรับเงื่อนไข
การตรวจสอบ lldk
คงอยู่อย่างต่อเนื่องเมื่อมีเงื่อนไขการล็อกอยู่และค้นหาสตริงที่ประกอบด้วย " symbol+0x"
หรือ " symbol.cfi+0x"
ในไฟล์ /proc/pid/stack
บน Linux รายการสัญลักษณ์อยู่ใน ro.llk.stack
และค่าเริ่มต้นเป็นรายการที่คั่นด้วยเครื่องหมายจุลภาคของ " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
"
สัญลักษณ์ควรหายากและมีอายุสั้นมากพอที่ระบบทั่วไปจะเห็นฟังก์ชันเพียงครั้งเดียวในตัวอย่างในช่วงหมดเวลาของ ro.llk.stack.timeout_ms
(ตัวอย่างเกิดขึ้นทุก ro.llk.check_ms
) เนื่องจากขาดการป้องกัน ABA นี่เป็นวิธีเดียวที่จะป้องกันการทริกเกอร์ที่ผิดพลาด ฟังก์ชันสัญลักษณ์ต้องปรากฏด้านล่างฟังก์ชันที่เรียกการล็อกที่สามารถโต้แย้งได้ หากล็อคอยู่ด้านล่างหรือในฟังก์ชันสัญลักษณ์ สัญลักษณ์จะปรากฏในกระบวนการที่ได้รับผลกระทบทั้งหมด ไม่ใช่แค่กระบวนการที่ทำให้เกิดการล็อก
ความคุ้มครอง
การใช้งานเริ่มต้นของ llkd
ไม่ได้ตรวจสอบการวางไข่ init
, [kthreadd]
หรือ [kthreadd]
เพื่อให้ llkd
ครอบคลุม [kthreadd]
- เธรดที่เกิด:
- ผู้ขับขี่ต้องไม่อยู่ในสถานะ D ถาวร
หรือ
- ไดรเวอร์ต้องมีกลไกในการกู้คืนเธรดหากเธรดถูกกำจัดจากภายนอก ตัวอย่างเช่น ใช้
wait_event_interruptible()
แทนwait_event()
หากตรงตามเงื่อนไขข้อใดข้อหนึ่งข้างต้น บัญชีดำ llkd
สามารถปรับให้ครอบคลุมส่วนประกอบเคอร์เนลได้ การตรวจสอบสัญลักษณ์กองซ้อนเกี่ยวข้องกับบัญชีดำของกระบวนการเพิ่มเติมเพื่อป้องกันการละเมิดการแบ่งแยกดินแดนในบริการที่บล็อกการดำเนินการ ptrace
คุณสมบัติ Android
llkd
ตอบสนองต่อคุณสมบัติ Android หลายประการ (รายการด้านล่าง)
- คุณสมบัติที่ชื่อ
prop_ms
มีหน่วยเป็นมิลลิวินาที - คุณสมบัติที่ใช้เครื่องหมายจุลภาค (,) ตัวคั่นสำหรับรายการใช้ตัวคั่นนำหน้าเพื่อรักษารายการเริ่มต้น จากนั้นเพิ่มหรือลบรายการด้วยคำนำหน้าบวก (+) และลบ (-) ตามลำดับ สำหรับรายการเหล่านี้ สตริง "เท็จ" มีความหมายเหมือนกันกับรายการว่าง และรายการว่างหรือรายการที่ขาดหายไปจะใช้ค่าเริ่มต้นที่ระบุ
ro.config.low_ram
อุปกรณ์ได้รับการกำหนดค่าด้วยหน่วยความจำที่จำกัด
ro.debuggable
อุปกรณ์ได้รับการกำหนดค่าสำหรับ userdebug หรือ eng build
ro.llk.sysrq_t
หากคุณสมบัติคือ "eng" ค่าดีฟอลต์จะไม่ใช่ ro.config.low_ram
หรือ ro.debuggable
หากเป็น true ให้ดัมพ์เธรดทั้งหมด ( sysrq t
)
ro.llk.enable
อนุญาตให้เปิดใช้งาน live-lock daemon ค่าเริ่มต้นเป็นเท็จ
llk.enable
ประเมินสำหรับการสร้าง eng ค่าเริ่มต้นคือ ro.llk.enable
ro.khungtask.enable
อนุญาตให้เปิดใช้งาน [khungtask]
daemon ค่าเริ่มต้นเป็นเท็จ
khungtask.enable
ประเมินสำหรับการสร้าง eng ค่าเริ่มต้นคือ ro.khungtask.enable
ro.llk.mlockall
เปิดใช้งานการเรียก mlockall()
ค่าเริ่มต้นเป็นเท็จ
ro.khungtask.timeout
[khungtask]
จำกัดเวลาสูงสุด. ค่าเริ่มต้นคือ 12 นาที
ro.llk.timeout_ms
D หรือ Z จำกัดเวลาสูงสุด ค่าเริ่มต้นคือ 10 นาที เพิ่มค่านี้เป็นสองเท่าเพื่อตั้งนาฬิกาปลุกสำหรับ llkd
ro.llk.D.timeout_ms
D ขีด จำกัด เวลาสูงสุด ค่าเริ่มต้นคือ ro.llk.timeout_ms
ro.llk.Z.timeout_ms
Z ขีด จำกัด เวลาสูงสุด ค่าเริ่มต้นคือ ro.llk.timeout_ms
ro.llk.stack.timeout_ms
ตรวจสอบการจำกัดเวลาสูงสุดของสัญลักษณ์สแต็กถาวร ค่าเริ่มต้นคือ ro.llk.timeout_ms
ใช้งานเฉพาะใน userdebug หรือ eng builds
ro.llk.check_ms
ตัวอย่างเธรดสำหรับ D หรือ Z ค่าเริ่มต้นคือสองนาที
ro.llk.stack
ตรวจสอบสัญลักษณ์สแต็กเคอร์เนลที่หากปรากฏอย่างต่อเนื่องสามารถบ่งชี้ว่าระบบย่อยถูกล็อค ค่าเริ่มต้นคือ cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
รายการสัญลักษณ์เคอร์เนลที่คั่นด้วยเครื่องหมายจุลภาค การตรวจสอบจะไม่ดำเนินการจัดกำหนดการ ABA ล่วงหน้า ยกเว้นโดยการสำรวจทุก ro.llk_check_ms
ตลอดระยะเวลา ro.llk.stack.timeout_ms
ดังนั้นสัญลักษณ์กองซ้อนควรหายากเป็นพิเศษและหายวับไป (ไม่น่าเป็นไปได้สูงที่สัญลักษณ์จะแสดงอย่างถาวรในทุกกรณี ตัวอย่างของสแต็ก) ตรวจสอบการจับคู่สำหรับ " symbol+0x"
หรือ " symbol.cfi+0x"
ในการขยายสแต็ก มีเฉพาะใน userdebug หรือ eng builds เท่านั้น ข้อกังวลด้านความปลอดภัยเกี่ยวกับการสร้างผู้ใช้ส่งผลให้เกิดการจำกัดสิทธิ์ที่ป้องกันการตรวจสอบนี้
ro.llk.blacklist.process
llkd
ไม่ได้ดูกระบวนการที่ระบุ ค่าเริ่มต้นคือ 0,1,2
( kernel
, init
และ [kthreadd]
) บวกชื่อกระบวนการ init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
. กระบวนการสามารถเป็นการอ้างอิง comm
, cmdline
หรือ pid
ค่าเริ่มต้นอัตโนมัติอาจมีขนาดใหญ่กว่าขนาดคุณสมบัติสูงสุดปัจจุบันที่ 92
ro.llk.blacklist.parent
llkd
ไม่ดูกระบวนการที่มีพาเรนต์ที่ระบุ ค่าเริ่มต้นคือ 0,2,adbd&[setsid]
( kernel
, [kthreadd]
และ adbd
สำหรับ zombie setsid
เท่านั้น) ตัวคั่นเครื่องหมายและ (&) ระบุว่าพาเรนต์ถูกละเว้นร่วมกับกระบวนการลูกเป้าหมายเท่านั้น เครื่องหมายและถูกเลือกเนื่องจากไม่เคยเป็นส่วนหนึ่งของชื่อกระบวนการ อย่างไรก็ตาม setprop
ในเชลล์ต้องการเครื่องหมาย ampersand เพื่อหลีกเลี่ยงหรืออ้างอิง แม้ว่าไฟล์ init rc
ที่ระบุโดยปกติจะไม่มีปัญหานี้ กระบวนการพาเรนต์หรือเป้าหมายสามารถเป็นการอ้างอิง comm
, cmdline
หรือ pid
ro.llk.blacklist.uid
llkd
ไม่ดูกระบวนการที่ตรงกับ uid ที่ระบุ รายการหมายเลขหรือชื่อ uid ที่คั่นด้วยเครื่องหมายจุลภาค ค่าเริ่มต้นว่างเปล่าหรือเท็จ
ro.llk.blacklist.process.stack
llkd
ไม่ได้มอนิเตอร์ชุดย่อยที่ระบุของกระบวนการสำหรับลายเซ็นสแต็กล็อกแบบสด ค่าเริ่มต้นคือชื่อกระบวนการ init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
ป้องกันการละเมิด sepolicy ที่เกี่ยวข้องกับกระบวนการที่บล็อก ptrace
(เนื่องจากไม่สามารถตรวจสอบได้) ใช้งานได้เฉพาะกับ userdebug และ eng builds สำหรับรายละเอียดเกี่ยวกับประเภทบิลด์ โปรดดู การ สร้าง Android
ความกังวลด้านสถาปัตยกรรม
- คุณสมบัติถูกจำกัดไว้ที่ 92 อักขระ (อย่างไรก็ตาม ค่านี้จะถูกละเว้นสำหรับค่าดีฟอลต์ที่กำหนดไว้ในไฟล์
include/llkd.h
ในแหล่งที่มา) -
[khungtask]
daemon ในตัวนั้นธรรมดาเกินไปและมีการสะดุดของรหัสไดรเวอร์ที่อยู่ในสถานะ D มากเกินไป การเปลี่ยนไปใช้ S จะทำให้งานสามารถฆ่าได้ (และฟื้นคืนชีพได้โดยไดรเวอร์หากจำเป็น)
อินเทอร์เฟซห้องสมุด (ไม่บังคับ)
คุณสามารถเลือกรวม llkd
เข้ากับ daemon ที่มีสิทธิพิเศษอื่นโดยใช้อินเตอร์เฟส C ต่อไปนี้จากคอมโพเนนต์ libllkd
:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
หากมีการระบุชื่อเธรด เธรดจะวางไข่โดยอัตโนมัติ มิฉะนั้นผู้เรียกจะต้องเรียก llkCheckMilliseconds
ในลูปหลัก ฟังก์ชันส่งกลับช่วงเวลาก่อนการเรียกครั้งต่อไปที่คาดหวังไปยังตัวจัดการนี้