מודולים של ליבה שניתן לטעינה

כחלק מדרישות הליבה של המודול שהוצגו ב-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 משתמשים בתשתית החתימה של הליבה בזמן ה-build כדי להבדיל בין GKI לבין מודולים אחרים בזמן הריצה. מותר לטעון מודולים ללא חתימה כל עוד הם משתמשים רק בסמלים שמופיעים ברשימת ההיתרים או שסופקו על ידי מודולים אחרים ללא חתימה. כדי לאפשר חתימה על מודולים של GKI במהלך ה-build של GKI באמצעות זוג המפתחות של הליבה בזמן ה-build, הפעלנו את CONFIG_MODULE_SIG_ALL=y בתצורת הליבה של GKI. כדי להימנע מחתימה על מודולים שאינם GKI במהלך גרסאות build של ליבה של מכשיר, צריך להוסיף את # CONFIG_MODULE_SIG_ALL is not set כחלק מקטעי התצורה של הליבה.

מיקומי קבצים

ב-Android 7.x ואילך אין איסור על שימוש במודולים של ליבה (וגם תמיכה ב-insmod וב-rmmod), אבל ב-Android 8.x ואילך מומלץ להשתמש במודולים של ליבה בסביבה העסקית. בטבלה הבאה מפורטת תמיכה אפשרית בציוד היקפי ספציפי ללוח, שנדרשת בשלושה מצבי אתחול של Android.

מצב הפעלה אחסון תצוגה לוח חיוג סוללה PMIC מסך מגע NFC, ‏ Wi-Fi,
Bluetooth
חיישנים מצלמה
שחזור
מטען
Android

בנוסף לזמינות במצבי האתחול של Android, אפשר גם לסווג את מודולי הליבה לפי הבעלים שלהם (ספק ה-SoC או ה-ODM). אם משתמשים במודולים של ליבה, הדרישות למיקום שלהם במערכת הקבצים הן:

  • כל הליבות צריכות לכלול תמיכה מובנית בהפעלה ובטעינה של מחיצות.
  • מודולים של ליבה חייבים להיות נטענים ממחיצה לקריאה בלבד.
  • במכשירים שנדרשת להם הפעלה מאומתת, צריך לטעון את המודולים של הליבה ממחיצות מאומתות.
  • אסור למקם מודולים של ליבה ב-/system.
  • צריך לטעון את המודולים של GKI הנדרשים למכשיר מ-/system/lib/modules, שהוא קישור סימבולי ל-/system_dlkm/lib/modules.
  • מודולי הליבה של ספק ה-SOC שנדרשים למצבי Android או Charger מלאים צריכים להיות ב-/vendor/lib/modules.
  • אם יש מחיצה של ODM, מודולי הליבה של ODM שנדרשים למצבים מלאים של Android או Charger צריכים להיות ב-/odm/lib/modules. אחרת, המודולים האלה צריכים להיות ב-/vendor/lib/modules.
  • מודולי הליבה של ספק ה-SoC ושל ה-ODM הנדרשים למצב Recovery צריכים להיות ב-ramfs של Recovery‏ /lib/modules.
  • מודולי הליבה הנדרשים גם למצב שחזור וגם למצב Android מלא או למצב מטען צריכים להופיע גם במחיצה rootfs של התאוששות וגם במחיצה /vendor או /odm (כפי שמתואר למעלה).
  • מודולים של ליבה שמשמשים במצב שחזור לא צריכים להיות תלויים במודולים שנמצאים רק ב-/vendor או ב-/odm, כי המחיצות האלה לא מותקנות במצב שחזור.
  • אסור שמודולים של ליבה של ספקי SoC יהיו תלויים במודולים של ליבה של ODM.

ב-Android מגרסה 7.x ומטה, המחיצות /vendor ו-/odm לא מורכבות מוקדם. ב-Android מגרסה 8.x ואילך, כדי לאפשר את טעינת המודול מהמחיצות האלה, בוצעו ההכנות להרכבת המחיצות בשלב מוקדם גם במכשירים ללא בדיקת A/B וגם במכשירים עם בדיקת A/B. כך אפשר לוודא שהמחיצות מותקנות גם במצב Android וגם במצב מטען.

תמיכה במערכת build של Android

ב-BoardConfig.mk, build של 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

בדוגמה הזו, מאגר של מודול ליבה של ספק שנוצר מראש ממופה ל-build של 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

ה-build של Android גורם להרצה של depmod כדי ליצור את הקבצים הנדרשים מסוג modules.dep ב-/vendor/lib/modules וב-/lib/modules (recovery ramfs).

טעינה של מודולים וניהול גרסאות

אפשר לטעון את כל המודולים של הליבה בבת אחת מ-init.rc* על ידי הפעלת modprobe -a. כך אפשר להימנע מהעלות של אתחול חוזר של סביבת זמן הריצה של C עבור קובץ ה-binary 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). תיפגע התאימות עם מודולי הליבה שעבר קודם הרצה ב-GCC ומשתמשים בממשקים האלה, ולכן יהיה צורך לבנות מחדש את המודולים האלה עם הגדרת הליבה החדשה.

למידע נוסף על CONFIG_MODVERSIONS, אפשר לעיין במסמכי העזרה בעץ הליבה בכתובת Documentation/kbuild/modules.rst.