אכיפת ממשקים של מחיצות מוצרים

ב-Android 11 מתבטלת החבילה של המחיצה product, וכך ללא תלות במחיצות system ו-vendor. כחלק מהשינויים האלה, עכשיו אפשר לשלוט בגישה של המחיצה product ל-Native ול-Java ממשקים (שדומה לאופן שבו אכיפת הממשק פועלת עבור vendor) מחיצות).

אכיפת ממשקים נייטיב

כדי להפעיל את האכיפה של הממשק המקורי, צריך להגדיר PRODUCT_PRODUCT_VNDK_VERSION אל current. (הגרסה מוגדרת אוטומטית לערך current כשערך המשלוח) רמת ה-API של היעד גדולה מ-29). האכיפה מאפשרת:

  • מודולים מקוריים במחיצה product לקישור:
    • באופן סטטי או דינמי למודולים אחרים במחיצה product לכלול ספריות סטטיות, ספריות משותפות או ספריות של כותרות.
    • באופן דינמי לספריות VNDK במחיצה system.
  • ספריות JNI ב-APKs לא כלולים במחיצת product לקישור אל ב-/product/lib או ב-/product/lib64 (בנוסף ל ספריות NDK).

האכיפה לא מתירה קישורים אחרים למחיצות מלבד product מחיצה.

אכיפת זמן היצירה (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 libs.

הטבלה הבאה מסכמת את המאפיינים של Android.bp ששימשו ליצירת התמונה וריאציות של אותו מודל.

נכסים ב-Android.bp נוצרו וריאציות
לפני האכיפה לאחר האכיפה
ברירת מחדל (ללא) התוכן הקבוע
(כולל /system, /system_ext וגם /product)
התוכן הקבוע
(כולל /system ו-/system_ext, אבל לא /product)
system_ext_specific: true התוכן הקבוע התוכן הקבוע
product_specific: true התוכן הקבוע מוצר
vendor: true ספק ספק
vendor_available: true ליבה, ספק ליבה, ספק
product_available: true לא רלוונטי ליבה, מוצר
vendor_available: true וגם product_available: true לא רלוונטי ליבה, מוצר, ספק
system_ext_specific: true וגם vendor_available: true ליבה, ספק ליבה, ספק
product_specific: true וגם vendor_available: true ליבה, ספק מוצר, ספק

אכיפת זמן build (Android.mk)

כאשר אכיפה של ממשק נייטיב מופעלת, מודולים מקוריים מותקנים למחיצה product יש סוג קישור native:product שיכול לקשר רק אל מודולים אחרים של native:product או native:vndk. מנסה לקשר אל כלשהו מודולים אחרים מלבד אלה יגרמו למערכת ה-build ליצור בדיקה של סוג קישור שגיאה.

אכיפה של זמן ריצה

כאשר אכיפה של ממשק נייטיב מופעלת, תצורת המקשר של Bionic Linker לא מאפשר לתהליכי מערכת להשתמש בספריות product, יצירת קטע product לתהליכי product שלא יכולים לקשר אליהם ספריות מחוץ למחיצה product (עם זאת, תהליכים כאלה יכולים לקשר אל ספריות VNDK). ניסיונות להפר את תצורת הקישור בסביבת זמן הריצה יגרמו תיכשל ותיצור הודעת שגיאה CANNOT LINK EXECUTABLE.

אכיפת ממשקי Java

כדי להפעיל את האכיפה של ממשק Java, צריך להגדיר PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE עד true. (הערך הוא מוגדר באופן אוטומטי לערך true כשרמת ה-API של המשלוח ליעד היא גדול מ-29.) כשהאכיפה מופעלת, הפעולות הבאות מאפשרות או אסורות. access:

API /system /system_ext /product /vendor /data
ממשק API ציבורי
@SystemApi
@הסתרה של API

כמו במחיצה של vendor, אפליקציה או ספריית Java ב-product המחיצה מורשית להשתמש רק בממשקי API ציבוריים ובממשקי API של המערכת; קישור לספרייה שאינו משתמש בממשקי API נסתרים. ההגבלה הזו חלה גם על קישור בזמן ה-build בזמן הריצה ובזמן הריצה.

אכיפת זמן build

בזמן ה-build, חברת Make ו-Songg מאמתות את המודולים של Java בproduct לא להשתמש בממשקי API נסתרים על ידי סימון של platform_apis sdk_version שדות. sdk_version של האפליקציות במחיצה product חייבות ימולאו ב-current, ב-system_current או בגרסה מספרית של ה-API, וגם השדה platform_apis חייב להיות ריק.

אכיפה של זמן ריצה

סביבת זמן הריצה של Android מאמתת שהאפליקציות במחיצה product לא משתמשות ממשקי API נסתרים, כולל תהליך חשיבה. פרטים נוספים זמינים במאמר הגבלות על לא SDK ממשקים.

הפעלת אכיפה של ממשק המוצר

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

שלב משימה חובה
1 להגדיר קובץ getfile של המערכת שלכם שמציין את החבילות עבור מחיצה system, ולאחר מכן להגדיר את בדיקת הדרישות של נתיב פריטי המידע שנוצרו בתהליך הפיתוח (Artifact) בdevice.mk (כדי למנוע התקנה של מודולים שאינם של המערכת למחיצה system). לא
2 למחיקת רשימת ההיתרים. לא
3 אכיפת ממשקים נייטיב וזיהוי כשלים בקישור בסביבת זמן הריצה (אפשר להפעיל ב: במקביל לאכיפה של Java). Y
4 לאכוף ממשקי Java ולאמת התנהגות בזמן ריצה (יכולה לפעול במקביל עם אכיפה מובנית). Y
5 בדיקת התנהגויות של סביבת זמן ריצה. Y
6 יש לעדכן את device.mk עם אכיפה של ממשק המוצר. Y

שלב 1: יצירת קובץ makefile והפעלת בדיקת נתיב של ארטיפקט

בשלב הזה מגדירים את קובץ ה-Makefile system.

  1. יוצרים קובץ 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),)
    
  2. בקובץ device.mk, מקבלים בירושה את קובץ ה-createfile של system מחיצה ולאפשר את בדיקת הדרישות של הנתיב של פריטי המידע שנוצרו בתהליך הפיתוח (Artifact). לדוגמה:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk)
    
    # Enable artifact path requirements checking
    PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
    

מידע על הדרישות לגבי הנתיב של פריט המידע שנוצר בתהליך הפיתוח (Artifact)

כשהערך בשדה PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS הוא true או strict, מערכת ה-build מונעת התקנה של חבילות שמוגדרות ב-createfiles אחרים הנתיבים שמוגדרים ב-require-artifacts-in-path וגם מונעים חבילות מוגדר בקובץ ה-Makefile הנוכחי מהתקנת ארטיפקטים מחוץ לנתיבים מוגדר ב-require-artifacts-in-path.

בדוגמה שלמעלה, כאשר PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS מוגדר לערך strict, קבצים מחוץ ל-oem_system.mk לא יכולים לכלול מודולים שהותקנו ב- המחיצה root או system. כדי לכלול את המודולים האלה, צריך מגדירים אותם בקובץ oem_system.mk עצמו או בקובץ makefile כלול. ניסיונות להתקין מודולים בנתיבים אסורים גורמים להפסקות ב-build. כדי לפתור את הבעיה מבצעים אחת מהפעולות הבאות:

  • אפשרות 1: מכניסים את מודול המערכת לקובצי makefiles שכלולים ב- oem_system.mk. כתוצאה מכך, כתוצאה מכך יש עמידה בדרישה של נתיב פריטי המידע שנוצרו בתהליך הפיתוח (Artifact) קיימים עכשיו בקובץ makefile כלול) ולכן הם מאפשרים להתקין קבוצת נתיבים ב-'demand-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. הזה השלב הזה הוא אופציונלי כי הגדרת תמונה נפוצה של system לא נדרשת כדי להפעיל אכיפה של ממשק המוצר. עם זאת, ריקון רשימת ההיתרים מועיל להגדרת הגבול system עם system_ext.

שלב 3: אכיפת ממשקים מותאמים

בשלב הזה מגדירים PRODUCT_PRODUCT_VNDK_VERSION := current, ואז בודקים כדי לאתר שגיאות build ושגיאות זמן ריצה, ולפתור אותן. כדי לבדוק את ההפעלה של המכשיר ואת היומנים ולאתר ולתקן כשלים בקישור בסביבת זמן הריצה:

  1. הגדרה של PRODUCT_PRODUCT_VNDK_VERSION := current.

  2. יוצרים את המכשיר ומחפשים שגיאות build. סביר להניח שתראו גרסאות build של וריאציות מוצר או וריאציות ליבה חסרים. הפסקות נפוצות כוללים:

    • כל מודול של hidl_interface שמכיל product_specific: true לא יהיה זמין למודולים של המערכת. כדי לפתור את הבעיה, צריך להחליף את product_specific: true עם system_ext_specific: true.
    • יכול להיות שבמודולים חסרה וריאציית המוצר שנדרשת למוצר מודולים. כדי לפתור את הבעיה, צריך להפוך את המודול הזה לזמין למחיצה של product באמצעות הגדרה של product_available: true או העברת המודול אל product מחיצה על ידי הגדרה של product_specific: true.
  3. צריך לפתור שגיאות build ולוודא שתהליך ה-build של המכשיר הושלם בהצלחה.

  4. צריך להעלות את התמונה להבהוב ולחפש שגיאות בזמן הריצה באתחול המכשיר וביומנים.

    • אם בתג linker ביומן של מקרי הבדיקה מוצג CANNOT LINK EXECUTABLE חסרה תלות בקובץ create, והוא לא תועד זמן build).
    • כדי לבדוק זאת ממערכת ה-build, צריך להוסיף את הספרייה הנדרשת שדה shared_libs: או required:.
  5. פותרים את יחסי התלות החסרים בעזרת ההנחיות שלמעלה.

שלב 4: אכיפת ממשקי Java

בשלב הזה מגדירים PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true, אחר כך מאתרים ומתקנים שגיאות build כתוצאה מכך. חפשו שני סוגים ספציפיים של שגיאות:

  • שגיאות בסוג הקישור. השגיאה הזו מציינת שאפליקציה מקשרת למודולים של 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}
    
  • דוגמה לתוצאה של וורידקס:

    #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

אחרי תיקון כל הכשלים ב-build ובזמן הריצה, ואימות של זמן הריצה כדי שההתנהגות תהיה תקינה צריך להגדיר את הדברים הבאים ב-device.mk:

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true