טעינת מחיצות מראש

במכשירים שתומכים ב-Treble, חייבים להפעיל טעינה בשלב הראשון כדי לוודא הספק init יכול לטעון את Linux עם שיפור אבטחה (SELinux) קטעי מדיניות שמפוזרים על פני system ו- vendor מחיצות. הגישה הזו מאפשרת גם לטעון ליבה (kernel) בהקדם האפשרי אחרי אתחול הליבה.

כדי לבצע טעינה מוקדמת, ל-Android צריכה להיות גישה למערכות הקבצים ב- שבהם נמצאים המודולים. Android מגרסה 8.0 ואילך תומכת בטעינה /system, /vendor או /odm כבר עכשיו השלב הראשון של init (כלומר, לפני אתחול SElinux).

רשומות Fstab

ב-Android מגרסה 9 ומטה, אפשר לציין במכשירים fstab רשומות עבור מחיצות שהותקנו מראש באמצעות עץ המכשירים שכבות-על (DTO). ב-Android מגרסה 10 ואילך, המכשירים חייבים לציין fstab רשומות למחיצות שנטענו מוקדם באמצעות קובץ fstab בשלב הראשון ramdisk. במכשירי Android 10 מציג את הדגלים הבאים של fs_mgr לשימוש בקובץ fstab:

  • first_stage_mount מציין שקיימת מחיצה של השלב הראשון.
  • logical מציין חלוקה דינמית.
  • avb=vbmeta-partition-name מציין את הערך מחיצה vbmeta. השלב הראשון מאתחל את המחיצה לפני התקנת מחיצות אחרות. אפשר להשמיט את הארגומנט של הדגל הזה אם המחיצה vbmeta עבור הרשומה כבר צוינה על ידי רשומת fstab נוספת בשורה הקודמת.

הדוגמה הבאה מציגה רשומות של fstab כדי להגדיר את system, vendor ו-product מחיצות כמחיצות לוגיות (דינמיות).

#<dev>  <mnt_point> <type>  <mnt_flags options> <fs_mgr_flags>
system   /system     ext4    ro,barrier=1     wait,slotselect,avb=vbmeta_system,logical,first_stage_mount
vendor   /vendor     ext4    ro,barrier=1     wait,slotselect,avb=vbmeta,logical,first_stage_mount
product  /product    ext4    ro,barrier=1     wait,slotselect,avb,logical,first_stage_mount

בדוגמה זו, הספק מציין את המחיצה vbmeta באמצעות הדגל fs_mgr avb=vbmeta, אבל product משמט את הארגומנט vbmeta כי הספק כבר הוסיף vbmeta לרשימת המחיצות.

במכשירים עם Android מגרסה 10 ואילך חייבים להציב את קובץ fstab ב-ramdisk וב-vendor מחיצה.

רמדיסק

המיקום של קובץ fstab ב-ramdisk תלוי באופן שבו המכשיר משתמש ב-ramdisk.

מכשירים עם רדיסק אתחול חייבים להציב את השדה fstab בתיקיית השורש של RAMdisk האתחול. אם למכשיר יש גם רדיסק אתחול וגם ramdisk שחזור, לא נדרשים שינויים ברדיסק השחזור. דוגמה:

PRODUCT_COPY_FILES +=  device/google/<product-name>/fstab.hardware:$(TARGET_COPY_OUT_RAMDISK)/fstab.$(PRODUCT_PLATFORM)

מכשירים שמשתמשים בהם כ-Radisk חייבים להשתמש פרמטר שורת הפקודה androidboot.force_normal_boot=1 של הליבה ל- ולהחליט אם לבצע אתחול ב-Android או להמשיך בתהליך השחזור. מכשירים השקה עם Android מגרסה 12 ואילך עם גרסת ליבה (kernel) 5.10 ואילך חייבת להשתמש ב-bootconfig כדי להעביר את הפרמטר androidboot.force_normal_boot=1. לחשבון במכשירים האלה, השלב הראשון מבצע פעולת שורש של החלפה /first_stage_ramdisk לפני טעינת מחיצות הטעינה המוקדמות, לכן המכשירים חייבים למקם את הקובץ fstab $(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk. דוגמה:

PRODUCT_COPY_FILES +=  device/google/<product-name>/fstab.hardware:$(TARGET_COPY_OUT_RECOVERY)/root/first_stage_ramdisk/fstab.$(PRODUCT_PLATFORM)

ספק

בכל המכשירים צריך להעביר עותק של הקובץ fstab אל /vendor/etc. הסיבה לכך היא שהשלב הראשון משחרר אחרי שהיא מסיימת את ההתקנה המוקדמת של המחיצות ומבצעת החלפת פעולת הבסיס כדי להעביר את הטעינה ב-/system אל /. כל הפעולות הבאות שנדרשות כדי לגשת אל fstab לכן חייבים להשתמש בעותק שבקובץ /vendor/etc. דוגמה:

PRODUCT_COPY_FILES +=  device/google/<product-name>/fstab.hardware:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.$(PRODUCT_PLATFORM)

טעינת מחיצות בשלב מוקדם, VBoot 1.0

הדרישות לטעינה מוקדמת של מחיצות באמצעות VBoot 1.0 כוללות:

  1. נתיבי צמתים של מכשירים חייבים להשתמש בסמלי ה-by-name שלהם ב- רשומות fstab ועץ המכשיר. לדוגמה, במקום לציין מחיצות באמצעות /dev/block/mmcblk0pX, צריך לוודא שהמחיצות שם, וצומת המכשיר הוא /dev/block/…./by-name/{system,vendor,odm}.
  2. נתיבים שניתנו עבור PRODUCT_{SYSTEM,VENDOR}_VERITY_PARTITION ו CUSTOM_IMAGE_VERITY_BLOCK_DEVICE בהגדרת המכשיר של את המוצר (כלומר device/oem/project/device.mk) חייב להתאים הצמתים התואמים של המכשירים החסומים שצוינו by-name רשומות fstab/devicetree. דוגמה:
    PRODUCT_SYSTEM_VERITY_PARTITION := /dev/block/…./by-name/system
    PRODUCT_VENDOR_VERITY_PARTITION := /dev/block/…./by-name/vendor
    CUSTOM_IMAGE_VERITY_BLOCK_DEVICE := /dev/block/…./by-name/odm
    
  3. אסור שרשומות שסופקו באמצעות שכבות-על של עץ מכשירים לא יחזרו על עצמן fstab מקטעים של קובץ. לדוגמה, כשמציינים ערך של צריך לטעון את /vendor לעץ המכשיר, הקובץ fstab אסור לחזור על הרשומה הזו.
  4. אסור למחיצות שנדרשת בהן verifyatboot לבצע טעינה מוקדמת (הפעולה הזו לא נתמכת).
  5. יש לציין את מצב/מצב האימות של מחיצות מאומתות ב- kernel_cmdline עם אפשרות אחת (androidboot.veritymode) (דרישה קיימת).

התקנת devicetree מוקדמת, VBoot 1.0

ב-Android מגרסה 8.x ואילך, init מנתח את עץ המכשיר ו יוצרת רשומות fstab כדי לטעון את המחיצה מוקדם במהלך השלב הראשון. רשומת fstab תופיע בטופס:

src mnt_point type mnt_flags fs_mgr_flags

מאפייני Devicetree מוגדרים כך שמחקים את הפורמט הזה:

  • fstab רשומות חייבות להיות מתחת /firmware/android/fstab בעץ המכשיר וחייבת להיות לו המחרוזת התואמת שהוגדרה היא android,fstab.
  • כל צומת בערך /firmware/android/fstab נחשב ערך אחד של טעינה מוקדמת של fstab. צומת צריך לכלול: מאפיינים מוגדרים:
    • dev חייב להצביע על הצומת של המכשיר שמייצג את מחיצה by-name
    • type חייב להיות סוג מערכת הקבצים (כמו fstab קבצים)
    • mnt_flags חייב להיות רשימה מופרדת בפסיקים של דגלי טעינה (כמו ב-fstab קבצים)
    • fsmgr_flags חייבת להיות הרשימה של fs_mgr flags ב-Android (כמו ב-fstab קבצים)
  • למחיצות A/B חייבת להיות אפשרות slotselect fs_mgr.
  • מחיצות שמופעלות ב-dm-verity חייבות לכלול verify fs_mgr כאפשרות.

דוגמה: /system ו /vendor ב-N6P

בדוגמה הבאה מוצגת טעינה מוקדמת של עץ המכשיר עבור system ו-vendor מחיצות ב-Nexus 6P:

/ {
  firmware {
    android {
      compatible = "android,firmware";
      fstab {
        compatible = "android,fstab";
        system {
          compatible = "android,system";
          dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/system";
          type = "ext4";
          mnt_flags = "ro,barrier=1,inode_readahead_blks=8";
          fsmgr_flags = "wait,verify";
        };
        vendor {
          compatible = "android,vendor";
          dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor";
          type = "ext4";
          mnt_flags = "ro,barrier=1,inode_readahead_blks=8";
          fsmgr_flags = "wait";
        };
      };
    };
  };
};

לדוגמה: /vendor ב-Pixel

בדוגמה הבאה מוצגת טעינה מוקדמת של עץ המכשיר עבור /vendor ב-Pixel (חשוב לזכור להוסיף את slotselect למחיצות שכפופה A/B):

/ {
  firmware {
    android {
      compatible = "android,firmware";
      fstab {
        compatible = "android,fstab";
        vendor {
          compatible = "android,vendor";
          dev = "/dev/block/platform/soc/624000.ufshc/by-name/vendor";
          type = "ext4";
          mnt_flags = "ro,barrier=1,discard";
          fsmgr_flags = "wait,slotselect,verify";
        };
      };
    };
  };
};

טעינת מחיצות בשלב מוקדם, VBoot 2.0

VBoot 2.0 הוא אתחול מאומת של Android (AVB). הדרישות להשתתפות בתוכנית מחיצות טעינה עם VBoot 2.0 הן:

  1. נתיבי הצמתים של המכשיר חייבים להשתמש בסמלי הסימלין של by-name שלהם ב- רשומות fstab ועץ המכשיר. לדוגמה, במקום לציין מחיצות באמצעות /dev/block/mmcblk0pX, צריך לוודא שהמחיצות מופיעים שמות, וצומת המכשיר הוא /dev/block/…./by-name/{system,vendor,odm}.
  2. לבנות משתני מערכת (כמו PRODUCT_{SYSTEM,VENDOR}_VERITY_PARTITION והקבוצה CUSTOM_IMAGE_VERITY_BLOCK_DEVICE) משמש עבור VBoot 1.0 אינם נדרש ל-VBoot 2.0. במקום זאת, כדאי לבנות משתנים שהוכנסו ל-VBoot 2.0. צריך להגדיר (כולל BOARD_AVB_ENABLE := true). עבור הגדרות אישיות מלאות, יצירת שילוב מערכת ל-AVB.
  3. אסור שרשומות שסופקו באמצעות שכבות-על של עץ מכשירים לא יחזרו על עצמן fstab מקטעים של קובץ. לדוגמה, אם תציינו ערך עבור צריך לטעון את /vendor לעץ המכשיר, הקובץ fstab אסור לחזור על הרשומה הזו.
  4. ב-VBoot 2.0 אין תמיכה ב-verifyatboot, גם אם בטעינה מוקדמת מופעלת או לא מופעלת.
  5. יש לציין את מצב/מצב האימות של מחיצות מאומתות ב- kernel_cmdline באמצעות androidboot.veritymode אפשרות (דרישה קיימת). חשוב לכלול את התיקונים הבאים לגבי AVB:

התקנת devicetree מוקדמת, VBoot 2.0

ההגדרה ב-devicetree של VBoot 2.0 זהה לזו שב- VBoot 1.0, עם התג החריגים הבאים:

  • הערך בעמודה fsmgr_flag השתנה מ-verify ל- avb.
  • כל המחיצות עם מטא-נתונים של AVB חייבות להיות ברשומת VBMeta מכשיר, גם אם המחיצה לא נטענת מוקדם (לדוגמה, /boot).

דוגמה: /system ו /vendor ב-N5X

בדוגמה הבאה מוצגת טעינה מוקדמת של עץ המכשיר עבור מחיצות system ו-vendor ב-Nexus 5X. הערה:

  • /system נטען עם AVB ו-/vendor הוא טעונה ללא אימות תקינות.
  • ב-Nexus 5X אין מחיצת /vbmeta, לכן ברמה העליונה vbmeta נמצאת בסוף המחיצה /boot (לפרטים, תוכלו למצוא מידע נוסף ברשימת השינויים של AOSP).
    / {
      firmware {
        android {
          compatible = "android,firmware";
          vbmeta {
            compatible = "android,vbmeta";
            parts = "boot,system,vendor";
          };
          fstab {
            compatible = "android,fstab";
            system {
              compatible = "android,system";
              dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/system";
              type = "ext4";
              mnt_flags = "ro,barrier=1,inode_readahead_blks=8";
              fsmgr_flags = "wait,avb";
            };
            vendor {
              compatible = "android,vendor";
              dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor";
              type = "ext4";
              mnt_flags = "ro,barrier=1,inode_readahead_blks=8";
              fsmgr_flags = "wait";
            };
          };
        };
      };
    };
    

לדוגמה: /vendor ב-Pixel

בדוגמה הבאה רואים טעינה של /vendor בשלב מוקדם של Pixel. הערה:

  • מחיצות נוספות מפורטות ברשומת vbmeta מכיוון שהמחיצות האלה הן מוגנות באמצעות AVB.
  • צריך לכלול את כל מחיצות ה-AVB, גם אם רק /vendor עם טעינה מוקדמת.
  • חשוב לזכור להוסיף את slotselect למחיצות שכפופים ל-A/B.
    / {
      vbmeta {
        compatible = "android,vbmeta";
        parts = "vbmeta,boot,system,vendor,dtbo";
      };
      firmware {
        android {
          compatible = "android,firmware";
          fstab {
            compatible = "android,fstab";
            vendor {
              compatible = "android,vendor";
              dev = "/dev/block/platform/soc/624000.ufshc/by-name/vendor";
              type = "ext4";
              mnt_flags = "ro,barrier=1,discard";
              fsmgr_flags = "wait,slotselect,avb";
            };
          };
        };
      };
    };