ในฐานะที่เป็นส่วนหนึ่งของข้อกำหนดเคอร์เนลโมดูลที่เปิดตัวใน 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 เปิดใช้ CONFIG_MODULE_SIG_ALL=y
เพื่อให้การลงนามโมดูล GKI ในระหว่างการสร้าง GKI โดยใช้คู่คีย์เวลาสร้างของเคิร์นัลสะดวกขึ้น
คุณต้องเพิ่ม # CONFIG_MODULE_SIG_ALL is not set
เป็นส่วนหนึ่งของข้อมูลโค้ดสำหรับกำหนดค่าเคอร์เนลเพื่อหลีกเลี่ยงการเซ็นโมดูลที่ไม่ใช่ GKI ในระหว่างการสร้างเคอร์เนลของอุปกรณ์
ตำแหน่งไฟล์
แม้ว่า Android 7.x และเวอร์ชันที่ต่ำกว่าจะไม่บังคับใช้ข้อกำหนดเกี่ยวกับโมดูลเคอร์เนล (และรองรับ insmod
และ rmmod
) แต่ Android 8.x ขึ้นไปแนะนำให้ใช้โมดูลเคอร์เนลในระบบนิเวศ ตารางต่อไปนี้แสดงการรองรับอุปกรณ์ต่อพ่วงเฉพาะบอร์ดที่เป็นไปได้ซึ่งจำเป็นในโหมดการบูต Android 3 โหมด
โหมดเปิดเครื่อง | พื้นที่เก็บข้อมูล | จอแสดงผล | ปุ่มกด | แบตเตอรี่ | PMIC | หน้าจอสัมผัส | NFC, Wi-Fi, บลูทูธ |
เซ็นเซอร์ | กล้อง |
---|---|---|---|---|---|---|---|---|---|
การกู้คืน | |||||||||
ที่ชาร์จ | |||||||||
Android |
นอกจากความพร้อมใช้งานในโหมดการบูตของ Android แล้ว โมดูลเคอร์เนลยังอาจจัดหมวดหมู่ตามเจ้าของ (ผู้จำหน่าย SoC หรือ ODM) ด้วย หากมีการใช้โมดูลเคอร์เนล ข้อกำหนดสำหรับตำแหน่งของโมดูลในระบบไฟล์มีดังนี้
- เคอร์เนลทั้งหมดควรรองรับการบูตและการต่อเชื่อมพาร์ติชันในตัว
- ต้องโหลดโมดูลเคอร์เนลจากพาร์ติชันแบบอ่านอย่างเดียว
- สำหรับอุปกรณ์ที่ต้องเปิดเครื่องแบบยืนยันแล้ว ระบบควรโหลดโมดูลเคอร์เนลจากพาร์ติชันที่ได้รับการยืนยัน
- ไม่ควรวางโมดูลเคอร์เนลไว้ใน
/system
- ควรโหลดโมดูล GKI ที่จําเป็นสําหรับอุปกรณ์จาก
/system/lib/modules
ซึ่งเป็นลิงก์สัญลักษณ์ไปยัง/system_dlkm/lib/modules
- โมดูลเคอร์เนลจากผู้ให้บริการ SoC ที่จําเป็นสําหรับโหมด Android แบบเต็มหรือโหมดชาร์จควรอยู่ใน
/vendor/lib/modules
- หากมีพาร์ติชัน ODM อยู่ โมดูลเคอร์เนลจาก ODM ที่จําเป็นสําหรับโหมด Android แบบเต็มหรือโหมดชาร์จควรอยู่ใน
/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 จะจัดการการเรียกใช้ 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
ให้วิธีแก้ปัญหาโดยการตรวจหาข้อบกพร่องในอินเทอร์เฟซแบบไบนารีของแอปพลิเคชัน (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