פורמט קובץ 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 סיביות של הבינארי.

כדי להוסיף שליטה עדינה על ABIs של הספריות והבינאריות המקוריות, השתמש במאפייני 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 שנדרשים להיות מותקן מוקדם מאוד ברצף האתחול.

  • APEXים שאינם ניתנים לעדכון. דחיסה מועילה רק אם מותקנת גרסה מעודכנת של 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, המיישמת את הפונקציות. במקרים כאלה, אפליקציות אלה לא מנותבות מחדש.

,

פורמט המכולה של 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 במכשיר אנדרואיד, נדרשים תכונות גרעין לינוקס הבאות: מנהל ההתקן של Loopback ו- DM-verity. מנהל התקן Loopback מתקן את תמונת מערכת הקבצים במודול Apex ו- DM-venity מאמת את מודול ה- Apex.

הביצועים של מנהל התקן Loopback ו- DM-verity חשובים בהשגת ביצועי מערכת טובים בעת השימוש במודולי Apex.

גרסאות גרעין נתמכות

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

טלאי גרעינים נדרשים

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

גרסת גרעין 4.4

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

  • במעלה הזרם: לולאה: הוסף את IOCTL לשינוי גודל חסימת לוגי ( 4.4 )
  • Backport: Block/Loop: הגדר hw_sectors ( 4.4 )
  • במעלה הזרם: לולאה: הוסף LOOP_SET_BLOCK_SIZE ב- COMPAT IOCTL ( 4.4 )
  • אנדרואיד: MNT: תקן את Next_Descendent ( 4.4 )
  • אנדרואיד: MNT: Remount צריך להתפשט לעבדי עבדים ( 4.4 )
  • אנדרואיד: MNT: להפיץ מחדש נכון ( 4.4 )
  • Revert "Android: DM Verity: הוסף גודל מינימלי מראש" ( 4.4 )
  • במעלה הזרם: לולאה: טיפת מטמון אם קיזוז או block_size משתנים ( 4.4 )

גרסאות גרעין 4.9/4.14/4.19

כדי לקבל את הטלאים הנדרשים לגרעיני גרעין 4.9/4.14/4.19, Down-MERGE מהסניף 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

לבנות איפקס

פרק זה מתאר כיצד לבנות איפקס באמצעות מערכת בניית אנדרואיד. להלן דוגמה ל- 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

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

תלות מעבר

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

לטפל באביס מרובה

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

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

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

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

  • first : תואם את ה- ABI העיקרי של המכשיר. זה ברירת המחדל של בינאריות.
  • lib32 : תואם את ה- ABI של 32 סיביות של המכשיר, אם נתמך.
  • lib64 : תואם את ה- ABI של 64 סיביות של המכשיר, הוא תמך.
  • prefer32 : תואם את ה- ABI של 32 סיביות של המכשיר, אם נתמך. אם ה- ABI של 32 סיביות אינו נתמך, תואם את ה- ABI של 64 סיביות.
  • both : תואם את שני אביס. זה ברירת המחדל עבור 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_key . השתמש key כדי לחתום על הקצה באמצעות המפתח. המפתח הציבורי נכלל אוטומטית ב- 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 ) הופך למזהה של המפתח. המזהה של המפתח המשמש לחתימת איפקס נכתב באפקס. בזמן ריצה, apexd מאמת את האפקס באמצעות מקש ציבורי עם אותו מזהה במכשיר.

חתימת איפקס

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

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

  • לא מוגדר: אם לא מוגדר ערך, הקצה נחתם עם האישור הממוקם ב- 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)
}

התקן איפקס

כדי להתקין איפקס, השתמש ב- ADB.

adb install apex_file_name
adb reboot

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

adb install --force-non-staged apex_file_name

השתמש בקצה

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

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

בדרך כלל משתמשים באפקסיות כדלקמן:

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

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

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

הגדר את מאפיין המערכת הבא כדי 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)

איפקס שטוח

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

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

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

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

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

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

איפלים דחוסים

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

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

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

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

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

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

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

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

Diagram shows the format of a compressed APEX file

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

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

ארבעה קבצים כוללים קובץ איפקס:

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

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

בנה איפקס דחוס

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

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

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

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

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

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

קבצי Apex דחוסים שנוצרו על ידי מערכת Build הם בעלי סיומת .capex . ההרחבה מקלה על ההבחנה בין גרסאות דחוסות ללא דחיסה של קובץ איפקס.

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

אנדרואיד 12 תומך רק בדחיסת ZIP Deflate.

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

לפני שניתן להפעיל איפקס דחוס, קובץ original_apex בפנים הוא מתפרק בספריה /data/apex/decompressed . קובץ ה- Apex המפורק שהתקבל מקושר ל- /data/apex/active Directory.

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

קחו בחשבון /system/apex/com.android.foo.capex com.android.foo.capex כאפקס דחוס מופעל, עם קוד גרסה 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

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

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

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

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

אלטרנטיבות שנחשבו בעת פיתוח איפקס

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

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

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

DM-Crypt ליושרה

הקבצים במכולה של Apex הם ממחיצות מובנות (לדוגמה, מחיצת /system ) המוגנות על ידי DM-verity, כאשר כל שינוי בקבצים אסור גם לאחר ההתקנה של המחיצות. כדי לספק את אותה רמת אבטחה לקבצים, כל הקבצים בקצה איפקס מאוחסנים בתמונת מערכת קבצים המשויכת לעץ חשיש ומתאר VBMETA. ללא כפיות DM, איפקס במחיצת /data חשוף לשינויים לא מכוונים שנעשו לאחר איומתו והותקנו.

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

הפניית נתיבים מ /מערכת ל- /Apex

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

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

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

,

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

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

רקע כללי

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

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

לְעַצֵב

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

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

פורמט איפקס

זהו הפורמט של קובץ איפקס.

פורמט קובץ Apex

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

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

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

  • 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 עבור קוד ומערכות חדשות העוסקות באפקס. AndroidManifest.xml עשוי להכיל מידע מיקוד נוסף שיכול לשמש את כלי פרסום האפליקציות הקיימים.

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

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

הנחיות שמות APEX

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

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

מנהל איפקס

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

רצף העדכון של איפקס משתמש בכיתת PackageManager והוא כדלקמן.

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

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

כאשר כל קבצי ה- 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 תומך בסוגי קבצים אלה:

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

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

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

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

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

קצה במחיצות מובנות

קבצי Apex יכולים להיות ממוקמים במחיצות מובנות כמו /system . המחיצה כבר מעל ל- DM-verity, כך שקבצי ה- Apex מותקנים ישירות מעל מכשיר ה- Loopback.

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

דרישות גרעין

כדי לתמוך במודולי הקו הראשי של Apex במכשיר אנדרואיד, נדרשים תכונות גרעין לינוקס הבאות: מנהל ההתקן של Loopback ו- DM-verity. מנהל התקן Loopback מתקן את תמונת מערכת הקבצים במודול Apex ו- DM-venity מאמת את מודול ה- Apex.

הביצועים של מנהל התקן Loopback ו- DM-verity חשובים בהשגת ביצועי מערכת טובים בעת השימוש במודולי Apex.

גרסאות גרעין נתמכות

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

טלאי גרעינים נדרשים

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

גרסת גרעין 4.4

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

  • במעלה הזרם: לולאה: הוסף את IOCTL לשינוי גודל חסימת לוגי ( 4.4 )
  • Backport: Block/Loop: הגדר hw_sectors ( 4.4 )
  • במעלה הזרם: לולאה: הוסף LOOP_SET_BLOCK_SIZE ב- COMPAT IOCTL ( 4.4 )
  • אנדרואיד: MNT: תקן את Next_Descendent ( 4.4 )
  • אנדרואיד: MNT: Remount צריך להתפשט לעבדי עבדים ( 4.4 )
  • אנדרואיד: MNT: להפיץ מחדש נכון ( 4.4 )
  • Revert "Android: DM Verity: הוסף גודל מינימלי מראש" ( 4.4 )
  • במעלה הזרם: לולאה: טיפת מטמון אם קיזוז או block_size משתנים ( 4.4 )

גרסאות גרעין 4.9/4.14/4.19

כדי לקבל את הטלאים הנדרשים לגרעיני גרעין 4.9/4.14/4.19, Down-MERGE מהסניף 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

לבנות איפקס

פרק זה מתאר כיצד לבנות איפקס באמצעות מערכת בניית אנדרואיד. להלן דוגמה ל- 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

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

תלות מעבר

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

לטפל באביס מרובה

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

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

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

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

  • first : תואם את ה- ABI העיקרי של המכשיר. זה ברירת המחדל של בינארים.
  • lib32 : תואם את ה- ABI של 32 סיביות של המכשיר, אם נתמך.
  • lib64 : תואם את ה- ABI של 64 סיביות של המכשיר, הוא תמך.
  • prefer32 : תואם את ה- ABI של 32 סיביות של המכשיר, אם נתמך. אם ה- ABI של 32 סיביות אינו נתמך, תואם את ה- ABI של 64 סיביות.
  • both : תואם את שני אביס. זה ברירת המחדל עבור 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_key . השתמש key כדי לחתום על הקצה באמצעות המפתח. המפתח הציבורי נכלל אוטומטית ב- 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 ) הופך למזהה של המפתח. המזהה של המפתח המשמש לחתימת איפקס נכתב באפקס. בזמן ריצה, apexd מאמת את האפקס באמצעות מקש ציבורי עם אותו מזהה במכשיר.

חתימת איפקס

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

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

  • לא מוגדר: אם לא מוגדר ערך, הקצה נחתם עם האישור הממוקם ב- 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)
}

התקן איפקס

כדי להתקין איפקס, השתמש ב- ADB.

adb install apex_file_name
adb reboot

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

adb install --force-non-staged apex_file_name

השתמש בקצה

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

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

בדרך כלל משתמשים באפקסיות כדלקמן:

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

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

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

Set the following system property to true to support APEX file updates.

<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)

Flattened APEX

For legacy devices, it's sometimes impossible or infeasible to update the old kernel to fully support APEX. For example, the kernel might have been built without CONFIG_BLK_DEV_LOOP=Y , which is crucial for mounting the file system image inside an APEX.

Flattened APEX is a specially built APEX that can be activated on devices with a legacy kernel. Files in a flattened APEX are directly installed to a directory under the built-in partition. For example, lib/libFoo.so in a flattened APEX my.apex is installed to /system/apex/my.apex/lib/libFoo.so .

Activating a flattened APEX doesn't involve the loop device. The entire directory /system/apex/my.apex is directly bind-mounted to /apex/name@ver .

Flattened APEXes can't be updated by downloading updated versions of the APEXes from network because the downloaded APEXes can't be flattened. Flattened APEXes can be updated only via a regular OTA.

Flattened APEX is the default configuration. This means that all APEXes are by default flattened unless you explicitly configure your device to build non-flattened APEXes to support APEX updates (as explained above).

Mixing flattened and non-flattened APEXes in a device is NOT supported. APEXes in a device must either be all non-flattened or all flattened. This is especially important when shipping pre-signed APEX prebuilts for projects such as Mainline. APEXes that aren't presigned (that is, built from the source) should also be non-flattened and signed with proper keys. The device should inherit from updatable_apex.mk as explained in Updating a service with an APEX .

Compressed APEXes

Android 12 and later feature APEX compression for reducing the storage impact of updatable APEX packages. After an update to an APEX is installed, although its pre-installed version isn't used anymore, it still occupies the same amount of space. That occupied space remains unavailable.

APEX compression minimizes this storage impact by using a highly compressed set of APEX files on read-only partitions (such as the /system partition). Android 12 and later use a DEFLATE zip compression algorithm.

Compression doesn't provide optimization to the following:

  • Bootstrap APEXes that are required to be mounted very early in the boot sequence.

  • Nonupdatable APEXes. Compression is only beneficial if an updated version of an APEX is installed on the /data partition. A full list of updatable APEXes is available on the Modular System Components page.

  • Dynamic shared libs APEXes. Since apexd always activates both versions of such APEXes (pre-installed and upgraded), compressing them doesn't add value.

Compressed APEX file format

This is the format of a compressed APEX file.

Diagram shows the format of a compressed APEX file

Figure 2. Compressed APEX file format

At the top level, a compressed APEX file is a zip file containing the original apex file in deflated form with a compression level of 9, and with other files stored uncompressed.

Four files comprise an APEX file:

  • original_apex : deflated with compression level of 9 This is the original, uncompressed APEX file .
  • apex_manifest.pb : stored only
  • AndroidManifest.xml : stored only
  • apex_pubkey : stored only

The apex_manifest.pb , AndroidManifest.xml , and apex_pubkey files are copies of their corresponding files in original_apex .

Build compressed APEX

Compressed APEX can be built using the apex_compression_tool.py tool located at system/apex/tools .

Several parameters related to APEX compression are available in the build system.

In Android.bp whether an APEX file is compressible is controlled by the compressible property:

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

A PRODUCT_COMPRESSED_APEX product flag controls whether a system image built from source must contain compressed APEX files.

For local experimentation you can force a build to compress APEXes by setting OVERRIDE_PRODUCT_COMPRESSED_APEX= to true .

Compressed APEX files generated by the build system have the .capex extension. The extension makes it easier to distinguish between compressed and uncompressed versions of an APEX file.

Supported compression algorithms

Android 12 only supports deflate-zip compression.

Activate a compressed APEX file during boot

Before a compressed APEX can be activated, the original_apex file inside it's decompressed into the /data/apex/decompressed directory. The resulting decompressed APEX file is hard-linked to the /data/apex/active directory.

Consider the following example as an illustration of the process described above.

Consider /system/apex/com.android.foo.capex as a compressed APEX being activated, with versionCode 37.

  1. The original_apex file inside /system/apex/com.android.foo.capex is decompressed into /data/apex/decompressed/com.android.foo@37.apex .
  2. restorecon /data/apex/decompressed/com.android.foo@37.apex is performed to verify that it has a correct SELinux label.
  3. Verification checks are performed on /data/apex/decompressed/com.android.foo@37.apex to ensure its validity: apexd checks the public key bundled in /data/apex/decompressed/com.android.foo@37.apex to verify that it's equal to the one bundled in /system/apex/com.android.foo.capex .
  4. The /data/apex/decompressed/com.android.foo@37.apex file is hard-linked to the /data/apex/active/com.android.foo@37.apex directory.
  5. The regular activation logic for uncompressed APEX files is performed on /data/apex/active/com.android.foo@37.apex .

Interaction with OTA

Compressed APEX files have implications on OTA delivery and application. Since an OTA update might contain a compressed APEX file with a higher version level than what's active on a device, a certain amount of free space must be reserved before a device is rebooted to apply an OTA update.

To support the OTA system, apexd exposes these two binder APIs:

  • calculateSizeForCompressedApex - calculates the size required to decompress APEX files in an OTA package. This can be used to verify that a device has enough space before an OTA gets downloaded.
  • reserveSpaceForCompressedApex - reserves space on the disk for future use by apexd for decompressing compressed APEX files inside the OTA package.

In the case of an A/B OTA update, apexd attempts decompression in the background as part of the postinstall OTA routine. If decompression fails, apexd performs the decompression during the boot that applies the OTA update.

Alternatives considered when developing APEX

Here are some options that AOSP considered when designing the APEX file format, and why they were either included or excluded.

Regular package management systems

Linux distributions have package management systems like dpkg and rpm , which are powerful, mature, and robust. However, they weren't adopted for APEX because they can't protect the packages after installation. Verification is performed only when packages are being installed. Attackers can break the integrity of the installed packages, unnoticed. This is a regression for Android where all system components were stored in read-only file systems whose integrity is protected by dm-verity for every I/O. Any tampering to system components must either be prohibited, or be detectable so that the device can refuse to boot if compromised.

dm-crypt for integrity

The files in an APEX container are from built-in partitions (for example, the /system partition) that are protected by dm-verity, where any modification to the files are prohibited even after the partitions are mounted. To provide the same level of security to the files, all files in an APEX are stored in a file system image that is paired with a hash tree and a vbmeta descriptor. Without dm-verity, an APEX in the /data partition is vulnerable to unintended modifications that are made after it's been verified and installed.

In fact, the /data partition is also protected by encryption layers such as dm-crypt. Although this provides some level of protection against tampering, its primary purpose is privacy, not integrity. When an attacker gains access to the /data partition, there can be no further protection, and this again is a regression compared to every system component being in the /system partition. The hash tree inside an APEX file together with dm-verity provides the same level of content protection.

Redirect paths from /system to /apex

System component files packaged in an APEX are accessible via new paths like /apex/<name>/lib/libfoo.so . When the files were part of the /system partition, they were accessible via paths such as /system/lib/libfoo.so . A client of an APEX file (other APEX files or the platform) must use the new paths. You might need to update existing code as a result of the path change.

Although one way to avoid the path change is to overlay the file contents in an APEX file onto the /system partition, the Android team decided not to overlay files on the /system partition because this could impact performance as the number of files being overlayed (possibly even stacked one after another) increased.

Another option was to hijack file-access functions such as open , stat , and readlink , so that paths beginning with /system were redirected to their corresponding paths under /apex . The Android team discarded this option because it's infeasible to change all functions that accept paths. For example, some apps statically link Bionic, which implements the functions. In such cases, those apps don't get redirected.