עדכוני מערכת דינמיים

עדכוני מערכת דינמיים (DSU) מאפשרים ליצור קובץ אימג' של מערכת Android, שמשתמשים יכולים להוריד מהאינטרנט ולנסות בלי סיכון לפגוע בקובץ האימג' הנוכחי של המערכת. במסמך הזה נסביר איך לתמוך ב-DSU.

דרישות הליבה

הדרישות לגרעין מפורטות במאמר הטמעת מחיצות דינמיות.

בנוסף, DSU מסתמך על תכונת הליבה device-mapper-verity‏ (dm-verity) כדי לאמת את קובץ האימג' של מערכת Android. לכן צריך להפעיל את הגדרות הליבה הבאות:

  • CONFIG_DM_VERITY=y
  • CONFIG_DM_VERITY_FEC=y

דרישות למחיצות

החל מ-Android 11, כדי להשתמש ב-DSU, צריך להשתמש במערכת הקבצים F2FS או ext4 במחיצה /data. פורמט F2FS מספק ביצועים טובים יותר ומומלץ להשתמש בו, אבל ההבדל אמור להיות זניח.

ריכזנו כאן כמה דוגמאות למשך הזמן של עדכון מערכת דינמי במכשיר Pixel:

  • שימוש ב-F2FS:
    • 109 שניות, משתמש 8GB, מערכת 867M, סוג מערכת קבצים: F2FS: encryption=aes-256-xts:aes-256-cts
    • 104 שניות, 8GB משתמש, 867MB מערכת, סוג מערכת קבצים: F2FS: encryption=ice
  • שימוש ב-ext4:
    • 135 שניות, 8GB משתמש, 867M מערכת, סוג מערכת קבצים: ext4: encryption=aes-256-xts:aes-256-cts

אם הפעולה נמשכת הרבה יותר זמן בפלטפורמה שלכם, כדאי לבדוק אם דגל ההצמדה מכיל דגל כלשהו שגורם לכתיבה מסוג 'sync', או לציין דגל 'async' באופן מפורש כדי לשפר את הביצועים.

מחיצת metadata (16MB או יותר) נדרשת לאחסון נתונים שקשורים לתמונות המותקנות. צריך להתקין אותו במהלך ההתקנה של השלב הראשון.

במחיצה userdata צריך להשתמש במערכת קבצים מסוג F2FS או ext4. כשמשתמשים ב-F2FS, צריך לכלול את כל התיקונים שקשורים ל-F2FS שזמינים בליבת Android המשותפת.

DSU פותח ונבדק עם kernel/common 4.9. מומלץ להשתמש בליבה מגרסה 4.9 ואילך כדי להשתמש בתכונה הזו.

התנהגות HAL של הספק

Weaver HAL

ה-HAL של weaver מספק מספר קבוע של משבצות לאחסון מפתחות משתמשים. ה-DSU תופס שני חריצי מפתחות נוספים. אם ל-OEM יש HAL של weaver, צריכים להיות לו מספיק משבצות לתמונת מערכת גנרית (GSI) ולתמונת מארח.

Gatekeeper HAL

Gatekeeper HAL צריך לתמוך בערכים גדולים של USER_ID, כי GSI מעביר את מזהי ה-UID ל-HAL עם הזזה של 1000000.

אימות האתחול

אם רוצים לתמוך בהפעלה של תמונות GSI למפתחים במצב נעול בלי להשבית את האתחול המאומת, צריך לכלול מפתחות GSI למפתחים על ידי הוספת השורה הבאה לקובץ device/<device_name>/device.mk:

$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)

הגנה מפני רולבק

כשמשתמשים ב-DSU, קובץ האימג' של מערכת Android שהורדתם צריך להיות חדש יותר מקובץ האימג' הנוכחי של המערכת במכשיר. כדי לעשות זאת, משווים בין רמות תיקוני האבטחה בתיאור המאפיין של AVB ב-Android Verified Boot (AVB) בשתי קובצי האימג' של המערכת: Prop: com.android.build.system.security_patch -> '2019-04-05'.

במכשירים שלא משתמשים ב-AVB, צריך להוסיף את רמת תיקון האבטחה של קובץ האימג' הנוכחי של המערכת ל-cmdline או ל-bootconfig של הליבה באמצעות תוכנת האתחול:androidboot.system.security_patch=2019-04-05.

דרישות חומרה

כשמריצים מכונה של DSU, מוקצים שני קבצים זמניים:

  • מחיצה לוגית לאחסון GSI.img (1-1.5 G)
  • מחיצה ריקה של 8GB ב-/data כארגז חול להרצת ה-GSI

מומלץ להקצות לפחות 10GB של שטח פנוי לפני שמפעילים מכונה של DSU. DSU תומך גם בהקצאה מכרטיס SD. כאשר מוכנס כרטיס SD, הוא מקבל את העדיפות הגבוהה ביותר להקצאה. תמיכה בכרטיס SD חיונית למכשירים עם הספק נמוך, שאולי אין להם מספיק אחסון פנימי. אם יש כרטיס SD, חשוב לוודא שהוא לא אומץ. אין תמיכה ב-DSU בכרטיסי SD מאוחדים.

ממשקי קצה זמינים

אפשר להפעיל את DSU באמצעות adb, אפליקציית OEM או מנטען DSU בקליק אחד (ב-Android 11 ואילך).

הפעלת DSU באמצעות adb

כדי להפעיל את DSU באמצעות adb, מזינים את הפקודות הבאות:

$ simg2img out/target/product/.../system.img system.raw
$ gzip -c system.raw > system.raw.gz
$ adb push system.raw.gz /storage/emulated/0/Download
$ adb shell am start-activity \
-n com.android.dynsystem/com.android.dynsystem.VerificationActivity  \
-a android.os.image.action.START_INSTALL    \
-d file:///storage/emulated/0/Download/system.raw.gz  \
--el KEY_SYSTEM_SIZE $(du -b system.raw|cut -f1)  \
--el KEY_USERDATA_SIZE 8589934592

הפעלת DSU באמצעות אפליקציה

נקודת הכניסה הראשית ל-DSU היא ה-API של android.os.image.DynamicSystemClient.java:

public class DynamicSystemClient {


...
...

     /**
     * Start installing DynamicSystem from URL with default userdata size.
     *
     * @param systemUrl A network URL or a file URL to system image.
     * @param systemSize size of system image.
     */
    public void start(String systemUrl, long systemSize) {
        start(systemUrl, systemSize, DEFAULT_USERDATA_SIZE);
    }

צריך לצרף את האפליקציה הזו לחבילה או להתקין אותה מראש במכשיר. מכיוון ש-DynamicSystemClient הוא ממשק API של מערכת, אי אפשר ליצור את האפליקציה באמצעות ממשק ה-API הרגיל של ה-SDK, ואי אפשר לפרסם אותה ב-Google Play. מטרת האפליקציה הזו היא:

  1. אחזור רשימת תמונות וכתובת ה-URL התואמת באמצעות סכמה שהוגדרה על ידי הספק.
  2. להתאים את התמונות ברשימה למכשיר ולהציג תמונות תואמות למשתמש לבחירה.
  3. מפעילים את DynamicSystemClient.start כך:

    DynamicSystemClient aot = new DynamicSystemClient(...)
       aot.start(
            ...URL of the selected image...,
            ...uncompressed size of the selected image...);
    
    

כתובת ה-URL מפנה לקובץ קובץ אימג' של מערכת בפורמט gzip, לא דליל, שאפשר ליצור באמצעות הפקודות הבאות:

$ simg2img ${OUT}/system.img ${OUT}/system.raw
$ gzip ${OUT}/system.raw
$ ls ${OUT}/system.raw.gz

שם הקובץ צריך להיות בפורמט הזה:

<android version>.<lunch name>.<user defined title>.raw.gz

לדוגמה:

  • o.aosp_taimen-userdebug.2018dev.raw.gz
  • p.aosp_taimen-userdebug.2018dev.raw.gz

מעבד DSU בלחיצה אחת

ב-Android 11 נוסף מערך DSU loader בלחיצה אחת, שהוא ממשק קצה בהגדרות הפיתוח.

הפעלת מערך האתחול של DSU

איור 1. הפעלת מערך האתחול של DSU

כשהמפתח לוחץ על הלחצן DSU Loader, מתבצע אחזור של מתאר DSU JSON שהוגדר מראש מהאינטרנט, וכל התמונות הרלוונטיות מוצגות בתפריט הצף. בוחרים קובץ אימג' כדי להתחיל את התקנת DSU, וההתקדמות תוצג בסרגל ההתראות.

ההתקדמות בהתקנת קובץ האימג&#39; של DSU

איור 2. ההתקדמות בהתקנת קובץ האימג' של DSU

כברירת מחדל, מערך הטעינה של DSU טוען מתאר JSON שמכיל את קובצי האימג' של GSI. בחלקים הבאים מוסבר איך ליצור חבילות DSU בחתימה של יצרן ציוד מקורי (OEM) ולטעון אותן מהמטען של DSU.

מתג feature flag

התכונה DSU נמצאת ב-feature flag‏ settings_dynamic_android. לפני שמשתמשים ב-DSU, צריך לוודא שסימן ההפעלה של התכונה הרלוונטית מופעל.

הפעלת ה-feature flag.

איור 3. הפעלת ה-feature flag

יכול להיות שממשק המשתמש של ה-feature flag לא יהיה זמין במכשיר שבו פועל build של משתמש. במקרה כזה, צריך להשתמש בפקודה adb במקום זאת:

$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1

אירוח של קובצי אימג' של מערכת על ידי ספק ב-GCE (אופציונלי)

אחד ממיקומי האחסון האפשריים של קובצי האימג' של המערכת הוא הקטגוריה של Google Compute Engine‏ (GCE). האדמין של הגרסה משתמש במסוף האחסון של GCP כדי להוסיף, למחוק או לשנות את קובץ האימג' של המערכת שפורסם.

התמונות צריכות להיות גלויות לכולם, כפי שמוצג כאן:

גישה ציבורית ב-GCE

איור 4. גישה ציבורית ב-GCE

במסמכי התיעוד של Google Cloud מוסבר איך להפוך פריט לציבורי.

DSU עם כמה מחיצות בקובץ ZIP

החל מגרסה 11 של Android, ל-DSU יכול להיות יותר ממחיצה אחת. לדוגמה, הוא יכול להכיל product.img בנוסף ל-system.img. כשהמכשיר מופעל, השלב הראשון init מזהה את המחיצות של DSU שמותקנות ומחליף את המחיצה במכשיר באופן זמני, כש-DSU שמותקן מופעל. חבילה של DSU עשויה להכיל מחיצה שאין לה מחיצה תואמת במכשיר.

תהליך DSU עם מספר מחיצות

איור 5. תהליך DSU עם מספר מחיצות

DSU בחתימה של OEM

כדי לוודא שכל קובצי האימג' שפועלים במכשיר אושרו על ידי יצרן המכשיר, צריך לחתום על כל קובצי האימג' בחבילת DSU. לדוגמה, נניח שיש חבילת DSU שמכילה שתי תמונות של מחיצות, כמו בדוגמה הבאה:

dsu.zip {
    - system.img
    - product.img
}

קובצי system.img ו-product.img צריכים להיות חתומים על ידי מפתח ה-OEM לפני שמוסיפים אותם לקובץ ה-ZIP. השיטה הנפוצה היא להשתמש באלגוריתם אסימטרי, למשל RSA, שבו המפתח הסודי משמש לחתימה על החבילה והמפתח הציבורי משמש לאימות שלה. דיסק ה-RAM של השלב הראשון חייב לכלול את המפתח הציבורי לצורך התאמה, לדוגמה, /avb/*.avbpubkey. אם המכשיר כבר אימץ את AVB, תהליך החתימה הקיים יספיק. בקטעים הבאים מוסבר תהליך החתימה ומתואר המיקום של מפתח ה-AVB הציבורי שמשמש לאימות התמונות בחבילת ה-DSU.

מתאר JSON של DSU

מתאר ה-JSON של DSU מתאר את חבילות ה-DSU. יש בו תמיכה בשני רכיבים בסיסיים. קודם כול, הפרימיטיב include כולל תיאורי JSON נוספים או מפנה את מערך הטעינה של DSU למיקום חדש. לדוגמה:

{
    "include": ["https://.../gsi-release/gsi-src.json"]
}

שנית, הפרימיטיב image משמש לתיאור חבילות DSU שפורסמו. בתוך הרכיב הבסיסי של התמונה יש כמה מאפיינים:

  • המאפיינים name ו-details הם מחרוזות שמוצגות בתיבת הדו-שיח כדי שהמשתמש יוכל לבחור.

  • המאפיינים cpu_api,‏ vndk ו-os_version משמשים לבדיקות תאימות שמתוארות בקטע הבא.

  • המאפיין האופציונלי pubkey מתאר את המפתח הציבורי שמתאימים למפתח הסודי שמשמש לחתימה על חבילת ה-DSU. כשהיא מצוינה, שירות ה-DSU יכול לבדוק אם במכשיר יש את המפתח שמשמש לאימות חבילת ה-DSU. כך אפשר למנוע התקנה של חבילת DSU לא מזוהה, למשל התקנה של DSU שנחתם על ידי OEM-A במכשיר שנוצר על ידי OEM-B.

  • המאפיין האופציונלי tos מפנה לקובץ טקסט שמתאר את התנאים וההגבלות של חבילת ה-DSU המתאימה. כשמפתח בוחר בחבילת DSU עם מאפיין של התנאים וההגבלות, נפתחת תיבת הדו-שיח שמוצגת באיור 6, ומופיעה בקשה מהמפתח לאשר את התנאים וההגבלות לפני התקנת חבילת ה-DSU.

    תיבת הדו-שיח &#39;התנאים וההגבלות&#39;

    איור 6. תיבת הדו-שיח 'התנאים וההגבלות'

לידיעתכם, הנה מתאר JSON של DSU ל-GSI:

{
   "images":[
      {
         "name":"GSI+GMS x86",
         "os_version":"10",
         "cpu_abi": "x86",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
         "uri":"https://.../gsi/gsi_gms_x86-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI+GMS ARM64",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
         "uri":"https://.../gsi/gsi_gms_arm64-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI ARM64",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "uri":"https://.../gsi/aosp_arm64-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI x86_64",
         "os_version":"10",
         "cpu_abi": "x86_64",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "uri":"https://.../gsi/aosp_x86_64-exp-QP1A.190711.020.C4-5928301.zip"
      }
   ]
}

ניהול תאימות

יש כמה מאפיינים שמשמשים לציון התאימות בין חבילת DSU למכשיר המקומי:

  • cpu_api היא מחרוזת שמתארת את ארכיטקטורת המכשיר. המאפיין הזה הוא חובה, והוא מושווה לנכס המערכת ro.product.cpu.abi. הערכים שלהם חייבים להיות זהים.

  • os_version הוא מספר שלם אופציונלי שמציין גרסה של Android. לדוגמה, ב-Android 10, הערך של os_version הוא 10 וב-Android 11, הערך של os_version הוא 11. כשמציינים את המאפיין הזה, הוא חייב להיות שווה למאפיין המערכת ro.system.build.version.release או גדול ממנו. הבדיקה הזו משמשת למניעת אתחול של קובץ אימג' של GSI מגרסה 10 של Android במכשיר של ספק עם Android מגרסה 11, כי אין כרגע תמיכה בכך. מותר להפעיל את קובץ האימג' של GSI ב-Android 11 במכשיר Android 10.

  • vndk הוא מערך אופציונלי שמציין את כל ה-VNDKs שכלולים בחבילת ה-DSU. כשהאפשרות הזו מצוינה, מעבד ההטענה של DSU בודק אם המספר שחולץ מנכס המערכת ro.vndk.version נכלל.

ביטול מפתחות DSU למטרות אבטחה

במקרה הנדיר ביותר שבו זוהתה פריצה לזוג המפתחות מסוג RSA שמשמש לחתימה על קובצי האימג' של DSU, צריך לעדכן את ה-ramdisk בהקדם האפשרי כדי להסיר את המפתח שנפרץ. בנוסף לעדכון של מחיצת האתחול, אפשר לחסום מפתחות שנחשפו באמצעות רשימת ביטול של מפתחות DSU (רשימת מפתחות שחורה) מכתובת URL מסוג HTTPS.

רשימת ביטול המפתחות של DSU מכילה רשימה של מפתחות ציבוריים של AVB שבוטלו. במהלך התקנת DSU, המפתחות הציבוריים בתוך קובצי האימג' של DSU מאומתים באמצעות רשימת הביטולים. אם מתגלה שהתמונות מכילות מפתח ציבורי מבוטל, תהליך ההתקנה של DSU מושהה.

כתובת ה-URL של רשימת ביטול המפתחות צריכה להיות כתובת URL מסוג HTTPS כדי להבטיח את חוזק האבטחה, והיא מצוינה במחרוזת משאבים:

frameworks/base/packages/DynamicSystemInstallationService/res/values/strings.xml@key_revocation_list_url

הערך של המחרוזת הוא https://dl.google.com/developers/android/gsi/gsi-keyblacklist.json, שהיא רשימת ביטולים של מפתחות GSI ש-Google פרסמה. אפשר להוסיף שכבה על מחרוזת המשאב הזו ולהתאים אותה אישית, כדי ש-OEMs שמאמצים את תכונת DSU יוכלו לספק ולתחזק רשימת מפתחות שחורה משלהם. כך יצרן הציוד המקורי יכול לחסום מפתחות ציבוריים מסוימים בלי לעדכן את קובץ האימג' של ה-ramdisk במכשיר.

הפורמט של רשימת הביטולים הוא:

{
   "entries":[
      {
         "public_key":"bf14e439d1acf231095c4109f94f00fc473148e6",
         "status":"REVOKED",
         "reason":"Key revocation test key"
      },
      {
         "public_key":"d199b2f29f3dc224cca778a7544ea89470cbef46",
         "status":"REVOKED",
         "reason":"Key revocation test key"
      }
   ]
}
  • public_key הוא סיכום SHA-1 של המפתח המבוטל, בפורמט שמתואר בקטע יצירת מפתח ה-pubkey של AVB.
  • status מציין את סטטוס הביטול של המפתח. בשלב זה, הערך הנתמך היחיד הוא REVOKED.
  • reason היא מחרוזת אופציונלית שמתארת את הסיבה לביטול.

הליכי DSU

בקטע הזה נסביר איך לבצע כמה הליכים להגדרת DSU.

יצירת זוג מפתחות חדש

משתמשים בפקודה openssl כדי ליצור זוג מפתחות RSA פרטי/ציבורי בפורמט .pem (לדוגמה, בגודל 2048 ביט):

$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem

יכול להיות שלא תהיה גישה למפתח הפרטי, והוא נשמר רק במודול אבטחה לחומרה (HSM). במקרה כזה, יכול להיות שיהיה אישור של מפתח ציבורי מסוג x509 זמין אחרי יצירת המפתח. בקטע הוספת מפתח ה-pubkey של ההתאמה ל-ramdisk מפורטות הוראות ליצירת המפתח הציבורי של AVB מאישור x509.

כדי להמיר אישור x509 לפורמט PEM:

$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem

אם האישור כבר הוא קובץ PEM, אפשר לדלג על השלב הזה.

הוספת מפתח ה-pubkey של ההתאמה ל-ramdisk

צריך להעביר את oem_cert.avbpubkey אל /avb/*.avbpubkey כדי לאמת את חבילת ה-DSU החתומה. קודם צריך להמיר את המפתח הציבורי בפורמט PEM לפורמט של מפתח ציבורי AVB:

$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey

לאחר מכן, צריך לכלול את המפתח הציבורי ב-ramdisk של השלב הראשון באמצעות השלבים הבאים.

  1. מוסיפים מודול מובנה כדי להעתיק את avbpubkey. לדוגמה, מוסיפים את device/<company>/<board>/oem_cert.avbpubkey ואת device/<company>/<board>/avb/Android.mk עם תוכן כזה:

    include $(CLEAR_VARS)
    
    LOCAL_MODULE := oem_cert.avbpubkey
    LOCAL_MODULE_CLASS := ETC
    LOCAL_SRC_FILES := $(LOCAL_MODULE)
    ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
    LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
    else
    LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
    endif
    
    include $(BUILD_PREBUILT)
    
  2. מגדירים את היעד droidcore כך שיהיה תלוי ב-oem_cert.avbpubkey שנוסף:

    droidcore: oem_cert.avbpubkey
    

יצירת המאפיין AVB pubkey בתיאור ה-JSON

השדה oem_cert.avbpubkey נמצא בפורמט הבינארי של מפתח ציבורי של AVB. משתמשים ב-SHA-1 כדי להפוך אותו לקריא לפני שמכניסים אותו לתיאורי ה-JSON:

$ sha1sum oem_cert.avbpubkey | cut -f1 -d ' '
3e62f2be9d9d813ef5........866ac72a51fd20

זה יהיה התוכן של המאפיין pubkey של מתאר ה-JSON.

   "images":[
      {
         ...
         "pubkey":"3e62f2be9d9d813ef5........866ac72a51fd20",
         ...
      },

חתימה על חבילת DSU

אפשר להשתמש באחת מהשיטות הבאות כדי לחתום על חבילת DSU:

  • שיטה 1: שימוש חוזר באובייקט שנוצר בתהליך החתימה המקורי של AVB כדי ליצור חבילת DSU. גישה חלופית היא לחלץ את התמונות שכבר חתומות מחבילת הגרסה, ולהשתמש בתמונות החתוכות כדי ליצור את קובץ ה-ZIP ישירות.

  • שיטה 2: משתמשים בפקודות הבאות כדי לחתום על מחיצות DSU אם המפתח הפרטי זמין. כל קובץ img בחבילת DSU (קובץ ה-ZIP) חתום בנפרד:

    $ key_len=$(openssl rsa -in oem_cert_pri.pem -text | grep Private-Key | sed -e 's/.*(\(.*\) bit.*/\1/')
    $ for partition in system product; do
        avbtool add_hashtree_footer \
            --image ${OUT}/${partition}.img \
            --partition_name ${partition} \
            --algorithm SHA256_RSA${key_len} \
            --key oem_cert_pri.pem
    done
    

למידע נוסף על הוספת add_hashtree_footer באמצעות avbtool, ראו שימוש ב-avbtool.

אימות החבילה של DSU באופן מקומי

מומלץ לאמת את כל התמונות המקומיות באמצעות המפתח הציבורי של ההתאמה באמצעות הפקודות הבאות:


for partition in system product; do
    avbtool verify_image --image ${OUT}/${partition}.img  --key oem_cert_pub.pem
done

הפלט הצפוי אמור להיראות כך:

Verifying image dsu/system.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/system.img
: Successfully verified sha1 hashtree of dsu/system.img for image of 898494464 bytes

Verifying image dsu/product.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/product.img
: Successfully verified sha1 hashtree of dsu/product.img for image of 905830400 bytes

יצירת חבילת DSU

בדוגמה הבאה נוצרת חבילת DSU שמכילה system.img ו-product.img:

dsu.zip {
    - system.img
    - product.img
}

אחרי שחותמים על שתי התמונות, משתמשים בפקודה הבאה כדי ליצור את קובץ ה-ZIP:

$ mkdir -p dsu
$ cp ${OUT}/system.img dsu
$ cp ${OUT}/product.img dsu
$ cd dsu && zip ../dsu.zip *.img && cd -

התאמה אישית של DSU בקליק אחד

כברירת מחדל, מערך הטעינה של DSU מפנה למטא-נתונים של קובצי אימג' של GSI, שהם https://...google.com/.../gsi-src.json.

יצרני ציוד מקורי יכולים לשנות את הרשימה על ידי הגדרת המאפיין persist.sys.fflag.override.settings_dynamic_system.list שמצביע על מתאר JSON משלהם. לדוגמה, יצרן ציוד מקורי (OEM) יכול לספק מטא-נתונים של JSON שכוללים GSI וגם תמונות קנייניות של OEM, באופן הבא:

{
    "include": ["https://dl.google.com/.../gsi-src.JSON"]
    "images":[
      {
         "name":"OEM image",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"...",
         "vndk":[
            27,
            28,
            29
         ],
         "spl":"...",
         "pubkey":"",
         "uri":"https://.../....zip"
      },

}

יצרן ציוד מקורי יכול לשרשר מטא-נתונים של DSU שפורסמו, כפי שמוצג באיור 7.

קישור של מטא-נתונים של DSU שפורסמו

איור 7. קישור של מטא-נתונים של DSU שפורסמו