โมดูลเคอร์เนลที่โหลดได้

เนื่องจากเป็นส่วนหนึ่งของข้อกำหนดเคอร์เนลของโมดูลที่นำมาใช้ใน 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