אפשר להשתמש בפורמט הקובץ APEX כדי לארוז ולהתקין מודולים ברמה נמוכה יותר של מערכת ההפעלה Android. הוא מאפשר פיתוח והתקנה עצמאיים של רכיבים כמו ספריות ושירותים מקומיים, הטמעות HAL, קושחה, קובצי תצורה וכו'.
מערכת ה-build מתקינה את מודולי ה-APEX של הספקים באופן אוטומטי במחיצה /vendor
ומפעילה אותם בסביבת זמן הריצה באמצעות apexd
, בדיוק כמו מודולי APEX במחיצות אחרות.
תרחישים לדוגמה
מודולריזציה של קובצי אימג' של ספקים
באמצעות APEXes אפשר לארוז ולפרוס באופן טבעי את הטמעות התכונות בתמונות של ספקים.
כשתמונות של ספקים נוצרות כשי combination של APEX של ספקים שנוצרו בנפרד, יצרני המכשירים יכולים לבחור בקלות את הטמעות הספק הספציפיות שהם רוצים במכשיר שלהם. יצרנים יכולים גם ליצור APEX חדש של ספק אם אף אחד מה-APEX שסופקו לא מתאים לצרכים שלהם, או אם יש להם חומרה מותאמת אישית חדשה לגמרי.
לדוגמה, יצרן ציוד מקורי יכול לבחור ליצור את המכשיר שלו באמצעות APEX להטמעת Wi-Fi של AOSP, APEX להטמעת Bluetooth של SoC ו-APEX להטמעת טלפוניה בהתאמה אישית של יצרן הציוד המקורי.
בלי חשבונות APEX של ספקים, הטמעה עם כל כך הרבה יחסי תלות בין רכיבי הספקים מחייבת תיאום וניטור קפדניים. כשעוטפים את כל הרכיבים (כולל קובצי תצורה וספריות נוספות) ב-APEX עם ממשקים מוגדרים בבירור בכל נקודה של תקשורת בין תכונות, הרכיבים השונים הופכים לניתנים להחלפה.
גרסאות אב למפתחים
באמצעות חבילות APEX של ספקים, מפתחים יכולים לפתח מודולים של ספקים במהירות רבה יותר. החבילות האלה מאפשרות לארוז יחד את כל הטמעת התכונה, כמו HAL של Wi-Fi, בתוך חבילת APEX של הספק. לאחר מכן, המפתחים יכולים ליצור את APEX של הספק ולשלוח אותו בנפרד כדי לבדוק את השינויים, במקום לבנות מחדש את קובץ האימג' המלא של הספק.
כך מפתחים שעובדים בעיקר בתחום תכונות אחד ורוצים לבצע שינויים רק בתחום הזה יכולים לפשט ולהאיץ את מחזור החזרות שלהם.
הקיפול הטבעי של תחום תכונות ל-APEX גם מפשט את התהליך של פיתוח, דחיפה ובדיקה של שינויים באותו תחום תכונות. לדוגמה, התקנה מחדש של APEX מעדכנת באופן אוטומטי את כל ספריות החבילה או קובצי התצורה שכלולים ב-APEX.
הקיפול של אזור תכונות ל-APEX גם מפשט את תהליך ניפוי הבאגים או החזרה למצב הקודם כשמתגלה התנהגות לא תקינה במכשיר. לדוגמה, אם טלפוניה פועלת בצורה גרועה בגרסה חדשה, המפתחים יכולים לנסות להתקין במכשיר גרסה ישנה יותר של APEX להטמעת טלפוניה (בלי צורך לבצע איפוס להגדרות המקוריות של גרסה מלאה) ולבדוק אם ההתנהגות חזרה להיות תקינה.
תהליך עבודה לדוגמה:
# 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. קובץ ה-manifest מעובד על ידי 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, צריך לספק את הספריות והקובצי ה-binary התואמים בתוך APEX של הספק, בדומה לדוגמאות הבאות:
כדי להכיל את הטמעת ה-HAL באופן מלא, צריך לציין ב-APEX גם את כל הקטעים הרלוונטיים של VINTF ואת סקריפטים ה-init.
קטעי 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 APEXes אפשר להשתמש ב-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 צריך לתייג כראוי את כל הרשומות של עומסי העבודה של הקושחה כדי לוודא של-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
צריך להתקין מודולים של ליבה באופן מפורש. בדוגמה הבאה של סקריפט init במחיצה של הספק מוצגת התקנה דרך 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 של ספקים, ואנחנו מוסיפים עוד.
דוגמאות:
- קובצי XML להצהרת תכונות
- ב-Sensors יש קובצי XML כקובצי build מוכנים מראש ב-APEX של ספק HAL של חיישן
- קבצי תצורה להזנה
- הגדרות של מסך מגע בתור חבילות מוכנות מראש ב-APEX של ספק להגדרות בלבד
Bootstrap Vendor APEXes
חלק משירותי HAL, כמו keymint
, אמורים להיות זמינים לפני הפעלת ה-APEX. בדרך כלל, ב-HALs האלה מוגדר early_hal
בהגדרת השירות שלהם בסקריפט ה-init. דוגמה נוספת היא המחלקה animation
, שמתחילה בדרך כלל לפני האירוע post-fs-data
. כששירות HAL מוקדם כזה ארוז ב-APEX של הספק, צריך ליצור את ה-apex "vendorBootstrap": true
במניפסט APEX שלו כדי שניתן יהיה להפעיל אותו מוקדם יותר. שימו לב שאפשר להפעיל את ה-APEX של ה-bootstrap רק מהמיקום שנוצר מראש, כמו /vendor/apex
, ולא מ-/data/apex
.
מאפייני מערכת
אלה מאפייני המערכת שהמסגרת קוראת כדי לתמוך ב-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 כך שיהיה גלוי.
מגדירים את מאפייני המערכת בסקריפטים של init באמצעות הפקודה setprop
.
תכונות פיתוח נוספות
בחירת APEX בזמן האתחול
דוגמה:
מפתחים יכולים גם להתקין כמה גרסאות של APEX של ספקים שיש להם את אותו שם ומפתח APEX, ואז לבחור איזו גרסה תופעל בכל הפעלה באמצעות sysprops מתמידים. בתרחישי שימוש מסוימים למפתחים, האפשרות הזו עשויה להיות פשוטה יותר מאשר התקנה של עותק חדש של APEX באמצעות adb install
.
תרחישים לדוגמה:
- התקנה של 3 גרסאות של APEX של WiFi HAL Vendor: צוותי בקרת איכות יכולים להריץ בדיקה ידנית או אוטומטית באמצעות גרסה אחת, ואז להפעיל מחדש בגרסה אחרת ולהריץ מחדש את הבדיקות, ולאחר מכן להשוות בין התוצאות הסופיות.
- התקנה של 2 גרסאות של APEX של ספק ה-HAL של המצלמה, הנוכחית והניסיונית: משתמשים בתוכנה לבדיקה עצמית יכולים להשתמש בגרסה הניסיונית בלי להוריד ולהתקין קובץ נוסף, כך שהם יכולים לחזור לגרסה הקודמת בקלות.
במהלך האתחול, apexd
מחפש sysprops בפורמט ספציפי כדי להפעיל את גרסת APEX המתאימה.
הפורמטים הנדרשים למפתח המאפיין הם:
- Bootconfig
- משמש להגדרת ערך ברירת המחדל, ב-
BoardConfig.mk
. androidboot.vendor.apex.<apex name>
- משמש להגדרת ערך ברירת המחדל, ב-
- Persistent sysprop
- משמש לשינוי ערך ברירת המחדל, שמוגדר במכשיר שכבר הופעל.
- משנה את הערך של 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,
..
}
צריך להגדיר את גרסת ברירת המחדל גם באמצעות bootconfig בקובץ 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";