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

ตามข้อกำหนดเคอร์เนลของโมดูลที่นำมาใช้ใน Android 8.0 เคอร์เนลระบบบนชิป (SoC) ต้องรองรับโมดูลเคอร์เนลที่โหลดได้

ตัวเลือกการกำหนดค่าเคอร์เนล

เพื่อรองรับโมดูลเคอร์เนลที่โหลดได้ android-base.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 และ ขอแนะนำให้ใช้โมดูลเคอร์เนลในระบบนิเวศที่สูงกว่า ดังต่อไปนี้ ตารางแสดงการรองรับอุปกรณ์ต่อพ่วงสำหรับกระดานโดยเฉพาะซึ่งจำเป็นต้องมีใน 3 แพลตฟอร์ม โหมดเปิดเครื่องของ Android

โหมดเปิดเครื่อง พื้นที่เก็บข้อมูล จอแสดงผล ปุ่มกด แบตเตอรี่ 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 ขึ้นไป เพื่อให้สามารถโหลดโมดูลจากพาร์ติชันเหล่านี้ได้ การจัดสรร สร้างขึ้นเพื่อต่อเชื่อมพาร์ติชันตั้งแต่เนิ่นๆ สำหรับทั้ง 2 แบบ อุปกรณ์ที่ไม่ใช่ 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