واحدهای هسته بارشدنی

به‌عنوان بخشی از الزامات هسته واحد معرفی‌شده در 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 و نسخه‌های بالاتر استفاده از واحد هسته در بوم‌سازگان را توصیه می‌کنند. جدول زیر پشتیبانی جانبی مختص برد بالقوه موردنیاز در سه حالت راه‌اندازی 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 یا 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 نسخه ۸.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 مراجعه کنید.