ספק APEX

אפשר להשתמש בפורמט הקובץ APEX כדי לארוז ו להתקין מודולים של Android OS ברמה נמוכה יותר. היא מאפשרת לבנות באופן עצמאי רכיבים כמו ספריות ושירותים מקוריים, HAL יישומים, קושחה, קובצי תצורה וכו'.

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

תרחישים לדוגמה

מודולריזציה של תמונות ספקים

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

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

לדוגמה, יכול להיות שיצרן הציוד המקורי יבחר לחבר את המכשיר שלו לרשת ה-Wi-Fi של AOSP APEX, הטמעת Bluetooth של SoC APEX ויצרן ציוד מקורי בהתאמה אישית שימוש בטכנולוגיית טלפוניה APEX.

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

חזרה על תהליך הפיתוח

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

כך מפתחים שעובדים בעיקר בתחום תכונות אחד ורוצים לבצע שינויים רק בתחום הזה יכולים לפשט ולהאיץ את מחזור החזרות שלהם.

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

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

תהליך עבודה לדוגמה:

# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w

# Test the device.
... testing ...

# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...

# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...

דוגמאות

יסודות

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

ב-Android.bp, הגדרת המאפיין vendor: true הופכת מודול APEX למודול APEX של ספק.

apex {
  ..
  vendor: true,
  ..
}

ספריות בינאריות וספריות משותפות

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

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

בקטע הקוד הבא, ה-APEX מכיל גם את הקובץ הבינארי (my_service) וגם את יחסי התלות הלא יציבים שלו (קבצי *.so).

apex {
  ..
  vendor: true,
  binaries: ["my_service"],
  ..
}

בקטע הקוד הבא, ה-APEX מכיל את הספרייה המשותפת my_standalone_lib ואת כל יחסי התלות הלא יציבים שלה (כפי שמתואר למעלה).

apex {
  ..
  vendor: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

הקטנה של APEX

קובץ ה-APEX עשוי לגדול כי הוא כולל יחד יחסי תלות לא יציבים. מומלץ להשתמש בקישור סטטי. אפשר לקשר באופן סטטי ספריות נפוצות כמו libc++.so ו-libbase.so לקובצי ה-HAL הבינאריים. אפשרות נוספת היא ליצור יחסי תלות כדי לספק ממשק יציב. התלות לא תצורף ל-APEX.

הטמעות של HAL

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

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

קטעי VINTF

אפשר להציג קטעי VINTF מ-APEX של ספק כשהקטעים נמצאים ב-etc/vintf של ה-APEX.

צריך להשתמש במאפיין prebuilts כדי להטמיע את מקטעי ה-VINTF ב-APEX.

apex {
  ..
  vendor: true,
  prebuilts: ["fragment.xml"],
  ..
}

prebuilt_etc {
  name: "fragment.xml",
  src: "fragment.xml",
  sub_dir: "vintf",
}

ממשקי API של שאילתות

כשמוסיפים מקטעי VINTF ל-APEX, צריך להשתמש בממשקי API של libbinder_ndk כדי לקבל של ממשקי HAL ושמות APEX.

  • AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default") : true אם מכונת HAL מוגדרת ב-APEX.
  • AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...) : הפונקציה מקבלת את השם ב-APEX שמגדיר את מכונה ה-HAL.
  • AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...) : משתמשים בה כדי לפתוח HAL של העברה.

סקריפטים של Init

קבצי APEX יכולים לכלול סקריפטים של init בשתי דרכים: (א) קובץ טקסט שנוצר מראש בתוך עומס העבודה של ה-APEX, או (ב) סקריפט init רגיל ב-/vendor/etc. אפשר להגדיר את שתי ההגדרות לאותו APEX.

סקריפט איפוס ב-APEX:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

סקריפטים של Init ב-APEX של ספקים יכולים לכלול הגדרות service והוראות on <property or event>.

צריך לוודא שהגדרת service מצביעה על קובץ בינארי באותו APEX. לדוגמה, com.android.foo APEX יכול להגדיר שירות בשם foo-service.

on foo-service /apex/com.android.foo/bin/foo
  ...

חשוב להיזהר כשמשתמשים בהוראות on. מאחר שסקריפטים של init ב-Apexes מנותחים ומבוצעים אחרי הפעלת ה-Apexes, אי אפשר להשתמש בחלק מהאירועים או מהמאפיינים. יש להשתמש ב-apex.all.ready=true כדי לבצע פעולות מוקדם ככל האפשר. Bootstrap APEX יכול להשתמש ב-on init, אבל לא on early-init

קושחה

דוגמה:

הטמעת קושחה ב-APEX של ספק עם סוג המודול prebuilt_firmware, כמו עוקבים.

prebuilt_firmware {
  name: "my.bin",
  src: "path_to_prebuilt_firmware",
  vendor: true,
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.bin"],  // installed inside APEX as /etc/firmware/my.bin
  ..
}

המודולים של prebuilt_firmware מותקנים בספרייה <apex name>/etc/firmware של ה-APEX. ueventd סורק את הספריות /apex/*/etc/firmware כדי למצוא מודולים של קושחת.

הערך file_contexts של APEX צריך להוסיף תוויות לרשומות של המטען הייעודי (payload) של הקושחה כדי לוודא שהקבצים האלה נגישים ל-ueventd בזמן ריצה. בדרך כלל, התווית vendor_file מספיקה. לדוגמה:

(/.*)? u:object_r:vendor_file:s0

מודולים של ליבה

מטמיעים מודולים של ליבה ב-APEX של ספק כמודולים מוכנים מראש, לפי השלבים הבאים.

prebuilt_etc {
  name: "my.ko",
  src: "my.ko",
  vendor: true,
  sub_dir: "modules"
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.ko"],  // installed inside APEX as /etc/modules/my.ko
  ..
}

השדה file_contexts של ה-APEX צריך לתייג כראוי את כל הרשומות של עומסי העבודה של מודול הליבה. לדוגמה:

/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0

צריך להתקין מודולים של ליבה באופן מפורש. דוגמה לסקריפט ההתחלתי במחיצת הספק מוצגת התקנה דרך insmod:

my_init.rc:

on early-boot
  insmod /apex/myapex/etc/modules/my.ko
  ..

שכבות-על של משאבים בזמן ריצה

דוגמה:

הטמעת שכבות-על של משאבי זמן ריצה ב-APEX של ספק באמצעות המאפיין rros.

runtime_resource_overlay {
    name: "my_rro",
    soc_specific: true,
}


apex {
  ..
  vendor: true,
  rros: ["my_rro"],  // installed inside APEX as /overlay/my_rro.apk
  ..
}

קובצי תצורה אחרים

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

דוגמאות:

Bootstrap Vendor APEXes

חלק משירותי HAL כמו keymint אמורים להיות זמינים לפני ש-APEX הופעל. עדכוני ה-HAL האלה בדרך כלל מגדירים early_hal בהגדרת השירות init סקריפט. דוגמה נוספת היא המחלקה animation, שמתחילה בדרך כלל לפני האירוע post-fs-data. כששירות HAL מוקדם כזה ארוז ב-APEX של הספק, צריך ליצור את ה-apex "vendorBootstrap": true במניפסט APEX שלו כדי שניתן יהיה להפעיל אותו מוקדם יותר. שימו לב שפריטי APEX של אתחול יכולים להיות מופעלת רק מהמיקום שהוגדר מראש, כמו /vendor/apex, ולא מהמיקום /data/apex.

מאפייני מערכת

אלה מאפייני המערכת שה-framework קורא כדי לתמוך בספק APEX:

  • input_device.config_file.apex=<apex name> – כשהיא מוגדרת, החיפוש של קובצי התצורה של הקלט (*.idc,‏ *.kl ו-*.kcm) מתבצע בספרייה /etc/usr של APEX.
  • ro.vulkan.apex=<apex name> – כשהיא מוגדרת, מנהל ההתקן של Vulkan נטען מ-APEX. מאחר שמנהלי HAL מוקדמים משתמשים ב-Vulkan driver, צריך ליצור את ה-APEX Bootstrap APEX ולהגדיר את מרחב השמות של ה-linker כך שיהיה גלוי.

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

תכונות פיתוח נוספות

בחירת APEX בזמן האתחול

דוגמה:

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

תרחישים לדוגמה:

  • התקנה של 3 גרסאות של APEX של WiFi HAL vendor: צוותי בקרת איכות יכולים להריץ בדיקה ידנית או אוטומטית באמצעות גרסה אחת, ואז להפעיל מחדש גרסה אחרת ולהריץ מחדש את הבדיקות, ולאחר מכן להשוות בין התוצאות הסופיות.
  • התקנה של 2 גרסאות של APEX של ספק ה-HAL של המצלמה, גרסה נוכחית וגרסה ניסיונית: משתמשים בתוכנית Dogfooding יכולים להשתמש בגרסה הניסיונית בלי להוריד ולהתקין קובץ נוסף, כך שהם יכולים לחזור לגרסה הקודמת בקלות.

במהלך האתחול, apexd מחפש sysprops בפורמט ספציפי כדי להפעיל את גרסת APEX המתאימה.

הפורמטים הנדרשים למפתח המאפיין הם:

  • Bootconfig
    • משמש להגדרת ערך ברירת המחדל ב-BoardConfig.mk.
    • androidboot.vendor.apex.<apex name>
  • מערכת מתמידה (sysp)
    • משמש לשינוי ערך ברירת המחדל, שמוגדר במכשיר שכבר הופעל.
    • משנה את הערך של bootconfig, אם הוא קיים.
    • persist.vendor.apex.<apex name>

הערך של המאפיין צריך להיות שם הקובץ של APEX הופעל.

// Default version.
apex {
  name: "com.oem.camera.hal.my_apex_default",
  vendor: true,
  ..
}

// Non-default version.
apex {
  name: "com.oem.camera.hal.my_apex_experimental",
  vendor: true,
  ..
}

צריך להגדיר גם את גרסת ברירת המחדל באמצעותbooconfig BoardConfig.mk:

# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
    androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default

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

$ adb root;
$ adb shell setprop \
    persist.vendor.apex.com.oem.camera.hal \
    com.oem.camera.hal.my_apex_experimental;
$ adb reboot;

אם המכשיר תומך בעדכון של bootconfig אחרי פלאש (למשל באמצעות פקודות fastboot oem), שינוי של מאפיין bootconfig של APEX שמותקן בכמה מכשירים משנה גם את הגרסה שמופעלת בזמן ההפעלה.

עבור התקני עזר וירטואליים המבוססים על Cuttlefish: אפשר להשתמש בפקודה --extra_bootconfig_args כדי להגדיר את המאפייןbootconfig ישירות בזמן ההפעלה. לדוגמה:

launch_cvd --noresume \
  --extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";