פורמט קובץ APEX

פורמט המכולה של Android Pony EXpress (APEX) הוצג באנדרואיד 10 והוא משמש בתהליך ההתקנה של מודולי מערכת ברמה נמוכה יותר. פורמט זה מקל על העדכונים של רכיבי מערכת שאינם מתאימים לדגם היישום הסטנדרטי של אנדרואיד. כמה רכיבים לדוגמה הם שירותים וספריות מקוריות, שכבות הפשטת חומרה ( HALs ), זמן ריצה ( ART ) וספריות מחלקות.

המונח "APEX" יכול להתייחס גם לקובץ APEX.

רקע כללי

למרות ש-Android תומכת בעדכונים של מודולים המתאימים למודל האפליקציה הסטנדרטי (לדוגמה, שירותים, פעילויות) באמצעות אפליקציות התקנת חבילות (כגון אפליקציית Google Play Store), לשימוש במודל דומה עבור רכיבי מערכת הפעלה ברמה נמוכה יותר יש את החסרונות הבאים:

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

לְעַצֵב

סעיף זה מתאר את העיצוב ברמה הגבוהה של פורמט הקובץ APEX ומנהל APEX, שהוא שירות המנהל קבצי APEX.

למידע נוסף על מדוע נבחר עיצוב זה עבור APEX, ראה חלופות שנלקחו בחשבון בעת ​​פיתוח APEX .

פורמט APEX

זהו הפורמט של קובץ APEX.

פורמט קובץ APEX

איור 1. פורמט קובץ APEX

ברמה העליונה, קובץ APEX הוא קובץ zip שבו קבצים מאוחסנים לא דחוסים וממוקמים בגבולות של 4 KB.

ארבעת הקבצים בקובץ APEX הם:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

הקובץ apex_manifest.json מכיל את שם החבילה והגרסה, המזהים קובץ APEX. זהו מאגר פרוטוקול ApexManifest בפורמט JSON.

הקובץ AndroidManifest.xml מאפשר לקובץ APEX להשתמש בכלים ותשתית הקשורים ל-APK כגון ADB, PackageManager ואפליקציות התקנת חבילות (כגון חנות Play). לדוגמה, קובץ APEX יכול להשתמש בכלי קיים כגון aapt כדי לבדוק מטא נתונים בסיסיים מהקובץ. הקובץ מכיל מידע על שם החבילה והגרסה. מידע זה זמין בדרך כלל גם ב- apex_manifest.json .

apex_manifest.json מומלץ על AndroidManifest.xml עבור קוד ומערכות חדשות העוסקות ב-APEX. AndroidManifest.xml עשוי להכיל מידע מיקוד נוסף שיכול לשמש את כלי פרסום האפליקציות הקיימים.

apex_payload.img היא תמונת מערכת קבצים מסוג ext4 המגובה על ידי dm-verity. התמונה מותקנת בזמן ריצה באמצעות מכשיר loopback. באופן ספציפי, עץ הגיבוב ובלוק המטא נתונים נוצרים באמצעות ספריית libavb . מטען מערכת הקבצים אינו מנותח (מכיוון שהתמונה צריכה להיות ניתנת להרכבה במקום). קבצים רגילים כלולים בתוך הקובץ apex_payload.img .

apex_pubkey הוא המפתח הציבורי המשמש לחתימה על תמונת מערכת הקבצים. בזמן ריצה, מפתח זה מבטיח שה-APEX שהורד נחתם עם אותה ישות החותמת על אותו APEX במחיצות המובנות.

הנחיות למתן שמות של APEX

כדי לסייע במניעת התנגשויות שמות בין APEXs חדשים עם התקדמות הפלטפורמה, השתמש בהנחיות הבאות למתן שמות:

  • com.android.*
    • שמור עבור AOSP APEXes. לא ייחודי לאף חברה או מכשיר.
  • com.<companyname>.*
    • שמור לחברה. פוטנציאל בשימוש על ידי מכשירים מרובים מאותה חברה.
  • com.<companyname>.<devicename>.*
    • שמור עבור APEXs ייחודיים למכשיר ספציפי (או תת-קבוצה של מכשירים).

מנהל APEX

מנהל APEX (או apexd ) הוא תהליך מקורי עצמאי שאחראי על אימות, התקנה והסרה של קבצי APEX. תהליך זה מופעל ומוכן מוקדם ברצף האתחול. קובצי APEX מותקנים בדרך כלל מראש במכשיר תחת /system/apex . ברירת המחדל של מנהל APEX משתמש בחבילות אלה אם אין עדכונים זמינים.

רצף העדכונים של APEX משתמש במחלקה PackageManager והוא כדלקמן.

  1. הורדת קובץ APEX מתבצעת באמצעות אפליקציית התקנת חבילה, ADB או מקור אחר.
  2. מנהל החבילות מתחיל את הליך ההתקנה. לאחר זיהוי שהקובץ הוא APEX, מנהל החבילות מעביר את השליטה למנהל APEX.
  3. מנהל APEX מאמת את קובץ APEX.
  4. אם קובץ APEX מאומת, מסד הנתונים הפנימי של מנהל APEX מתעדכן כך שישקף שקובץ APEX מופעל באתחול הבא.
  5. מבקש ההתקנה מקבל שידור לאחר אימות החבילה בהצלחה.
  6. כדי להמשיך בהתקנה, יש לאתחל את המערכת.
  7. באתחול הבא, מנהל APEX מתחיל, קורא את מסד הנתונים הפנימי ועושה את הפעולות הבאות עבור כל קובץ APEX הרשום:

    1. מאמת את קובץ APEX.
    2. יוצר התקן לולאה מקובץ APEX.
    3. יוצר מכשיר לחסום ממפה מכשירים על גבי התקן הלולאה.
    4. הרכבת התקן בלוק ממפה המכשיר על נתיב ייחודי (לדוגמה, /apex/ name @ ver ).

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

קבצי APEX הם קבצי APK

קובצי APEX הם קובצי APK חוקיים מכיוון שהם ארכיוני zip חתומים (באמצעות סכימת חתימות APK) המכילים קובץ AndroidManifest.xml . זה מאפשר לקובצי APEX להשתמש בתשתית עבור קובצי APK, כגון אפליקציית התקנת חבילות, כלי החתימה ומנהל החבילות.

קובץ AndroidManifest.xml בתוך קובץ APEX הוא מינימלי, המורכב name החבילה, versionCode ו- targetSdkVersion אופציונלי, minSdkVersion ו- maxSdkVersion למיקוד עדין. מידע זה מאפשר אספקת קבצי APEX באמצעות ערוצים קיימים כגון אפליקציות התקנת חבילות ו-ADB.

סוגי קבצים נתמכים

פורמט APEX תומך בסוגי קבצים אלה:

  • ליבות משותפות מקוריות
  • קובצי הפעלה מקוריים
  • קבצי JAR
  • קבצי נתונים
  • קבצי תצורה

זה לא אומר ש-APEX יכול לעדכן את כל סוגי הקבצים האלה. האם ניתן לעדכן סוג קובץ תלוי בפלטפורמה ובמידת היציבות של הגדרות הממשקים לסוגי הקבצים.

אפשרויות חתימה

קבצי APEX חתומים בשתי דרכים. ראשית, הקובץ apex_payload.img (באופן ספציפי, מתאר vbmeta שצורף ל- apex_payload.img ) נחתם במפתח. לאחר מכן, כל ה-APEX נחתם באמצעות סכימת חתימת APK v3 . שני מפתחות שונים משמשים בתהליך זה.

בצד המכשיר, מותקן מפתח ציבורי המתאים למפתח הפרטי המשמש לחתימה על מתאר vbmeta. מנהל APEX משתמש במפתח הציבורי כדי לאמת APEXs שמתבקשים להתקין. כל APEX חייב להיות חתום עם מפתחות שונים והוא נאכף הן בזמן הבנייה והן בזמן הריצה.

APEX במחיצות מובנות

ניתן לאתר קבצי APEX במחיצות מובנות כגון /system . המחיצה כבר מעל dm-verity, כך שקובצי APEX מורכבים ישירות מעל התקן הלולאה.

אם קיים APEX במחיצה מובנית, ניתן לעדכן את ה-APEX על ידי אספקת חבילת APEX עם אותו שם חבילה וקוד גדול או שווה לקוד הגרסה. ה-APEX החדש מאוחסן ב- /data , ובדומה ל-APKs, הגרסה החדשה שהותקנה מאפילה על הגרסה שכבר קיימת במחיצה המובנית. אבל בניגוד ל-APKs, הגרסה החדשה של ה-APEX מופעלת רק לאחר אתחול מחדש.

דרישות הליבה

כדי לתמוך במודולי APEX mainline במכשיר אנדרואיד, נדרשות תכונות ליבת לינוקס הבאות: מנהל ההתקן הלולאה ו-dm-verity. מנהל ההתקן של ה-loopback מעלה את תמונת מערכת הקבצים במודול APEX ו-dm-verity מאמת את מודול APEX.

הביצועים של מנהל ההתקן הלולאה וה-dm-verity חשובים להשגת ביצועי מערכת טובים בעת שימוש במודולי APEX.

גרסאות ליבה נתמכות

מודולי APEX mainline נתמכים במכשירים המשתמשים בגרסאות ליבה 4.4 ומעלה. מכשירים חדשים שיושקו עם אנדרואיד 10 ומעלה חייבים להשתמש בגרסת ליבה 4.9 ומעלה כדי לתמוך במודולי APEX.

תיקוני ליבה נדרשים

תיקוני הליבה הנדרשים לתמיכה במודולי APEX כלולים בעץ המשותף של אנדרואיד. כדי לקבל את התיקונים לתמוך ב-APEX, השתמש בגרסה העדכנית ביותר של העץ המשותף של אנדרואיד.

גרסת ליבה 4.4

גרסה זו נתמכת רק עבור מכשירים המשודרגים מאנדרואיד 9 לאנדרואיד 10 ורוצים לתמוך במודולי APEX. כדי לקבל את התיקונים הנדרשים, מומלץ בחום מיזוג למטה מענף android-4.4 . להלן רשימה של התיקונים הנפרדים הנדרשים עבור גרסת ליבה 4.4.

  • UPSTREAM: לולאה: הוסף ioctl לשינוי גודל הבלוק הלוגי ( 4.4 )
  • BACKPORT: בלוק/לולאה: הגדר hw_sectors ( 4.4 )
  • UPSTREAM: לולאה: הוסף LOOP_SET_BLOCK_SIZE ב-compat ioctl ( 4.4 )
  • ANDROID: mnt: תקן next_descendent ( 4.4 )
  • אנדרואיד: mnt: remount אמור להתפשט לעבדים של עבדים ( 4.4 )
  • אנדרואיד: mnt: הפצת התקנה מחדש בצורה נכונה ( 4.4 )
  • החזר לגרסה הקודמת "ANDROID: dm verity: הוסף גודל אחזור מינימלי" ( 4.4 )
  • UPSTREAM: לולאה: שחרר מטמונים אם היסט או block_size משתנים ( 4.4 )

גרסאות ליבה 4.9/4.14/4.19

כדי לקבל את התיקונים הנדרשים עבור גרסאות ליבה 4.9/4.14/4.19, מיזוג למטה מהענף android-common .

אפשרויות תצורת ליבה נדרשות

הרשימה הבאה מציגה את דרישות התצורה הבסיסיות לתמיכה במודולי APEX שהוצגו באנדרואיד 10. הפריטים עם כוכבית (*) הם דרישות קיימות מאנדרואיד 9 ומטה.

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support

דרישות פרמטר שורת הפקודה של ליבה

כדי לתמוך ב-APEX, ודא שהפרמטרים של שורת הפקודה של הליבה עומדים בדרישות הבאות:

  • אין להגדיר loop.max_loop
  • loop.max_part חייב להיות <= 8

בנה APEX

סעיף זה מתאר כיצד לבנות APEX באמצעות מערכת הבנייה של אנדרואיד. להלן דוגמה של Android.bp עבור APEX בשם apex.test .

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so and libcutils.so are included in the apex
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

דוגמה apex_manifest.json :

{
  "name": "com.android.example.apex",
  "version": 1
}

file_contexts דוגמה:

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

סוגי קבצים ומיקומים ב-APEX

סוג קובץ מיקום ב-APEX
ספריות משותפות /lib ו- /lib64 ( /lib/arm עבור זרוע מתורגמת ב-x86)
קבצי הפעלה /bin
ספריות Java /javalib
בנוי מראש /etc

תלות טרנזיטיבית

קובצי APEX כוללים באופן אוטומטי תלות מעבר של libs משותף מקורי או קובצי הפעלה. לדוגמה, אם libFoo תלוי ב- libBar , שתי ה-libs נכללות כאשר רק libFoo מופיע במאפיין native_shared_libs .

טיפול במספר ABIs

התקן את המאפיין native_shared_libs עבור ממשקים בינאריים של יישומים ראשיים ומשניים (ABI) של המכשיר. אם APEX מכוון להתקנים עם ABI בודד (כלומר, 32 סיביות בלבד או 64 סיביות בלבד), מותקנות רק ספריות עם ה-ABI המתאים.

התקן את המאפיין binaries רק עבור ה-ABI הראשי של ההתקן כמתואר להלן:

  • אם ההתקן הוא 32 סיביות בלבד, מותקן רק גרסת 32 סיביות של הבינארי.
  • אם ההתקן הוא 64 סיביות בלבד, מותקן רק גרסת ה-64 סיביות של הבינארי.

כדי להוסיף שליטה עדינה על ה-ABI של הספריות והבינאריות המקוריות, השתמש במאפייני multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] .

  • first : מתאים ל-ABI הראשי של המכשיר. זוהי ברירת המחדל עבור קבצים בינאריים.
  • lib32 : מתאים ל-32 סיביות ABI של המכשיר, אם נתמך.
  • lib64 : מתאים ל-64 סיביות ABI של המכשיר, הוא נתמך.
  • prefer32 : מתאים ל-32 סיביות ABI של המכשיר, אם נתמך. אם ה-ABI של 32 סיביות אינו נתמך, מתאים ל-ABI של 64 סיביות.
  • both : מתאים לשני ה-ABI. זוהי ברירת המחדל עבור native_shared_libraries .

המאפיינים java , libraries prebuilts הם ABI-agnostic.

דוגמה זו מיועדת למכשיר שתומך ב-32/64 ואינו מעדיף את 32:

apex {
    // other properties are omitted
    native_shared_libs: ["libFoo"], // installed for 32 and 64
    binaries: ["exec1"], // installed for 64, but not for 32
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // installed for 64, but not for 32
            binaries: ["exec2"], // same as binaries without multilib.first
        },
        both: {
            native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
            binaries: ["exec3"], // installed for 32 and 64
        },
        prefer32: {
            native_shared_libs: ["libX"], // installed for 32, but not for 64
        },
        lib64: {
            native_shared_libs: ["libY"], // installed for 64, but not for 32
        },
    },
}

חתימת vbmeta

חתום על כל APEX במפתחות שונים. כאשר נדרש מפתח חדש, צור זוג מפתחות ציבורי-פרטי וצור מודול apex_key . השתמש במאפיין key כדי לחתום על ה-APEX באמצעות המפתח. המפתח הציבורי נכלל אוטומטית ב-APEX עם השם avb_pubkey .

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

בדוגמה שלמעלה, שם המפתח הציבורי ( foo ) הופך למזהה המפתח. המזהה של המפתח המשמש לחתימה על APEX כתוב ב-APEX. בזמן ריצה, apexd מאמת את ה-APEX באמצעות מפתח ציבורי עם אותו מזהה במכשיר.

חתימת APEX

חתום על APEXs באותו אופן כמו שאתה חותם על APKs. חתום על APEXes פעמיים; פעם אחת עבור מערכת הקבצים המיני (קובץ apex_payload.img ) ופעם אחת עבור הקובץ כולו.

כדי לחתום על APEX ברמת הקובץ, הגדר את מאפיין certificate באחת משלוש הדרכים הבאות:

  • לא מוגדר: אם לא הוגדר ערך, ה-APEX נחתם עם האישור שנמצא ב- PRODUCT_DEFAULT_DEV_CERTIFICATE . אם לא הוגדר דגל, ברירת המחדל של הנתיב הוא build/target/product/security/testkey .
  • <name> : ה-APEX חתום עם האישור <name> באותה ספרייה כמו PRODUCT_DEFAULT_DEV_CERTIFICATE .
  • :<name> : ה-APEX חתום עם האישור המוגדר על ידי מודול Soong בשם <name> . ניתן להגדיר את מודול התעודה באופן הבא.
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

התקן APEX

כדי להתקין APEX, השתמש ב-ADB.

adb install apex_file_name
adb reboot

אם supportsRebootlessUpdate מוגדר כ- true ב- apex_manifest.json וה-APEX המותקן כעת אינו בשימוש (לדוגמה, כל השירותים שהוא מכיל הופסק), אז ניתן להתקין APEX חדש ללא אתחול מחדש עם הדגל --force-non-staged .

adb install --force-non-staged apex_file_name

השתמש ב-APEX

לאחר אתחול מחדש, ה-APEX מותקן בספריית /apex/<apex_name>@<version> . ניתן להרכיב מספר גרסאות של אותו APEX בו-זמנית. בין נתיבי ההרכבה, זה שמתאים לגרסה האחרונה מותקן ב-bind-mounted ב- /apex/<apex_name> .

לקוחות יכולים להשתמש בנתיב המותקן ב-bind כדי לקרוא או להפעיל קבצים מ-APEX.

APEXs משמשים בדרך כלל כדלקמן:

  1. OEM או ODM טוענים מראש APEX תחת /system/apex כאשר המכשיר נשלח.
  2. הגישה לקבצים ב-APEX מתבצעת דרך הנתיב /apex/<apex_name>/ .
  3. כאשר גרסה מעודכנת של ה-APEX מותקנת ב- /data/apex , הנתיב מצביע על ה-APEX החדש לאחר אתחול מחדש.

עדכן שירות עם APEX

כדי לעדכן שירות באמצעות APEX:

  1. סמן את השירות במחיצת המערכת כמתעדכן. הוסף את האפשרות updatable לעדכון להגדרת השירות.

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. צור קובץ .rc חדש עבור השירות המעודכן. השתמש באפשרות override כדי להגדיר מחדש את השירות הקיים.

    /apex/my.apex/etc/init.rc:
    
    service myservice /apex/my.apex/bin/myservice
        class core
        user system
        ...
        override
    

ניתן להגדיר הגדרות שירות רק בקובץ .rc של APEX. מפעילי פעולה אינם נתמכים ב-APEXs.

אם שירות המסומן כמתעדכן מתחיל לפני הפעלת ה-APEXs, ההתחלה מתעכבת עד להשלמת הפעלת ה-APEXs.

הגדר את המערכת כדי לתמוך בעדכוני APEX

הגדר את מאפיין המערכת הבא כ- true כדי לתמוך בעדכוני קבצי APEX.

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

או רק

<device.mk>:

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

APEX שטוח

עבור מכשירים מדור קודם, לפעמים זה בלתי אפשרי או בלתי אפשרי לעדכן את הליבה הישנה לתמיכה מלאה ב-APEX. לדוגמה, ייתכן שהקרנל נבנה ללא CONFIG_BLK_DEV_LOOP=Y , שהוא חיוני להרכבת תמונת מערכת הקבצים בתוך APEX.

Flattened APEX הוא APEX שנבנה במיוחד שניתן להפעיל במכשירים עם ליבה מדור קודם. קבצים ב-APEX שטוח מותקנים ישירות בספרייה מתחת למחיצה המובנית. לדוגמה, lib/libFoo.so ב-APEX שטוח my.apex מותקן ב- /system/apex/my.apex/lib/libFoo.so .

הפעלת APEX שטוח אינה כרוכה במכשיר הלולאה. כל הספרייה /system/apex/my.apex מותאמת ישירות ל- /apex/name@ver .

לא ניתן לעדכן APEXs שטוחים על ידי הורדת גרסאות מעודכנות של APEXs מהרשת מכיוון שלא ניתן לשטח את APEXes שהורדת. ניתן לעדכן APEXים שטוחים רק באמצעות OTA רגיל.

APEX שטוח היא תצורת ברירת המחדל. משמעות הדבר היא שכל ה-APEXs משוטחים כברירת מחדל, אלא אם כן תגדיר במפורש את המכשיר שלך לבנות APEXים לא משוטחים כדי לתמוך בעדכוני APEX (כפי שהוסבר לעיל).

אין תמיכה בערבוב APEX פחוסים ובלתי משוטחים במכשיר. APEXs במכשיר חייבים להיות כולם לא משטחים או כולם משוטחים. זה חשוב במיוחד כאשר שולחים מראש APEX חתומים מראש עבור פרויקטים כגון Mainline. APEXs שאינם מוגדרים מראש (כלומר, בנויים מהמקור) צריכים להיות גם לא משטחים וחתומים עם מפתחות מתאימים. המכשיר אמור לרשת מ- updatable_apex.mk כפי שהוסבר בעדכון שירות עם APEX .

APEX דחוסים

אנדרואיד 12 ואילך כולל דחיסת APEX להפחתת השפעת האחסון של חבילות APEX הניתנות לעדכון. לאחר התקנת עדכון ל-APEX, למרות שהגרסה המותקנת שלו אינה בשימוש יותר, הוא עדיין תופס את אותה כמות מקום. השטח הכבוש הזה נשאר לא זמין.

דחיסת APEX ממזערת את השפעת האחסון על ידי שימוש בקבוצה דחוסה מאוד של קבצי APEX במחיצות לקריאה בלבד (כגון מחיצת /system ). אנדרואיד 12 ואילך משתמש באלגוריתם דחיסת zip DEFLATE.

דחיסה אינה מספקת אופטימיזציה לדברים הבאים:

  • Bootstrap APEXs שנדרשים להיות מותקן מוקדם מאוד ברצף האתחול.

  • APEXs שאינם ניתנים לעדכון. דחיסה מועילה רק אם מותקנת גרסה מעודכנת של APEX במחיצת /data . רשימה מלאה של APEXs הניתנים לעדכון זמינה בדף רכיבי המערכת המודולרית .

  • APEXs דינמי של libs משותף. מכיוון ש- apexd תמיד מפעיל את שתי הגרסאות של APEXs כאלה (מותקנים ומשודרגים מראש), דחיסה שלהם לא מוסיפה ערך.

פורמט קובץ APEX דחוס

זהו הפורמט של קובץ APEX דחוס.

Diagram shows the format of a compressed APEX file

איור 2. פורמט קובץ APEX דחוס

ברמה העליונה, קובץ APEX דחוס הוא קובץ zip המכיל את קובץ ה-apex המקורי בצורה מנוקחת עם רמת דחיסה של 9, ועם קבצים אחרים המאוחסנים לא דחוסים.

ארבעה קבצים מהווים קובץ APEX:

  • original_apex : מנוזל עם רמת דחיסה של 9 זהו קובץ ה-APEX המקורי והלא דחוס.
  • apex_manifest.pb : מאוחסן בלבד
  • AndroidManifest.xml : מאוחסן בלבד
  • apex_pubkey : מאוחסן בלבד

הקבצים apex_manifest.pb , AndroidManifest.xml ו- apex_pubkey הם עותקים של הקבצים המתאימים להם ב- original_apex .

בניית APEX דחוס

ניתן לבנות APEX דחוס באמצעות הכלי apex_compression_tool.py הממוקם ב- system/apex/tools .

מספר פרמטרים הקשורים לדחיסת APEX זמינים במערכת הבנייה.

ב- Android.bp אם קובץ APEX ניתן לדחיסה נשלטת על ידי המאפיין compressible :

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    compressible: true,
}

דגל מוצר PRODUCT_COMPRESSED_APEX שולט אם תמונת מערכת הבנויה ממקור חייבת להכיל קובצי APEX דחוסים.

עבור ניסויים מקומיים אתה יכול לאלץ מבנה לדחוס APEXs על ידי הגדרת OVERRIDE_PRODUCT_COMPRESSED_APEX= ל- true .

לקבצי APEX דחוסים שנוצרו על ידי מערכת ה-build יש את הסיומת .capex . התוסף מקלה על ההבחנה בין גרסאות דחוסות וגרסאות לא דחוסות של קובץ APEX.

אלגוריתמי דחיסה נתמכים

אנדרואיד 12 תומך רק בדחיסת deflate-zip.

הפעל קובץ APEX דחוס במהלך האתחול

לפני שניתן להפעיל APEX דחוס, הקובץ original_apex שבתוכו יפורק לתוך הספרייה /data/apex/decompressed . קובץ ה-APEX שהתקבל מקושר בצורה קשה לספריית /data/apex/active .

שקול את הדוגמה הבאה כהמחשה לתהליך המתואר לעיל.

שקול את /system/apex/com.android.foo.capex כ-APEX דחוס המופעל, עם גרסה קוד 37.

  1. קובץ original_apex בתוך /system/apex/com.android.foo.capex מפורק ל- /data/apex/decompressed/com.android.foo@37.apex .
  2. restorecon /data/apex/decompressed/com.android.foo@37.apex מתבצע כדי לוודא שיש לו תווית SELinux נכונה.
  3. בדיקות אימות מתבצעות ב- /data/apex/decompressed/com.android.foo@37.apex כדי להבטיח את תוקפו: apexd בודק את המפתח הציבורי המצורף ב- /data/apex/decompressed/com.android.foo@37.apex ל ודא שהוא שווה לזה המצורף ב- /system/apex/com.android.foo.capex .
  4. הקובץ /data/apex/decompressed/com.android.foo@37.apex מקושר בצורה קשה לספריית /data/apex/active/com.android.foo@37.apex .
  5. היגיון ההפעלה הרגיל עבור קבצי APEX לא דחוסים מתבצע ב- /data/apex/active/com.android.foo@37.apex .

אינטראקציה עם OTA

לקבצי APEX דחוסים יש השלכות על משלוח ויישום OTA. מכיוון שעדכון OTA עשוי להכיל קובץ APEX דחוס עם רמת גרסה גבוהה יותר ממה שפעיל במכשיר, יש לשמור כמות מסוימת של מקום פנוי לפני הפעלה מחדש של מכשיר כדי להחיל עדכון OTA.

כדי לתמוך במערכת ה-OTA, apexd חושפת את שני ממשקי ה-API של קלסר:

  • calculateSizeForCompressedApex - מחשב את הגודל הנדרש לביטול דחיסת קבצי APEX בחבילת OTA. זה יכול לשמש כדי לוודא שלמכשיר יש מספיק מקום לפני הורדת OTA.
  • reserveSpaceForCompressedApex - שומרת מקום בדיסק לשימוש עתידי על ידי apexd לביטול דחיסה של קבצי APEX דחוסים בתוך חבילת OTA.

במקרה של עדכון A/B OTA, apexd מנסה ביטול דחיסה ברקע כחלק משגרת OTA לאחר ההתקנה. אם הדחיסה נכשלת, apexd מבצעת את ביטול הדחיסה במהלך האתחול שמחיל את עדכון OTA.

חלופות שנלקחו בחשבון בעת ​​פיתוח APEX

הנה כמה אפשרויות ש-AOSP שקלה בעת תכנון פורמט הקובץ APEX, ומדוע הן נכללו או לא נכללו.

מערכות ניהול חבילות רגילות

להפצות לינוקס יש מערכות ניהול חבילות כמו dpkg ו- rpm , שהן חזקות, בוגרות וחזקות. עם זאת, הם לא אומצו עבור APEX מכיוון שהם לא יכולים להגן על החבילות לאחר ההתקנה. האימות מתבצע רק כאשר חבילות מותקנות. תוקפים יכולים לשבור את שלמות החבילות המותקנות, מבלי לשים לב. זוהי רגרסיה עבור אנדרואיד שבה כל רכיבי המערכת אוחסנו במערכות קבצים לקריאה בלבד שהשלמות שלהן מוגנת על ידי dm-verity עבור כל קלט/פלט. כל התעסקות ברכיבי מערכת חייבת להיות אסורה, או להיות ניתנת לזיהוי כך שההתקן יוכל לסרב לאתחל אם ייפגע.

dm-crypt עבור שלמות

הקבצים בקונטיינר של APEX הם ממחיצות מובנות (לדוגמה, מחיצת /system ) המוגנות על ידי dm-verity, כאשר כל שינוי בקבצים אסור גם לאחר הטעינה של המחיצות. כדי לספק את אותה רמת אבטחה לקבצים, כל הקבצים ב-APEX מאוחסנים בתמונת מערכת קבצים שמזווגת עם עץ hash ו-vbmeta descriptor. ללא dm-verity, APEX במחיצת /data חשוף לשינויים לא מכוונים שמתבצעים לאחר אימות והתקנתו.

למעשה, מחיצת /data מוגנת גם על ידי שכבות הצפנה כגון dm-crypt. למרות שזה מספק רמה מסוימת של הגנה מפני שיבוש, המטרה העיקרית שלו היא פרטיות, לא שלמות. כאשר תוקף מקבל גישה למחיצת /data , לא יכולה להיות הגנה נוספת, וזו שוב רגרסיה בהשוואה לכל רכיב מערכת שנמצא במחיצת /system . עץ הגיבוב בתוך קובץ APEX יחד עם dm-verity מספק את אותה רמת הגנת תוכן.

הפניית נתיבים מ-/system ל-/apex

קבצי רכיבי מערכת ארוזים ב-APEX נגישים דרך נתיבים חדשים כמו /apex/<name>/lib/libfoo.so . כאשר הקבצים היו חלק ממחיצת /system , הם היו נגישים דרך נתיבים כגון /system/lib/libfoo.so . לקוח של קובץ APEX (קובצי APEX אחרים או הפלטפורמה) חייב להשתמש בנתיבים החדשים. ייתכן שתצטרך לעדכן קוד קיים כתוצאה משינוי הנתיב.

למרות שאחת הדרכים להימנע משינוי הנתיב היא שכבת על של תוכן הקובץ בקובץ APEX על מחיצת /system , צוות אנדרואיד החליט לא לשכב על קבצים על מחיצת /system מכיוון שהדבר עלול להשפיע על הביצועים כמספר הקבצים שנמצאים מעל ( אולי אפילו מוערמים בזה אחר זה) גדל.

אפשרות נוספת הייתה לחטוף פונקציות של גישה לקבצים כגון open , stat ו- readlink , כך שהנתיבים המתחילים ב- /system הופנו לנתיבים המתאימים להם תחת /apex . צוות אנדרואיד דחה את האפשרות הזו מכיוון שלא ניתן לשנות את כל הפונקציות שמקבלות נתיבים. לדוגמה, אפליקציות מסוימות מקשרות באופן סטטי את Bionic, המיישמת את הפונקציות. במקרים כאלה, אפליקציות אלה לא מנותבות מחדש.