เนื่องจากเป็นส่วนหนึ่งของข้อกำหนดเคอร์เนลของโมดูลที่นำมาใช้ใน Android 8.0 เคอร์เนลระบบบนชิป (SoC) ทั้งหมดจะต้องรองรับโมดูลเคอร์เนลที่โหลดได้
ตัวเลือกการกำหนดค่าเคอร์เนล
เพื่อรองรับโมดูลเคอร์เนลที่โหลดได้ android-base.config ในเคอร์เนลทั่วไปทั้งหมดจะมีตัวเลือก kernel-config ต่อไปนี้ (หรือเวอร์ชันเคอร์เนลที่เทียบเท่า):
CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y
เคอร์เนลของอุปกรณ์ทั้งหมดจะต้องเปิดใช้งานตัวเลือกเหล่านี้ โมดูลเคอร์เนลควรรองรับการขนถ่ายและโหลดซ้ำทุกครั้งที่เป็นไปได้
การลงนามโมดูล
ไม่รองรับการลงนามโมดูลสำหรับโมดูลผู้จำหน่าย GKI บนอุปกรณ์ที่ต้องรองรับการบูตที่ได้รับการตรวจสอบ Android กำหนดให้โมดูลเคอร์เนลอยู่ในพาร์ติชันที่เปิดใช้งาน dm-verity สิ่งนี้จะขจัดความจำเป็นในการลงนามโมดูลแต่ละโมดูลเพื่อความถูกต้อง Android 13 เปิดตัวแนวคิดของโมดูล GKI โมดูล GKI ใช้โครงสร้างพื้นฐานการลงนามเวลาบิลด์ของเคอร์เนลเพื่อแยกความแตกต่างระหว่าง GKI และโมดูลอื่นๆ ณ รันไทม์ โมดูลที่ไม่ได้ลงนามจะได้รับอนุญาตให้โหลดได้ตราบใดที่ใช้เฉพาะสัญลักษณ์ที่ปรากฏในรายการที่อนุญาตหรือจัดทำโดยโมดูลที่ไม่ได้ลงนามอื่นๆ เพื่ออำนวยความสะดวกในการลงนามโมดูล GKI ในระหว่างการสร้าง GKI โดยใช้คู่คีย์เวลาการสร้างของเคอร์เนล การกำหนดค่าเคอร์เนล GKI ได้เปิดใช้งาน CONFIG_MODULE_SIG_ALL=y
เพื่อหลีกเลี่ยงการลงนามโมดูลที่ไม่ใช่ GKI ในระหว่างการสร้างเคอร์เนลของอุปกรณ์ คุณต้องเพิ่ม # CONFIG_MODULE_SIG_ALL is not set
ให้เป็นส่วนหนึ่งของแฟรกเมนต์การกำหนดค่าเคอร์เนลของคุณ
ตำแหน่งไฟล์
แม้ว่า Android 7.x และต่ำกว่าจะไม่บังคับใช้กับโมดูลเคอร์เนล (และรวมถึงการรองรับ insmod
และ rmmod
) แต่ Android 8.x และสูงกว่าแนะนำให้ใช้โมดูลเคอร์เนลในระบบนิเวศ ตารางต่อไปนี้แสดงการสนับสนุนอุปกรณ์ต่อพ่วงเฉพาะบอร์ดที่เป็นไปได้ซึ่งจำเป็นสำหรับโหมดการบูต Android สามโหมด
โหมดบูต | พื้นที่จัดเก็บ | แสดง | ปุ่มกด | แบตเตอรี่ | พีเอ็มไอซี | หน้าจอสัมผัส | เอ็นเอฟซี, Wi-Fi, บลูทู ธ | เซนเซอร์ | กล้อง |
---|---|---|---|---|---|---|---|---|---|
การกู้คืน | |||||||||
ที่ชาร์จ | |||||||||
หุ่นยนต์ |
นอกเหนือจากความพร้อมใช้งานในโหมดการบูต Android แล้ว โมดูลเคอร์เนลยังอาจจัดหมวดหมู่ตามผู้ที่เป็นเจ้าของ (ผู้จำหน่าย SoC หรือ ODM) หากมีการใช้โมดูลเคอร์เนล ข้อกำหนดสำหรับการวางตำแหน่งในระบบไฟล์จะเป็นดังนี้:
- เคอร์เนลทั้งหมดควรมีการรองรับในตัวสำหรับการบูทและการติดตั้งพาร์ติชั่น
- ต้องโหลดโมดูลเคอร์เนลจากพาร์ติชันแบบอ่านอย่างเดียว
- สำหรับอุปกรณ์ที่ต้องมีการตรวจสอบการบูต ควรโหลดโมดูลเคอร์เนลจากพาร์ติชันที่ได้รับการตรวจสอบ
- โมดูลเคอร์เนลไม่ควรอยู่ใน
/system
- โมดูล GKI ที่จำเป็นสำหรับอุปกรณ์ควรโหลดจาก
/system/lib/modules
ซึ่งเป็นลิงก์สัญลักษณ์ไปยัง/system_dlkm/lib/modules
- โมดูลเคอร์เนลจากผู้จำหน่าย SoC ที่จำเป็นสำหรับโหมด Android หรือเครื่องชาร์จแบบเต็มควรอยู่ใน
/vendor/lib/modules
- หากมีพาร์ติชัน ODM โมดูลเคอร์เนลจาก ODM ที่จำเป็นสำหรับโหมด Android หรือ Charger แบบเต็มควรอยู่ใน
/odm/lib/modules
มิฉะนั้น โมดูลเหล่านี้ควรอยู่ใน/vendor/lib/modules
- โมดูลเคอร์เนลจากผู้ขาย SoC และ ODM ที่จำเป็นสำหรับโหมดการกู้คืนควรอยู่ใน
ramfs
การกู้คืนที่/lib/modules
- โมดูลเคอร์เนลที่จำเป็นสำหรับทั้งโหมดการกู้คืนและโหมด Android แบบเต็มหรือโหมดเครื่องชาร์จควรมีอยู่ใน
rootfs
การกู้คืนและพาร์ติชัน/vendor
หรือ/odm
(ตามที่อธิบายไว้ข้างต้น) - โมดูลเคอร์เนลที่ใช้ในโหมดการกู้คืนไม่ควรขึ้นอยู่กับโมดูลที่อยู่ใน
/vendor
หรือ/odm
เท่านั้น เนื่องจากพาร์ติชันเหล่านั้นไม่ได้ติดตั้งในโหมดการกู้คืน - โมดูลเคอร์เนลของผู้จำหน่าย SoC ไม่ควรขึ้นอยู่กับโมดูลเคอร์เนล ODM
ใน Android 7.x และต่ำกว่า พาร์ติ /vendor
และ /odm
จะ ไม่ ถูกเมาท์ตั้งแต่เนิ่นๆ ใน Android 8.x และสูงกว่า เพื่อให้โหลดโมดูลจากพาร์ติชันเหล่านี้ได้ จึงมีการเตรียมการเพื่อติดตั้งพาร์ติชันตั้งแต่เนิ่นๆ สำหรับทั้ง อุปกรณ์ที่ไม่ใช่ A/B และ A/B นอกจากนี้ยังช่วยให้แน่ใจว่าพาร์ติชันถูกติดตั้งทั้งในโหมด Android และโหมดเครื่องชาร์จ
รองรับระบบสร้าง Android
ใน BoardConfig.mk
บิลด์ Android จะกำหนดตัวแปร BOARD_VENDOR_KERNEL_MODULES
ที่จัดเตรียมรายการโมดูลเคอร์เนลทั้งหมดสำหรับอิมเมจของผู้จำหน่าย โมดูลที่แสดงในตัวแปรนี้จะถูกคัดลอกไปยังอิมเมจของผู้ขายที่ /lib/modules/
และหลังจากติดตั้งใน Android แล้ว จะปรากฏใน /vendor/lib/modules
(ตามข้อกำหนดข้างต้น) ตัวอย่างการกำหนดค่าโมดูลเคอร์เนลของผู้จำหน่าย:
vendor_lkm_dir := device/$(vendor)/lkm-4.x BOARD_VENDOR_KERNEL_MODULES := \ $(vendor_lkm_dir)/vendor_module_a.ko \ $(vendor_lkm_dir)/vendor_module_b.ko \ $(vendor_lkm_dir)/vendor_module_c.ko
ในตัวอย่างนี้ พื้นที่เก็บข้อมูลเคอร์เนลโมดูลของผู้จำหน่ายที่สร้างไว้ล่วงหน้าจะถูกแมปเข้ากับ Android บิลด์ในตำแหน่งที่แสดงด้านบน
อิมเมจการกู้คืนอาจมีชุดย่อยของโมดูลผู้จัดจำหน่าย โครงสร้าง Android กำหนดตัวแปร BOARD_RECOVERY_KERNEL_MODULES
สำหรับโมดูลเหล่านี้ ตัวอย่าง:
vendor_lkm_dir := device/$(vendor)/lkm-4.x BOARD_RECOVERY_KERNEL_MODULES := \ $(vendor_lkm_dir)/vendor_module_a.ko \ $(vendor_lkm_dir)/vendor_module_b.ko
Android build ดูแลการรัน depmod
เพื่อสร้างไฟล์ modules.dep
ที่จำเป็นใน /vendor/lib/modules
และ /lib/modules
( recovery ramfs
)
การโหลดโมดูลและการกำหนดเวอร์ชัน
โหลดโมดูลเคอร์เนลทั้งหมดในครั้งเดียวจาก init.rc*
โดยการเรียกใช้ modprobe -a
วิธีนี้จะหลีกเลี่ยงค่าใช้จ่ายในการเริ่มต้นสภาพแวดล้อมรันไทม์ C ซ้ำๆ สำหรับไบนารี modprobe
เหตุการณ์ early-init
สามารถแก้ไขได้เพื่อเรียกใช้ modprobe
:
on early-init exec u:r:vendor_modprobe:s0 -- /vendor/bin/modprobe -a -d \ /vendor/lib/modules module_a module_b module_c ...
โดยทั่วไปแล้ว โมดูลเคอร์เนลจะต้องถูกคอมไพล์ด้วยเคอร์เนลที่จะใช้กับโมดูลนั้น (ไม่เช่นนั้นเคอร์เนลจะปฏิเสธที่จะโหลดโมดูล) CONFIG_MODVERSIONS
ให้วิธีแก้ปัญหาโดยการตรวจจับการแตกหักใน Application Binary Interface (ABI) คุณสมบัตินี้จะคำนวณค่าการตรวจสอบความซ้ำซ้อนแบบวนรอบ (CRC) สำหรับต้นแบบของสัญลักษณ์ที่ส่งออกแต่ละรายการในเคอร์เนล และจัดเก็บค่าไว้เป็นส่วนหนึ่งของเคอร์เนล สำหรับสัญลักษณ์ที่ใช้โดยโมดูลเคอร์เนล ค่าจะถูกเก็บไว้ในโมดูลเคอร์เนลด้วย เมื่อโมดูลถูกโหลด ค่าของสัญลักษณ์ที่ใช้โดยโมดูลจะถูกเปรียบเทียบกับค่าในเคอร์เนล หากค่าตรงกัน โมดูลจะถูกโหลด มิฉะนั้นโหลดจะล้มเหลว
หากต้องการเปิดใช้งานการอัปเดตอิมเมจเคอร์เนลแยกจากอิมเมจของผู้จำหน่าย ให้เปิดใช้งาน CONFIG_MODVERSIONS
การทำเช่นนี้จะทำให้มีการอัพเดตเคอร์เนลเล็กน้อย (เช่น การแก้ไขจุดบกพร่องจาก LTS) ในขณะที่ยังคงรักษาความเข้ากันได้กับโมดูลเคอร์เนลที่มีอยู่ในอิมเมจของผู้จำหน่าย อย่างไรก็ตาม CONFIG_MODVERSIONS
ไม่สามารถแก้ไขการแตกของ ABI ได้ด้วยตัวเอง หากต้นแบบของสัญลักษณ์ที่ส่งออกในเคอร์เนลเปลี่ยนแปลง ไม่ว่าจะเกิดจากการดัดแปลงแหล่งที่มาหรือเนื่องจากการกำหนดค่าเคอร์เนลเปลี่ยนไป จะทำให้ความเข้ากันได้กับโมดูลเคอร์เนลที่ใช้สัญลักษณ์นั้นเสียหาย ในกรณีเช่นนี้ เคอร์เนลโมดูลจะต้องถูกคอมไพล์ใหม่
ตัวอย่างเช่น โครงสร้าง task_struct
ในเคอร์เนล (กำหนดใน include/linux/sched.h
) มีหลายฟิลด์ที่รวมตามเงื่อนไขขึ้นอยู่กับการกำหนดค่าเคอร์เนล ฟิลด์ sched_info
จะปรากฏเฉพาะเมื่อมีการเปิดใช้งาน CONFIG_SCHED_INFO
(ซึ่งเกิดขึ้นเมื่อเปิดใช้งาน CONFIG_SCHEDSTATS
หรือ CONFIG_TASK_DELAY_ACCT
) หากตัวเลือกการกำหนดค่าเหล่านี้เปลี่ยนสถานะ โครงร่างของโครงสร้าง task_struct
จะเปลี่ยนไปและอินเทอร์เฟซที่ส่งออกจากเคอร์เนลที่ใช้ task_struct
จะถูกเปลี่ยนแปลง (เช่น set_cpus_allowed_ptr
ใน kernel/sched/core.c
) ความเข้ากันได้กับโมดูลเคอร์เนลที่คอมไพล์ไว้ก่อนหน้านี้ซึ่งใช้อินเทอร์เฟซเหล่านี้ใช้งานไม่ได้ ทำให้โมดูลเหล่านั้นต้องสร้างขึ้นใหม่ด้วยการกำหนดค่าเคอร์เนลใหม่
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ CONFIG_MODVERSIONS
โปรดดูเอกสารประกอบในแผนผังเคอร์เนลที่ Documentation/kbuild/modules.rst