ב-Android 11, המחיצה product
מופרדת, כך שהיא לא תלויה במחיצות system
ו-vendor
. כחלק מהשינויים האלה, עכשיו אפשר לשלוט בגישה של מחיצת product
לממשקים מקוריים ולממשקי Java (בדומה לאופן שבו נאכף ממשק למחיצות vendor
).
אכיפת ממשקים מקוריים
כדי להפעיל את האכיפה של הממשק המקומי, מגדירים את PRODUCT_PRODUCT_VNDK_VERSION
לערך current
. (הגרסה מוגדרת אוטומטית ל-current
אם רמת ה-API של המשלוח ליעד גבוהה מ-29). האכיפה מאפשרת:
- מודולים מותאמים במחיצה
product
לקישור:- באופן סטטי או דינמי למודולים אחרים במחיצה
product
שכוללים ספריות סטטיות, משותפות או של כותרות. - באופן דינמי לספריות VNDK במחיצה
system
.
- באופן סטטי או דינמי למודולים אחרים במחיצה
- ספריות JNI ב-APK לא ארוז במחיצה
product
לקישור לספריות ב-/product/lib
או ב-/product/lib64
(בנוסף לספריות NDK).
האכיפה לא מאפשרת קישורים אחרים למחיצות אחרות מלבד המחיצה product
.
אכיפה של זמן ה-build (Android.bp)
ב-Android 11, מודולים של המערכת יכולים ליצור וריאציה של תמונת מוצר בנוסף לווריאציות של תמונות ליבה ותמונות ספקים. כשמופעלת אכיפה של ממשק מקורי (PRODUCT_PRODUCT_VNDK_VERSION
מוגדר ל-current
):
מודולים מותאמים במחיצה
product
נמצאים בווריאציית המוצר במקום בווריאציית הליבה.מודולים עם
product_available: true
בקובציAndroid.bp
שלהם זמינים לווריאציית המוצר.ספריות או קבצים בינאריים שצוין בהם
product_specific: true
יכולים לקשר לספריות אחרות שצוין בהןproduct_specific: true
אוproduct_available: true
בקובציAndroid.bp
שלהם.בספריות VNDK צריך להיות
product_available: true
בקובציAndroid.bp
כדי שקבצים בינאריים שלproduct
יוכלו לקשר לספריות VNDK.
בטבלה הבאה מפורטים מאפייני Android.bp
שמשמשים ליצירת וריאציות של תמונות.
מאפיינים ב-Android.bp | הווריאציות שנוצרו | |
---|---|---|
לפני האכיפה | אחרי האכיפה | |
ברירת מחדל (ללא) | core
(כולל /system , /system_ext ו-/product ) |
ליבה
(כולל /system ו-/system_ext אבל לא /product ) |
system_ext_specific: true |
core | core |
product_specific: true |
core | מכפלה |
vendor: true |
ספק | ספק |
vendor_available: true |
core, vendor | core, vendor |
product_available: true |
לא רלוונטי | core, product |
vendor_available: true וגם product_available:
true |
לא רלוונטי | core, product, vendor |
system_ext_specific: true וגם vendor_available:
true |
core, vendor | core, vendor |
product_specific: true וגם vendor_available:
true |
core, vendor | מוצר, ספק |
אכיפה בזמן ה-build (Android.mk)
כשאוכפים שימוש בממשק מקורי, למודולים מקוריים שמותקנים במחיצה product
יש סוג קישור native:product
שאפשר לקשר רק למודולים אחרים מסוג native:product
או native:vndk
. ניסיון לקשר למודולים אחרים גורם למערכת הבנייה ליצור שגיאה בבדיקת סוג הקישור.
אכיפה בזמן ריצה
כשהאכיפה של ממשק מקורי מופעלת, הגדרת המקשר של המקשר הביוני לא מאפשרת לתהליכי מערכת להשתמש בספריות product
, ויוצרת קטע product
לתהליכי product
שלא יכולים לקשר לספריות מחוץ למחיצה product
(אבל תהליכים כאלה יכולים לקשר לספריות VNDK). ניסיונות להפר את הגדרות הקישור בזמן הריצה גורמים לתהליך להיכשל וליצור הודעת שגיאה CANNOT LINK EXECUTABLE
.
אכיפת ממשקי Java
כדי להפעיל את האכיפה של ממשק Java, מגדירים את
PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
ל-true
. (הערך מוגדר אוטומטית ל-true
כשגרסת Shipping API של היעד גבוהה מ-29). כשהאכיפה מופעלת, היא מאפשרת או חוסמת את הגישה הבאה:
API | /system | /system_ext | /product | /vendor | /data |
---|---|---|---|---|---|
Public API | |||||
@SystemApi | |||||
@hide API |
כמו במחיצה vendor
, אפליקציה או ספריית Java במחיצה product
יכולות להשתמש רק בממשקי API ציבוריים וממשקי API של המערכת. אסור לקשר לספרייה שמשתמשת בממשקי API מוסתרים. ההגבלה הזו כוללת קישור בזמן הבנייה ושיקוף בזמן הריצה.
אכיפה בזמן הבנייה
בזמן הבנייה, מערכות Make ו-Soong בודקות את השדות platform_apis
ו-sdk_version
כדי לוודא שמודולי Java במחיצה product
לא משתמשים בממשקי API מוסתרים. הערך sdk_version
של אפליקציות במחיצה product
חייב להיות current
, system_current
או גרסה מספרית של ה-API, והשדה platform_apis
חייב להיות ריק.
אכיפה בזמן ריצה
סביבת זמן הריצה של Android מוודאת שאפליקציות במחיצה product
לא משתמשות בממשקי API מוסתרים, כולל רפלקציה. פרטים נוספים זמינים במאמר בנושא הגבלות על ממשקי SDK שאינם של Google.
הפעלת אכיפה של ממשק המוצר
כדי להפעיל את האכיפה של ממשק המוצר, פועלים לפי השלבים שמפורטים בקטע הזה.
שלב | משימה | חובה |
---|---|---|
1 | מגדירים קובץ makefile משלכם למערכת שמציין את החבילות עבור המחיצה system , ואז מגדירים את בדיקת הדרישה של נתיב הארטיפקטים ב-device.mk (כדי למנוע התקנה של מודולים שאינם של המערכת במחיצה system ). |
N |
2 | מנקים את רשימת ההיתרים. | N |
3 | אכיפה של ממשקי Native וזיהוי של כשלים בקישורי זמן ריצה (אפשר להפעיל במקביל לאכיפה של Java). | Y |
4 | אכיפה של ממשקי Java ואימות של התנהגות בזמן ריצה (אפשר להריץ במקביל לאכיפה מקומית). | Y |
5 | בודקים את ההתנהגויות בזמן הריצה. | Y |
6 | עדכון device.mk עם אכיפה של ממשק מוצר. |
Y |
שלב 1: יצירת קובץ makefile והפעלת בדיקה של נתיב הארטיפקט
בשלב הזה מגדירים את system
makefile.
יוצרים קובץ makefile שמגדיר את החבילות למחיצה
system
. לדוגמה, יוצרים קובץoem_system.mk
עם ההגדרות הבאות:$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system.mk) $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system.mk) # Applications PRODUCT_PACKAGES += \ CommonSystemApp1 \ CommonSystemApp2 \ CommonSystemApp3 \ # Binaries PRODUCT_PACKAGES += \ CommonSystemBin1 \ CommonSystemBin2 \ CommonSystemBin3 \ # Libraries PRODUCT_PACKAGES += \ CommonSystemLib1 \ CommonSystemLib2 \ CommonSystemLib3 \ PRODUCT_SYSTEM_NAME := oem_system PRODUCT_SYSTEM_BRAND := Android PRODUCT_SYSTEM_MANUFACTURER := Android PRODUCT_SYSTEM_MODEL := oem_system PRODUCT_SYSTEM_DEVICE := generic # For system-as-root devices, system.img should be mounted at /, so we # include ROOT here. _my_paths := \ $(TARGET_COPY_OUT_ROOT)/ \ $(TARGET_COPY_OUT_SYSTEM)/ \ $(call require-artifacts-in-path, $(_my_paths),)
בקובץ
device.mk
, מעבירים בירושה את קובץ ה-Makefile המשותף למחיצהsystem
ומפעילים את בדיקת הדרישות של נתיב הארטיפקט. לדוגמה:$(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk) # Enable artifact path requirements checking PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
מידע על הדרישות בנוגע לנתיב הארטיפקט
כשהערך של PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
מוגדר כ-true
או כ-strict
, מערכת ה-build מונעת התקנה של חבילות שהוגדרו בקובצי makefile אחרים בנתיבים שהוגדרו ב-require-artifacts-in-path
ו מונעת התקנה של חבילות שהוגדרו בקובץ ה-makefile הנוכחי בארטיפקטים מחוץ לנתיבים שהוגדרו ב-require-artifacts-in-path
.
בדוגמה שלמעלה, אם PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
מוגדר כ-strict
, קובצי makefile מחוץ ל-oem_system.mk
לא יכולים לכלול מודולים שהותקנו במחיצה root
או system
. כדי לכלול את המודולים האלה, צריך להגדיר אותם בקובץ oem_system.mk
עצמו או בקובץ makefile שכלול בו.
ניסיונות להתקין מודולים בנתיבים אסורים גורמים להפסקת הבנייה. כדי לתקן את ההפסקות, מבצעים אחת מהפעולות הבאות:
אפשרות 1: כוללים את מודול המערכת בקובצי ה-Makefile שכלולים ב-
oem_system.mk
. כך מתקיימת הדרישה לגבי נתיב הארטיפקט (כי המודולים קיימים עכשיו בקובץ makefile שכלול), ולכן אפשר להתקין את קבוצת הנתיבים ב-require-artifacts-in-path.אפשרות 2: התקנת מודולים במחיצה
system_ext
אוproduct
(ולא במחיצהsystem
).אפשרות 3: הוספת מודולים ל
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
. ברשימה הזו מפורטים המודולים שמותר להתקין.
שלב 2: מרוקנים את הרשימה המותרת
בשלב הזה, צריך לוודא שPRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
התיקייה ריקה כדי שכל המכשירים שמשתפים oem_system.mk
יוכלו גם לשתף תמונה אחת system
בלבד. כדי לרוקן את הרשימה המותרת, מעבירים את כל המודולים ברשימה למחיצה system_ext
או product
, או מוסיפים אותם ל-system
make files. השלב הזה הוא אופציונלי כי לא צריך להגדיר תמונה משותפת של system
כדי להפעיל את האכיפה של ממשק המוצר. עם זאת, מחיקת הרשימה המותרת יכולה לעזור בהגדרת system
הגבול באמצעות system_ext
.
שלב 3: אכיפה של ממשקי משתמש מקוריים
בשלב הזה מגדירים את PRODUCT_PRODUCT_VNDK_VERSION := current
, ואז מחפשים שגיאות build ושגיאות זמן ריצה ופותרים אותן. כדי לבדוק את האתחול של המכשיר ואת היומנים, ולמצוא ולתקן כשלים בקישור בזמן ריצה:
מגדירים את
PRODUCT_PRODUCT_VNDK_VERSION := current
.מבצעים את הבנייה של המכשיר ומחפשים שגיאות בנייה. סביר להניח שתיתקלו בכמה בעיות בבנייה בגלל וריאציות מוצרים חסרות או וריאציות ליבה חסרות. הפסקות נפוצות:
- כל מודול
hidl_interface
עםproduct_specific: true
לא יהיה זמין למודולים של המערכת. כדי לתקן את הבעיה, מחליפים אתproduct_specific: true
ב-system_ext_specific: true
. - יכול להיות שבמודולים חסרה וריאציית המוצר שנדרשת למודולים של מוצרים. כדי לפתור את הבעיה, צריך להגדיר את
product_available: true
כדי שהמודול יהיה זמין למחיצהproduct
, או להעביר את המודול למחיצהproduct
באמצעות הגדרתproduct_specific: true
.
- כל מודול
לפתור שגיאות בבנייה ולוודא שהמכשיר נבנה בהצלחה.
מבצעים Flash לתמונה ומחפשים שגיאות בזמן ריצה באתחול המכשיר וביומנים.
- אם התג
linker
מיומן של מקרה בדיקה מציג הודעהCANNOT LINK EXECUTABLE
, סימן שחסרה תלות בקובץ ה-make (והיא לא נרשמה בזמן הבנייה). - כדי לבדוק את זה ממערכת ה-build, מוסיפים את הספרייה הנדרשת לשדה
shared_libs:
אוrequired:
.
- אם התג
פותרים את הבעיות שקשורות לתלות חסרה באמצעות ההנחיות שלמעלה.
שלב 4: אכיפת ממשקי Java
בשלב הזה, מגדירים את PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true
, ואז מוצאים ומתקנים את שגיאות הבנייה שנובעות מכך. מחפשים שני סוגים ספציפיים של שגיאות:
שגיאות בסוג הקישור. השגיאה הזו מציינת שאפליקציה מקשרת למודולי Java עם
sdk_version
רחב יותר. כדי לפתור את הבעיה, אפשר להרחיב אתsdk_version
של האפליקציה או להגביל אתsdk_version
של הספרייה. שגיאה לדוגמה:error: frameworks/base/packages/SystemUI/Android.bp:138:1: module "SystemUI" variant "android_common": compiles against system API, but dependency "telephony-common" is compiling against private API.Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.
שגיאות בסמלים. השגיאה הזו מציינת שלא ניתן למצוא סמל כי הוא נמצא ב-API מוסתר. כדי לפתור את הבעיה, צריך להשתמש בממשק API גלוי (לא מוסתר) או למצוא חלופה. שגיאה לדוגמה:
frameworks/opt/net/voip/src/java/com/android/server/sip/SipSessionGroup.java:1051: error: cannot find symbol ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( ^ symbol: class ProxyAuthenticate location: class SipSessionGroup.SipSessionImpl
שלב 5: בדיקת התנהגויות בזמן ריצה
בשלב הזה, בודקים שההתנהגויות בזמן הריצה הן כמצופה. באפליקציות שאפשר לבצע בהן ניפוי באגים, אפשר לעקוב אחרי השימוש ב-API מוסתר באמצעות יומן באמצעות StrictMode.detectNonSdkApiUsage
(שיוצר יומן כשהאפליקציה משתמשת ב-API מוסתר). לחלופין, אפשר להשתמש בכלי לניתוח סטטי veridex כדי לקבל את סוג השימוש (קישור או שיקוף), רמת ההגבלה ומחסנית הקריאות.
תחביר Veridex:
./art/tools/veridex/appcompat.sh --dex-file={apk file}
תוצאה לדוגמה של veridex:
#1: Linking greylist-max-o Landroid/animation/AnimationHandler;-><init>()V use(s): Lcom/android/systemui/pip/phone/PipMotionHelper;-><init>(Landroid/content/Context;Landroid/app/IActivityManager;Landroid/app/IActivityTaskManager;Lcom/android/systemui/pip/phone/PipMenuActivityController;Lcom/android/internal/policy/PipSnapAlgorithm;Lcom/android/systemui/statusbar/FlingAnimationUtils;)V #1332: Reflection greylist Landroid/app/Activity;->mMainThread use(s): Landroidx/core/app/ActivityRecreator;->getMainThreadField()Ljava/lang/reflect/Field;
פרטים על השימוש ב-veridex זמינים במאמר בדיקה באמצעות הכלי veridex.
שלב 6: מעדכנים את device.mk
אחרי שמתקנים את כל הכשלים בבנייה ובזמן הריצה, ומוודאים שההתנהגויות בזמן הריצה הן כמצופה, מגדירים את הערכים הבאים ב-device.mk
:
PRODUCT_PRODUCT_VNDK_VERSION := current
PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true