ספק 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 File Format עם גרסה גנרית של APEX מידע, כולל דרישות לגבי מכשירים, פרטים על פורמט הקובץ בשלבי ההתקנה.

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

apex {
  ..
  vendor: true,
  ..
}

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

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

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

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

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

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

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

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

הטמעת 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",
}

הפעלת סקריפטים

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

הפעלת הסקריפט ב-APEX:

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

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

לסקריפטים שמופעלים בתוך APEX ניתן להגדיר רק service הגדרות. הפעלת סקריפטים ב-[APEX של ספקים] יכולות להיות גם הוראות on <property>.

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

קושחה

דוגמה:

הטמעת קושחה ב-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 צריך לתייג כל רשומה של מטען ייעודי (payload) של מודול ליבה (kernel) כראוי. לדוגמה:

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

לדוגמה:

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

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

דוגמה:

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

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

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

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

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

  • Bootconfig
    • משמש להגדרת ערך ברירת המחדל ב-BoardConfig.mk.
    • androidboot.vendor.apex.<apex name>
  • מערכת מתמידה (Syspro)
    • משמש לשינוי ערך ברירת המחדל שמוגדר במכשיר שכבר הופעל.
    • המדיניות משנה את הערך startconfig, אם יש כזה.
    • 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

לאחר אתחול המכשיר, שנה את הגרסה המופעלת על ידי הגדרת מערכת הפעלה מתמידה:

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

אם המכשיר תומך בעדכון אתחול אתחול לאחר הבהוב (למשל באמצעות פקודות fastboot oem), שינוי המאפייןbooconfig של ריבוי 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";