ב-Android מגרסה 8.1 ואילך, למערכת הבנייה יש תמיכה מובנית ב-VNDK. כשמופעלת תמיכה ב-VNDK, מערכת ה-build בודקת את התלות בין המודולים, יוצרת וריאציה ספציפית לספק עבור מודולים של ספקים ומתקינה את המודולים האלה באופן אוטומטי בספריות ייעודיות.
דוגמה לתמיכה ב-VNDK build
בדוגמה הזו, הגדרת המודול Android.bp
מגדירה ספרייה בשם libexample
. המאפיין vendor_available
מציין שמודולים של מסגרות ומודולים של ספקים עשויים להיות תלויים ב-libexample
:
התמיכה באיור 1. מופעלת.
גם קובץ ההפעלה של המסגרת /system/bin/foo
וגם קובץ ההפעלה של הספק /vendor/bin/bar
תלויים ב-libexample
, ו-libexample
מופיע במאפיינים שלהם shared_libs
.
אם נעשה שימוש ב-libexample
גם במודולים של המסגרת וגם במודולים של הספק, ייבנו שתי וריאציות של libexample
. הווריאנט המרכזי (שנקרא על שם libexample
) משמש מודולים של מסגרת, והווריאנט של הספק (שנקרא על שם libexample.vendor
) משמש מודולים של הספק. שתי הגרסאות מותקנות בספריות שונות:
- הווריאציה המרכזית מותקנת בתיקייה
/system/lib[64]/libexample.so
. - הווריאציה של הספק מותקנת ב-VNDK APEX כי
vndk.enabled
הואtrue
.
פרטים נוספים זמינים במאמר בנושא הגדרת מודול.
הגדרת תמיכה בבנייה
כדי להפעיל תמיכה מלאה במערכת build למכשיר מוצר, מוסיפים את
BOARD_VNDK_VERSION
אל BoardConfig.mk
:
BOARD_VNDK_VERSION := current
להגדרה הזו יש השפעה גלובלית: אם היא מוגדרת ב-BoardConfig.mk
, כל המודולים נבדקים. מכיוון שאין מנגנון להוספה לרשימה השחורה או הלבנה של מודול בעייתי, צריך לנקות את כל התלויות המיותרות לפני שמוסיפים את BOARD_VNDK_VERSION
. אפשר לבדוק ולבצע קומפילציה של מודול על ידי הגדרת BOARD_VNDK_VERSION
במשתני הסביבה:
$ BOARD_VNDK_VERSION=current m module_name.vendor
כשהאפשרות BOARD_VNDK_VERSION
מופעלת, כמה נתיבי חיפוש של כותרות גלובליות שמוגדרים כברירת מחדל מוסרים. למשל:
frameworks/av/include
frameworks/native/include
frameworks/native/opengl/include
hardware/libhardware/include
hardware/libhardware_legacy/include
hardware/ril/include
libnativehelper/include
libnativehelper/include_deprecated
system/core/include
system/media/audio/include
אם מודול מסוים תלוי בכותרות מהספריות האלה, צריך לציין (באופן מפורש) את התלות באמצעות header_libs
, static_libs
או shared_libs
.
VNDK APEX
ב-Android 10 ובגרסאות קודמות, מודולים עם vndk.enabled
הותקנו ב-/system/lib[64]/vndk[-sp]-${VER}
. ב-Android 11 ומעלה,
ספריות VNDK נארזות בפורמט APEX והשם של VNDK APEX הוא
com.android.vndk.v${VER}
. בהתאם להגדרת המכשיר, קובץ ה-VNDK APEX הוא שטוח או לא שטוח והוא זמין מהנתיב הקנוני /apex/com.android.vndk.v${VER}
.
איור 2. VNDK APEX.
הגדרת המודול
כדי ליצור Android באמצעות BOARD_VNDK_VERSION
, צריך לשנות את הגדרת המודול ב-Android.mk
או ב-Android.bp
. בקטע הזה מתוארים סוגים שונים של הגדרות מודולים, כמה מאפיינים של מודולים שקשורים ל-VNDK ובדיקות תלות שמוטמעות במערכת הבנייה.
Vendor modules
מודולים של ספקים הם קבצים הפעלה או ספריות משותפות שספציפיים לספק, וצריך להתקין אותם במחיצה של הספק. בקובצי Android.bp
, מודולים של ספקים צריכים להגדיר את המאפיין vendor או proprietary לערך true
.
בקובצי Android.mk
, מודולים של ספקים צריכים להגדיר את
LOCAL_VENDOR_MODULE
או LOCAL_PROPRIETARY_MODULE
בתור
true
.
אם BOARD_VNDK_VERSION
מוגדר, מערכת ה-build לא מאפשרת תלויות בין מודולים של ספקים לבין מודולים של מסגרות, ומציגה שגיאות אם:
- מודול ללא
vendor:true
תלוי במודול עםvendor:true
, או - מודול עם
vendor:true
תלוי במודול שאינוllndk_library
ושאין לוvendor:true
אוvendor_available:true
.
בדיקת התלות חלה על header_libs
, static_libs
ו-shared_libs
ב-Android.bp
, ועל LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
ו-LOCAL_SHARED_LIBRARIES
ב-Android.mk
.
LL-NDK
ספריות משותפות של LL-NDK הן ספריות משותפות עם ממשקי ABI יציבים. גם מודולי המסגרת וגם מודולי הספק חולקים את אותה הטמעה עדכנית. לכל ספרייה משותפת של LL-NDK, קובץ ה-cc_library
מכיל מאפיין llndk
עם קובץ סמלים:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
קובץ הסמלים מתאר את הסמלים שגלויים למודולים של הספק. לדוגמה:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
מערכת ה-build יוצרת ספרייה משותפת של stub למודולים של ספקים על סמך קובץ הסמלים, שמקושרת לספריות האלה כשמופעלת האפשרות BOARD_VNDK_VERSION
. סמל נכלל בספרייה המשותפת של ה-stub רק אם:
- לא מוגדר בסוף הקטע עם
_PRIVATE
או_PLATFORM
, - אין תג
#platform-only
, וגם - אין תגי
#introduce*
או שהתג תואם ליעד.
VNDK
בהגדרות של מודולים בקובצי Android.bp
, cc_library
, cc_library_static
, cc_library_shared
ו-cc_library_headers
, יש תמיכה בשלוש מאפיינים שקשורים ל-VNDK: vendor_available
, vndk.enabled
ו-vndk.support_system_process
.
אם הערך של vendor_available
או vndk.enabled
הוא true
, יכול להיות שייבנו שתי וריאציות (core ו-vendor). צריך להתייחס לגרסת הליבה כאל מודול מסגרת ולגרסת הספק כאל מודול ספק. אם מודולים מסוימים של המסגרת תלויים במודול הזה, נוצרת וריאציה של ליבה. אם מודולים מסוימים של ספקים תלויים במודול הזה, הגרסה של הספק תיבנה. מערכת הבנייה אוכפת את בדיקות התלות הבאות:
- גרסת הליבה היא תמיד framework-only ואין למודולים של ספקים גישה אליה.
- מודולים של מסגרת אף פעם לא יכולים לגשת לגרסת הספק.
- כל יחסי התלות של וריאציית הספק, שמצוינים ב-
header_libs
, ב-static_libs
או ב-shared_libs
, חייבים להיותllndk_library
או מודול עםvendor_available
אוvndk.enabled
. - אם
vendor_available
הואtrue
, הווריאציה של הספק נגישה לכל מודולי הספק. - אם
vendor_available
הואfalse
, אפשר לגשת לגרסת הספק רק ממודולים אחרים של VNDK או VNDK-SP (כלומר, מודולים עםvendor:true
לא יכולים לקשר מודולים שלvendor_available:false
).
נתיב ההתקנה שמוגדר כברירת מחדל ל-cc_library
או ל-cc_library_shared
נקבע לפי הכללים הבאים:
- הווריאציה הבסיסית מותקנת ב-
/system/lib[64]
. - נתיב ההתקנה של וריאציית הספק עשוי להשתנות:
- אם
vndk.enabled
הואfalse
, הווריאציה של הספק מותקנת ב-/vendor/lib[64]
. - אם הערך של
vndk.enabled
הואtrue
, גרסת הספק מותקנת ב-VNDK APEX(com.android.vndk.v${VER}
).
- אם
בטבלה הבאה מפורט איך מערכת ה-build מטפלת בווריאציות של הספקים:
vendor_available | vndk enabled |
vndk support_system_process |
תיאורי וריאנטים של ספקים |
---|---|---|---|
true |
false |
false |
הווריאציות של הספק הן VND-ONLY. הספריות המשותפות מותקנות ב-/vendor/lib[64] . |
true |
לא תקין (שגיאת בנייה) | ||
true |
false |
הווריאציות של הספק הן VNDK. הספריות המשותפות מותקנות ב-VNDK APEX. | |
true |
הווריאציות של הספק הן VNDK-SP. הספריות המשותפות מותקנות ב-VNDK APEX. | ||
|
|
|
אין וריאציות של ספקים. המודול הזה הוא FWK-ONLY. |
true |
לא תקין (שגיאת בנייה) | ||
true |
false |
הווריאציות של הספק הן VNDK-Private. הספריות המשותפות מותקנות ב-VNDK APEX. אסור להשתמש בהם ישירות במודולים של הספק. | |
true |
הווריאציות של הספק הן VNDK-SP-Private. הספריות המשותפות מותקנות ב-VNDK APEX. אסור להשתמש בהם ישירות במודולים של הספק. |
תוספים ל-VNDK
תוספי VNDK הם ספריות משותפות של VNDK עם ממשקי API נוספים. התוספים מותקנים ב-/vendor/lib[64]/vndk[-sp]
(בלי סיומת גרסה) ומבטלים את ההגדרות של הספריות המקוריות המשותפות של VNDK בזמן הריצה.
הגדרת תוספים של VNDK
ב-Android מגרסה 9 ואילך, Android.bp
תומך באופן מובנה בתוספים של VNDK. כדי ליצור תוסף VNDK, מגדירים מודול נוסף עם מאפיין vendor:true
ומאפיין extends
:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
מודול עם המאפיינים vendor:true
, vndk.enabled:true
ו-extends
מגדיר את התוסף VNDK:
- במאפיין
extends
צריך לציין שם של ספרייה משותפת בסיסית של VNDK (או שם של ספרייה משותפת של VNDK-SP). - שמות התוספים של VNDK (או התוספים של VNDK-SP) נגזרים משמות מודולי הבסיס שהם מרחיבים. לדוגמה, הפלט הבינארי של
libvndk_ext
הואlibvndk.so
ולאlibvndk_ext.so
. - תוספי VNDK מותקנים בתיקייה
/vendor/lib[64]/vndk
. - תוספי VNDK-SP מותקנים בתיקייה
/vendor/lib[64]/vndk-sp
. - בספריות המשותפות הבסיסיות צריכים להיות גם
vndk.enabled:true
וגםvendor_available:true
.
תוסף VNDK-SP חייב להיות הרחבה של ספרייה משותפת של VNDK-SP
(vndk.support_system_process
חייב להיות שווה):
cc_library { name: "libvndk_sp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, } cc_library { name: "libvndk_sp_ext", vendor: true, vndk: { enabled: true, extends: "libvndk_sp", support_system_process: true, }, }
יכול להיות שתוספים של VNDK (או תוספים של VNDK-SP) יהיו תלויים בספריות משותפות אחרות של ספקים:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, shared_libs: [ "libvendor", ], } cc_library { name: "libvendor", vendor: true, }
שימוש בתוספים של VNDK
אם מודול של ספק תלוי בממשקי API נוספים שמוגדרים על ידי תוספים של VNDK, המודול צריך לציין את השם של התוסף של VNDK במאפיין shared_libs
שלו:
// A vendor shared library example cc_library { name: "libvendor", vendor: true, shared_libs: [ "libvndk_ext", ], } // A vendor executable example cc_binary { name: "vendor-example", vendor: true, shared_libs: [ "libvndk_ext", ], }
אם מודול של ספק תלוי בתוספים של VNDK, התוספים האלה של VNDK מותקנים ב-/vendor/lib[64]/vndk[-sp]
באופן אוטומטי. אם מודול מסוים כבר לא תלוי בתוסף VNDK, צריך להוסיף שלב ניקוי ל-CleanSpec.mk
כדי להסיר את הספרייה המשותפת. לדוגמה:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
קומפילציה מותנית
בקטע הזה נסביר איך להתמודד עם ההבדלים הקלים (למשל, הוספה או הסרה של תכונה מאחד מהווריאנטים) בין שלושת הספריות המשותפות של VNDK הבאות:
- גרסת ליבה (לדוגמה,
/system/lib[64]/libexample.so
) - גרסת ספק (לדוגמה:
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - תוסף VNDK (לדוגמה,
/vendor/lib[64]/vndk[-sp]/libexample.so
)
דגלים של הידור מותנה
מערכת ה-Build של Android מגדירה את __ANDROID_VNDK__
כברירת מחדל עבור וריאציות של ספקים ותוספים של VNDK. אפשר להגן על הקוד באמצעות אמצעי ההגנה של מעבד C מקדים:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
בנוסף ל-__ANDROID_VNDK__
, אפשר לציין ב-Android.bp
cflags
או cppflags
שונים. הפונקציה cflags
או cppflags
שצוינה ב-target.vendor
ספציפית לווריאציה של הספק.
לדוגמה, קובץ ה-Android.bp
הבא מגדיר את libexample
ואת libexample_ext
:
cc_library { name: "libexample", srcs: ["src/example.c"], vendor_available: true, vndk: { enabled: true, }, target: { vendor: { cflags: ["-DLIBEXAMPLE_ENABLE_VNDK=1"], }, }, } cc_library { name: "libexample_ext", srcs: ["src/example.c"], vendor: true, vndk: { enabled: true, extends: "libexample", }, cflags: [ "-DLIBEXAMPLE_ENABLE_VNDK=1", "-DLIBEXAMPLE_ENABLE_VNDK_EXT=1", ], }
זו רשימת הקוד של src/example.c
:
void all() { } #if !defined(LIBEXAMPLE_ENABLE_VNDK) void framework_only() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK) void vndk() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK_EXT) void vndk_ext() { } #endif
על סמך שני הקבצים האלה, מערכת ה-build יוצרת ספריות משותפות עם הסמלים המיוצאים הבאים:
נתיב ההתקנה | סמלים שיוצאו |
---|---|
/system/lib[64]/libexample.so |
all , framework_only |
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so |
all , vndk |
/vendor/lib[64]/vndk/libexample.so |
all , vndk vndk_ext |
הדרישות לגבי הסמלים המיוצאים
כלי הבדיקה של VNDK ABI משווה את ה-ABI של וריאציות של ספקים ב-VNDK ושל תוספים ל-VNDK לבין קובצי ה-dump של ה-ABI של ההפניה בתיקייה prebuilts/abi-dumps/vndk
.
- הסמלים שמיוצאים על ידי וריאציות של ספקים ב-VNDK (לדוגמה:
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) צריכים להיות זהים לסמלים שמוגדרים ב-ABI dumps (ולא קבוצות-על שלהם). - סמלים שמיוצאים על ידי תוספי VNDK (למשל,
/vendor/lib[64]/vndk/libexample.so
) צריכים להיות קבוצות-על של הסמלים שמוגדרים בקובצי ה-dump של ה-ABI.
אם וריאציות של ספק VNDK או תוספים של VNDK לא עומדים בדרישות שלמעלה, כלי הבדיקה של VNDK ABI יציג שגיאות בנייה ויפסיק את הבנייה.
אי-הכללה של קובצי מקור או ספריות משותפות מגרסאות ספקים
כדי להחריג קובצי מקור מהגרסה של הספק, מוסיפים אותם לנכס exclude_srcs
. באופן דומה, כדי לוודא שהספריות המשותפות לא מקושרות לגרסת הספק, מוסיפים את הספריות האלה למאפיין exclude_shared_libs
. לדוגמה:
cc_library { name: "libexample_cond_exclude", srcs: ["fwk.c", "both.c"], shared_libs: ["libfwk_only", "libboth"], vendor_available: true, target: { vendor: { exclude_srcs: ["fwk.c"], exclude_shared_libs: ["libfwk_only"], }, }, }
בדוגמה הזו, גרסת הליבה של libexample_cond_exclude
כוללת את הקוד מ-fwk.c
ומ-both.c
, והיא תלויה בספריות המשותפות libfwk_only
ו-libboth
. הגרסה של libexample_cond_exclude
שסופקה על ידי הספק כוללת רק את הקוד מ-both.c
כי fwk.c
מוחרג על ידי המאפיין exclude_srcs
. באופן דומה, הוא תלוי רק בספרייה המשותפת libboth
כי הנכס libfwk_only
לא נכלל בגלל הנכס exclude_shared_libs
.
ייצוא כותרות מתוספי VNDK
תוסף VNDK עשוי להוסיף מחלקות חדשות או פונקציות חדשות לספרייה משותפת של VNDK. מומלץ להשאיר את ההצהרות האלה בכותרות נפרדות ולא לשנות את הכותרות הקיימות.
לדוגמה, קובץ כותרת חדש
include-ext/example/ext/feature_name.h
נוצר עבור התוסף VNDK
libexample_ext
:
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/feature_name.c
בדוגמה הבאה, בייצוא של Android.bp
ו-libexample
מיוצא רק include
, ואילו בייצוא של libexample_ext
מיוצאים גם include
וגם include-ext
. כך לא יכללו את feature_name.h
בטעות המשתמשים של libexample
:
cc_library { name: "libexample", srcs: ["src/example.c"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample_ext", srcs: [ "src/example.c", "src/ext/feature_name.c", ], export_include_dirs: [ "include", "include-ext", ], vendor: true, vndk: { enabled: true, extends: "libexample", }, }
אם אי אפשר להפריד את התוספים לקובצי כותרת עצמאיים, אפשר להוסיף אמצעי הגנה מסוג #ifdef
. עם זאת, חשוב לוודא שכל המשתמשים בתוסף VNDK מוסיפים את דגלי ההגדרה. אפשר להגדיר את cc_defaults
כדי להוסיף דגלי הגדרה ל-cflags
ולקשר ספריות משותפות ל-shared_libs
.
לדוגמה, כדי להוסיף פונקציית חבר חדשה Example2::get_b()
לתוסף VNDK libexample2_ext
, צריך לשנות את קובץ הכותרת הקיים ולהוסיף את המגן #ifdef
:
#ifndef LIBEXAMPLE2_EXAMPLE_H_ #define LIBEXAMPLE2_EXAMPLE_H_ class Example2 { public: Example2(); void get_a(); #ifdef LIBEXAMPLE2_ENABLE_VNDK_EXT void get_b(); #endif private: void *impl_; }; #endif // LIBEXAMPLE2_EXAMPLE_H_
הוגדר cc_defaults
בשם libexample2_ext_defaults
למשתמשים של libexample2_ext
:
cc_library { name: "libexample2", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample2_ext", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor: true, vndk: { enabled: true, extends: "libexample2", }, cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], } cc_defaults { name: "libexample2_ext_defaults", shared_libs: [ "libexample2_ext", ], cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], }
המשתמשים ב-libexample2_ext
יכולים פשוט לכלול את libexample2_ext_defaults
במאפיין defaults
שלהם:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
חבילות מוצרים
במערכת הבנייה של Android, המשתנה PRODUCT_PACKAGES
מציין את קובצי ההפעלה, הספריות המשותפות או החבילות שצריך
להתקין במכשיר. התלות הטרנזיטיבית של המודולים שצוינו מותקנת גם היא במכשיר באופן מרומז.
אם BOARD_VNDK_VERSION
מופעל, מודולים עם vendor_available
או vndk.enabled
מקבלים טיפול מיוחד. אם מודול של מסגרת תלוי במודול עם vendor_available
או vndk.enabled
, הגרסה הבסיסית נכללת בקבוצת ההתקנה הטרנזיטיבית. אם מודול של ספק
תלוי במודול עם vendor_available
, הגרסה של הספק נכללת
בסט ההתקנה הטרנזיטיבי. עם זאת, וריאציות של מודולים של ספקים עם vndk.enabled
מותקנות בין אם הן בשימוש של מודולים של ספקים ובין אם לא.
אם יחסי התלות לא גלויים למערכת הבנייה (למשל, ספריות משותפות שאפשר לפתוח באמצעות dlopen()
בזמן הריצה), צריך לציין את שמות המודולים ב-PRODUCT_PACKAGES
כדי להתקין את המודולים האלה באופן מפורש.
אם במודול מופיע vendor_available
או vndk.enabled
, השם של המודול מייצג את הווריאנט המרכזי שלו. כדי לציין במפורש את הווריאנט של הספק ב-PRODUCT_PACKAGES
, מוסיפים את הסיומת .vendor
לשם המודול. לדוגמה:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
בדוגמה הזו, libexample
מייצג את /system/lib[64]/libexample.so
ו-libexample.vendor
מייצג את /vendor/lib[64]/libexample.so
. כדי להתקין את /vendor/lib[64]/libexample.so
, מוסיפים את libexample.vendor
אל PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor