מרחב השמות של ה-Linker

הקשר הדינמי מתמודד עם שני אתגרים בתכנון של Treble VNDK:

  • ספריות משותפות של SP-HAL והתלויות שלהן, כולל ספריות VNDK-SP, נטענות לתהליכי framework. צריכים להיות מנגנונים מסוימים למניעת התנגשויות בין סמלים.
  • dlopen() ו-android_dlopen_ext() יכולים להוסיף תלות בזמן ריצה שלא נראית בזמן הבנייה, וקשה לזהות אותה באמצעות ניתוח סטטי.

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

מצד שני, מנגנון מרחב השמות של ה-linker מספק גמישות, כך שאפשר לייצא ספריות משותפות מסוימות על ידי מרחב שמות של ה-linker ולהשתמש בהן על ידי מרחב שמות אחר של ה-linker. ספריות משותפות מיוצאות יכולות להפוך לממשקי תכנות אפליקציות (API) שגלויים לתוכניות אחרות, תוך הסתרת פרטי ההטמעה שלהן במרחבי השמות של המקשר.

לדוגמה, /system/lib[64]/libcutils.so ו-/system/lib[64]/vndk-sp-${VER}/libcutils.so הן שתי ספריות משותפות. יכולים להיות סמלים שונים בשתי הספריות. הן נטענות למרחבי שמות שונים של מקשרים, כך שמודולים של מסגרות יכולים להיות תלויים ב-/system/lib[64]/libcutils.so וספריות משותפות של SP-HAL יכולות להיות תלויות ב-/system/lib[64]/vndk-sp-${VER}/libcutils.so.

לעומת זאת, /system/lib[64]/libc.so היא דוגמה לספרייה ציבורית שמיוצאת על ידי מרחב שמות של linker ומיובאת למרחבי שמות רבים של linker. הפניות הקשורות של /system/lib[64]/libc.so, כמו libnetd_client.so, נטענות למרחב השמות שבו נמצא /system/lib[64]/libc.so. למרחבי שמות אחרים לא תהיה גישה לתלות הזו. המנגנון הזה כולל את פרטי ההטמעה ומספק את הממשקים הציבוריים.

איך זה עובד

הקשר הדינמי אחראי לטעינת הספריות המשותפות שצוינו ברשומות DT_NEEDED או הספריות המשותפות שצוינו בארגומנט של dlopen() או android_dlopen_ext(). בשני המקרים, ה-linker הדינמי מוצא את מרחב השמות של ה-linker שבו נמצא המתקשר ומנסה לטעון את התלות באותו מרחב שמות של ה-linker. אם ה-linker הדינמי לא יכול לטעון את הספרייה המשותפת במרחב השמות של ה-linker שצוין, הוא מבקש מספריות משותפות מיוצאות ממרחב השמות המקושר של ה-linker.

פורמט של קובץ תצורה

פורמט קובץ ההגדרות מבוסס על פורמט קובץ ה-INI. קובץ תצורה טיפוסי נראה כך:

dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin

[system]
additional.namespaces = sphal,vndk

namespace.default.isolated = true
namespace.default.search.paths = /system/${LIB}
namespace.default.permitted.paths = /system/${LIB}/hw
namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw

namespace.sphal.isolated = true
namespace.sphal.visible = true
namespace.sphal.search.paths = /odm/${LIB}:/vendor/${LIB}
namespace.sphal.permitted.paths = /odm/${LIB}:/vendor/${LIB}
namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}:/odm/${LIB}
namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.asan.permitted.paths  = /data/asan/odm/${LIB}:/odm/${LIB}
namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}:/vendor/${LIB}
namespace.sphal.links = default,vndk
namespace.sphal.link.default.shared_libs = libc.so:libm.so
namespace.sphal.link.vndk.shared_libs = libbase.so:libcutils.so

namespace.vndk.isolated = true
namespace.vndk.search.paths = /system/${LIB}/vndk-sp-29
namespace.vndk.permitted.paths = /system/${LIB}/vndk-sp-29
namespace.vndk.links = default
namespace.vndk.link.default.shared_libs = libc.so:libm.so

[vendor]
namespace.default.isolated = false
namespace.default.search.paths = /vendor/${LIB}:/system/${LIB}

קובץ התצורה כולל:

  • כמה מאפיינים של מיפוי קטעי מדריך בתחילת הקובץ, כדי שהמקשר הדינמי יוכל לבחור את הקטע הרלוונטי.
  • כמה קטעי הגדרה של מרחבי שמות של כלי הקישור:
    • כל קטע מכיל כמה מרחבי שמות (קודקודי גרף) וכמה קישורי חלופה בין מרחבי שמות (קשתות גרף).
    • לכל מרחב שמות יש בידוד משלו, נתיבי חיפוש, נתיבים מותרים והגדרות חשיפה.

בטבלאות הבאות מפורטת המשמעות של כל מאפיין.

מאפיין מיפוי של קטע בספרייה

נכס תיאור דוגמה

dir.name

נתיב לספרייה שהקטע [name] חל עליה.

כל מאפיין ממפה את קובצי ההפעלה שמתחת לספרייה לקטע ההגדרות של מרחבי השמות של ה-linker. יכול להיות שיש שני נכסים (או יותר) עם אותו name אבל הם מפנים לספריות שונות.

dir.system = /system/bin
dir.system = /system/xbin
dir.vendor = /vendor/bin

ההערה הזו מציינת שההגדרה שצוינה בקטע [system] חלה על קובצי ההפעלה שנטענים מ-/system/bin או מ-/system/xbin.

ההגדרה שצוינה בקטע [vendor] חלה על קובצי ההפעלה שנטענים מ-/vendor/bin.

מאפייני קשר

נכס תיאור דוגמה
additional.namespaces

רשימה של מרחבי שמות נוספים (בנוסף למרחב השמות default) עבור הקטע, שמופרדים באמצעות פסיקים.

additional.namespaces = sphal,vndk

המשמעות היא שיש שלושה מרחבי שמות (default, sphal ו-vndk) בהגדרה [system].

namespace.name.links

רשימה מופרדת בפסיקים של מרחבי שמות חלופיים.

אם לא ניתן למצוא ספרייה משותפת במרחב השמות הנוכחי, ה-linker הדינמי מנסה לטעון את הספרייה המשותפת ממרחבי השמות של הגיבוי. המרחב שצוין בתחילת הרשימה הוא בעדיפות גבוהה יותר.

namespace.sphal.links = default,vndk

אם ספרייה משותפת או קובץ הפעלה מבקשים ספרייה משותפת שלא ניתן לטעון למרחב השמות sphal, המקשר הדינמי מנסה לטעון את הספרייה המשותפת ממרחב השמות default.

לאחר מכן, אם אי אפשר לטעון את הספרייה המשותפת ממרחב השמות default, ה-linker הדינמי מנסה לטעון את הספרייה המשותפת ממרחב השמות vndk.

לבסוף, אם כל הניסיונות נכשלים, המקשר הדינמי מחזיר שגיאה.

namespace.name.link.other.shared_libs

רשימה של ספריות משותפות שמופרדות באמצעות נקודתיים, שאפשר לחפש במרחבי השמות other אם אי אפשר למצוא את הספריות האלה במרחב השמות name.

אי אפשר להשתמש בנכס הזה עם namespace.name.link.other.allow_all_shared_libs.

namespace.sphal.link.default.shared_libs = libc.so:libm.so

המשמעות היא שקישור הגיבוי מקבל רק את libc.so או את libm.so כשם הספרייה המבוקש. ה-linker הדינמי מתעלם מקישור הגיבוי ממרחב השמות sphal אל מרחב השמות default אם שם הספרייה המבוקש הוא לא libc.so או libm.so.

namespace.name.link.other.allow_all_shared_libs

ערך בוליאני שמציין אם אפשר לחפש את כל הספריות המשותפות במרחב השמות other כשאי אפשר למצוא את הספריות האלה במרחב השמות name.

אי אפשר להשתמש בנכס הזה עם namespace.name.link.other.shared_libs.

namespace.vndk.link.sphal.allow_all_shared_libs = true

המשמעות היא שכל שמות הספריות יכולים לעבור דרך קישור הגיבוי ממרחב השמות vndk למרחב השמות sphal.

מאפיינים של מרחב שמות

נכס תיאור דוגמה
namespace.name.isolated

ערך בוליאני שמציין אם ה-linker הדינמי צריך לבדוק איפה נמצאת הספרייה המשותפת.

אם isolated הוא true, אפשר לטעון רק את הספריות המשותפות שנמצאות בתוך אחת מהספריות search.paths (לא כולל ספריות משנה) או מתחת לאחת מהספריות permitted.paths (כולל ספריות משנה).

אם isolated הוא false (ברירת מחדל), ה-linker הדינמי לא בודק את הנתיב של הספריות המשותפות.

namespace.sphal.isolated = true

ההגדרה הזו מציינת שרק הספריות המשותפות בנתיב search.paths או מתחתיו permitted.paths יכולות להיטען במרחב השמות sphal.

namespace.name.search.paths

רשימה של ספריות שמופרדות בנקודתיים, שבהן יתבצע חיפוש של ספריות משותפות.

הספריות שצוינו ב-search.paths מתווספות לפני שם הספרייה המבוקש אם קריאות הפונקציה לרשומות dlopen() או DT_NEEDED לא מציינות את הנתיב המלא. הספרייה שצוינה בתחילת הרשימה היא בעדיפות גבוהה יותר.

אם הערך של isolated הוא true, אפשר לטעון ספריות משותפות שנמצאות באחת מהספריות search.paths (לא כולל ספריות משנה), בלי קשר למאפיין permitted.paths.

לדוגמה, אם search.paths הוא /system/${LIB} ו-permitted.paths ריק, אפשר לטעון את /system/${LIB}/libc.so אבל אי אפשר לטעון את /system/${LIB}/vndk/libutils.so.

namespace.default.search.paths = /system/${LIB}

המשמעות היא שהמקשר הדינמי מחפש את /system/${LIB} ספריות משותפות.

namespace.name.asan.search.paths

רשימה של ספריות שמופרדות באמצעות נקודתיים, לחיפוש ספריות משותפות כשמופעל AddressSanitizer (ASan).

המערכת מתעלמת מהמדיניות namespace.name.search.paths כשההגדרה ASan מופעלת.

namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}

המשמעות היא שכאשר ASan מופעל, המקשר הדינמי מחפש קודם ב-/data/asan/system/${LIB} ואז ב-/system/${LIB}.

namespace.name.permitted.paths

רשימה של ספריות (כולל ספריות משנה) שמופרדות באמצעות נקודתיים, שבהן המקשר הדינמי יכול לטעון את הספריות המשותפות (בנוסף ל-search.paths) כש-isolated הוא true.

אפשר גם לטעון את הספריות המשותפות שנמצאות בספריות המשנה של permitted.paths. לדוגמה, אם permitted.paths הוא /system/${LIB}, אפשר לטעון גם את /system/${LIB}/libc.so וגם את /system/${LIB}/vndk/libutils.so.

אם isolated הוא false, המערכת מתעלמת מ-permitted.paths ומוציאה אזהרה.

namespace.default.permitted.paths = /system/${LIB}/hw

המשמעות היא שאפשר לטעון את הספריות המשותפות שמופיעות מתחת ל-/system/${LIB}/hw במרחב השמות המבודד default.

לדוגמה, בלי permitted.paths, אי אפשר לטעון את libaudiohal.so אל מרחב השמות default./system/${LIB}/hw/audio.a2dp.default.so

namespace.name.asan.permitted.paths

רשימה של ספריות שמופרדות באמצעות נקודתיים, שבהן המקשר הדינמי יכול לטעון את הספריות המשותפות כש-ASan מופעל.

המערכת מתעלמת מהמדיניות namespace.name.permitted.paths כשההגדרה ASan מופעלת.

namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw

המשמעות היא שכאשר ASan מופעל, אפשר לטעון ספריות משותפות ב-/data/asan/system/${LIB}/hw או ב-/system/${LIB}/hw למרחב השמות המבודד default.

namespace.name.visible

ערך בוליאני שמציין אם התוכנית (מלבד libc) יכולה לקבל נקודת אחיזה למרחב שמות של מקשר באמצעות android_get_exported_namespace() ולפתוח ספרייה משותפת במרחב השמות של המקשר על ידי העברת נקודת האחיזה אל android_dlopen_ext().

אם visible הוא true, הפונקציה android_get_exported_namespace() תמיד מחזירה את ה-handle אם מרחב השמות קיים.

אם הערך של visible הוא false (ברירת מחדל), הפונקציה android_get_exported_namespace() תמיד מחזירה NULL ללא קשר לנוכחות של מרחב השמות. ספריות משותפות ניתן לטעון למרחב השמות הזה רק אם (1) הן נדרשות על ידי מרחב שמות אחר של מקשר שיש לו קישור חלופי למרחב השמות הזה, או (2) הן נדרשות על ידי ספריות משותפות אחרות או קובצי הפעלה במרחב השמות הזה.

namespace.sphal.visible = true

המשמעות היא שהפונקציה android_get_exported_namespace("sphal") יכולה להחזיר נקודת אחיזה תקינה למרחב שמות של Linker.

יצירת מרחב שמות של Linker

ב-Android 11, הגדרת ה-linker נוצרת בזמן הריצה בתיקייה /linkerconfig במקום להשתמש בקובצי טקסט פשוט בתיקייה ${android-src}/system/core/rootdir/etc. ההגדרה נוצרת בזמן האתחול על סמך סביבת זמן הריצה, שכוללת את הפריטים הבאים:

  • אם המכשיר תומך ב-VNDK
  • גרסת היעד של VNDK במחיצת הספק
  • גרסת ה-VNDK של חלוקת המוצרים
  • מודולי APEX מותקנים

הגדרות ה-Linker נוצרות על ידי פתרון תלויות בין מרחבי שמות של ה-Linker. לדוגמה, אם יש עדכונים במודולי APEX שכוללים עדכוני תלות, נוצרת הגדרת linker שמשקפת את השינויים האלה. פרטים נוספים על יצירת הגדרות של כלי הקישור זמינים במאמר ${android-src}/system/linkerconfig.

בידוד מרחב השמות של Linker

יש שלושה סוגי הגדרות. בהתאם לערכים של PRODUCT_TREBLE_LINKER_NAMESPACES ושל BOARD_VNDK_VERSION ב-BoardConfig.mk, התצורה המתאימה נוצרת בזמן האתחול.

PRODUCT_TREBLE_
LINKER_NAMESPACES
BOARD_VNDK_
VERSION
ההגדרות שנבחרו דרישה לגבי VTS
true current VNDK חובה למכשירים שהושקו עם Android מגרסה 9 ואילך
ריק VNDK Lite חובה למכשירים שהושקו עם Android 8.x
false ריק Legacy במכשירים שאינם Treble

ההגדרה של VNDK Lite מבודדת את הספריות המשותפות SP-HAL ו-VNDK-SP. ב-Android 8.0, זה חייב להיות קובץ ההגדרות של ה-linker הדינמי כש-PRODUCT_TREBLE_LINKER_NAMESPACES הוא true.

ההגדרה של VNDK מבודדת גם את הספריות המשותפות SP-HAL ו-VNDK-SP. בנוסף, ההגדרה הזו מספקת בידוד מלא של ה-linker הדינמי. כך מוודאים שהמודולים במחיצת המערכת לא יהיו תלויים בספריות המשותפות במחיצות הספק, ולהפך.

ב-Android מגרסה 8.1 ואילך, הגדרת VNDK היא הגדרת ברירת המחדל ומומלץ מאוד להפעיל בידוד מלא של ה-linker הדינמי על ידי הגדרת BOARD_VNDK_VERSION ל-current.

הגדרת VNDK

ההגדרה של VNDK מבודדת את התלות של הספרייה המשותפת בין מחיצת המערכת לבין מחיצות הספק. בהשוואה להגדרות שצוינו בקטע המשנה הקודם, ההבדלים הם:

  • תהליכי Framework

    • נוצרים מרחבי השמות default, vndk, sphal ו-rs.
    • כל מרחבי השמות מבודדים.
    • ספריות משותפות של המערכת נטענות למרחב השמות default.
    • קובצי SP-HAL נטענים למרחב השמות sphal.
    • ספריות משותפות של VNDK-SP נטענות למרחב השמות vndk.
  • תהליכים של ספקים

    • נוצרים מרחבי השמות default, ‏vndk ו-system.
    • מרחב השמות default מבודד.
    • ספריות משותפות של ספקים נטענות למרחב השמות default.
    • ספריות משותפות של VNDK ו-VNDK-SP נטענות במרחב השמות vndk.
    • ‫LL-NDK והתלויות שלו נטענים למרחב השמות system.

האיור הבא ממחיש את הקשר בין מרחבי השמות של הכלי לקישור.

תרשים של מרחב השמות של ה-Linker שמתואר בהגדרת ה-VNDK

איור 1. בידוד של מרחב שמות של מקשר (הגדרת VNDK).

בתמונה שלמעלה, LL-NDK ו-VNDK-SP מייצגים את הספריות המשותפות הבאות:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libGLESv3.so
    • libandroid_net.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libneuralnetworks.so
    • libsync.so
    • libvndksupport.so
    • libvulkan.so
  • VNDK-SP
    • android.hardware.graphics.common@1.0.so
    • android.hardware.graphics.mapper@2.0.so
    • android.hardware.renderscript@1.0.so
    • android.hidl.memory@1.0.so
    • libRSCpuRef.so
    • libRSDriver.so
    • libRS_internal.so
    • libbase.so
    • libbcinfo.so
    • libc++.so
    • libcutils.so
    • libhardware.so
    • libhidlbase.so
    • libhidlmemory.so
    • libhidltransport.so
    • libhwbinder.so
    • libion.so
    • libutils.so
    • libz.so

פרטים נוספים זמינים ב/linkerconfig/ld.config.txt מהמכשיר.

הגדרת VNDK Lite

החל מ-Android 8.0, ה-linker הדינמי מוגדר כך שהוא מבודד את הספריות המשותפות SP-HAL ו-VNDK-SP, כדי שהסמלים שלהן לא יתנגשו עם ספריות משותפות אחרות של framework. הקשר בין מרחבי השמות של הכלי לקישור מוצג בהמשך.

תרשים של מרחב שמות של Linker שמתואר בהגדרה של VNDK Lite
איור 2. בידוד של מרחב שמות של מקשר (הגדרה של VNDK Lite)

LL-NDK ו-VNDK-SP מייצגים את הספריות המשותפות הבאות:

  • LL-NDK
    • libEGL.so
    • libGLESv1_CM.so
    • libGLESv2.so
    • libc.so
    • libdl.so
    • liblog.so
    • libm.so
    • libnativewindow.so
    • libstdc++.so (לא בהגדרה)
    • libsync.so
    • libvndksupport.so
    • libz.so (הועבר אל VNDK-SP בהגדרה)
  • VNDK-SP
    • android.hardware.graphics.common@1.0.so
    • android.hardware.graphics.mapper@2.0.so
    • android.hardware.renderscript@1.0.so
    • android.hidl.memory@1.0.so
    • libbase.so
    • libc++.so
    • libcutils.so
    • libhardware.so
    • libhidlbase.so
    • libhidlmemory.so
    • libhidltransport.so
    • libhwbinder.so
    • libion.so
    • libutils.so

בטבלה שלמטה מפורטת הגדרת מרחבי השמות לתהליכי המסגרת, והיא לקוחה מהקטע [system] בהגדרת VNDK Lite.

מרחב שמות נכס ערך
default search.paths /system/${LIB}
/odm/${LIB}
/vendor/${LIB}
/product/${LIB}
isolated false
sphal search.paths /odm/${LIB}
/vendor/${LIB}
permitted.paths /odm/${LIB}
/vendor/${LIB}
isolated true
visible true
links default,vndk,rs
link.default.shared_libs LL-NDK
link.vndk.shared_libs VNDK-SP
link.rs.shared_libs libRS_internal.so
vndk (ל-VNDK-SP) search.paths /odm/${LIB}/vndk-sp
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-sp-${VER}
permitted.paths /odm/${LIB}/hw
/odm/${LIB}/egl
/vendor/${LIB}/hw
/vendor/${LIB}/egl
/system/${LIB}/vndk-sp-${VER}/hw
isolated true
visible true
links default
link.default.shared_libs LL-NDK
rs (ל-RenderScript) search.paths /odm/${LIB}/vndk-sp
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-sp-${VER}
/odm/${LIB}
/vendor/${LIB}
permitted.paths /odm/${LIB}
/vendor/${LIB}
/data (לליבת RS מהודרת)
isolated true
visible true
links default,vndk
link.default.shared_libs LL-NDK
libmediandk.so
libft2.so
link.vndk.shared_libs VNDK-SP

בטבלה שלמטה מוצגת הגדרת מרחבי השמות לתהליכי ספקים, והיא לקוחה מהקטע [vendor] בהגדרת VNDK Lite.

מרחב שמות נכס ערך
default search.paths /odm/${LIB}
/odm/${LIB}/vndk
/odm/${LIB}/vndk-sp
/vendor/${LIB}
/vendor/${LIB}/vndk
/vendor/${LIB}/vndk-sp
/system/${LIB}/vndk-${VER}
/system/${LIB}/vndk-sp-${VER}
/system/${LIB} (הוצאה משימוש)
/product/${LIB} (הוצאה משימוש)
isolated false

פרטים נוספים זמינים ב/linkerconfig/ld.config.txt מהמכשיר.

היסטוריית המסמך

שינויים ב-Android 11

  • ב-Android 11, קובצי ld.config.*.txt הסטטיים מוסרים מבסיס הקוד, ו-LinkerConfig יוצר אותם בזמן הריצה במקום זאת.

שינויים ב-Android 9

  • ב-Android 9, מרחב השמות של המקשר vndk נוסף לתהליכי הספק, וספריות משותפות של VNDK מבודדות ממרחב השמות של המקשר שמוגדר כברירת מחדל.
  • מחליפים את PRODUCT_FULL_TREBLE בערך ספציפי יותר של PRODUCT_TREBLE_LINKER_NAMESPACES.
  • ב-Android 9, השמות של קובצי ההגדרה הבאים של ה-linker הדינמי השתנו.
    ‫Android 8.x ‫Android 9 תיאור
    ld.config.txt.in ld.config.txt למכשירים עם בידוד של מרחבי שמות של מקשרים בזמן ריצה
    ld.config.txt ld.config.vndk_lite.txt למכשירים עם בידוד של מרחב השמות של המקשר VNDK-SP
    ld.config.legacy.txt ld.config.legacy.txt למכשירים מדור קודם עם Android מגרסה 7.x ומטה
  • הסרה של android.hardware.graphics.allocator@2.0.so.
  • נוספו מחיצות product ו-odm.