RenderScript הוא framework להרצת משימות אינטנסיביות עם ביצועים גבוהים ב-Android. הוא מיועד לשימוש עם חישוב מקבילי לנתונים, אבל גם עומסי עבודה סידוריים יכולים להפיק ממנו תועלת. סביבת זמן הריצה של RenderScript מבצעת עבודה במקביל במעבדים שזמינים במכשיר, כמו מעבדי CPU ו-GPU עם כמה ליבות, ומאפשרת למפתחים להתמקד בביטוי של אלגוריתמים במקום בתזמון העבודה. RenderScript שימושי במיוחד לאפליקציות שמבצעות עיבוד תמונות, צילום חישובי או ראיית מכונה.
במכשירים עם Android מגרסה 8.0 ואילך נעשה שימוש במסגרת RenderScript וב-HAL של הספקים הבאים:
איור 1. קוד של ספק שמקשר לספריות פנימיות.
ההבדלים ביחס ל-RenderScript ב-Android 7.x ואילך כוללים:
- שתי מכונות של ספריות פנימיות של RenderScript בתהליך. קבוצה אחת היא לנתיב החלופי של המעבד, והיא מתחילה ישירות ב-
/system/lib
. הקבוצה השנייה היא לנתיב של המעבד הגרפי, והיא מתחילה ב-/system/lib/vndk-sp
. - ספריות ה-RS הפנימיות ב-
/system/lib
נוצרות כחלק מהפלטפורמה ומתעדכנות כשsystem.img
משודרג. עם זאת, הספריות ב-/system/lib/vndk-sp
נוצרות עבור הספק ולא מתעדכנות כשמבצעים שדרוג ל-system.img
(אפשר לעדכן אותן כדי לתקן בעיות אבטחה, אבל ה-ABI שלהן נשאר זהה). - קוד הספק (RS HAL, RS driver ו-
bcc plugin
) מקושר לספריות הפנימיות של RenderScript שנמצאות ב-/system/lib/vndk-sp
. הם לא יכולים לקשר ל-libs ב-/system/lib
כי libs בספרייה הזו מיועדים לפלטפורמה, ולכן יכול להיות שהם לא תואמים לקוד הספק (כלומר, ייתכן שנסיר סמלים). אם תעשו זאת, לא תוכלו לבצע עדכון OTA רק של המסגרת.
עיצוב
הקטעים הבאים מפרטים את העיצוב של RenderScript ב-Android 8.0 ואילך.
ספריות RenderScript שזמינות לספקים
בקטע הזה מפורטות ספריות RenderScript (שנקראות Vendor NDK for Same-Process HALs או VNDK-SP) שזמינות לקוד של הספק ואפשר ליצור אליהן קישור. מפורטות בו גם ספריות נוספות שלא קשורות ל-RenderScript אבל מסופקות גם לקוד הספק.
רשימת הספריות הבאה עשויה להשתנות בין גרסאות Android, אבל היא לא משתנה בגרסה ספציפית של Android. רשימה עדכנית של הספריות הזמינות מופיעה במאמר /system/etc/ld.config.txt
.
ספריות RenderScript | Libs שאינם RenderScript |
---|---|
|
|
הגדרת מרחב השמות של Linker
הגבלת הקישור שחוסמת את השימוש בספריות שלא נמצאות ב-VNDK-SP על ידי קוד של ספק, נאכפת בסביבת זמן הריצה באמצעות מרחב השמות של ה-linker. (לפרטים, אפשר לעיין במצגת VNDK Design).
במכשיר עם Android מגרסה 8.0 ואילך, כל ממשקי ה-HAL באותו תהליך (SP-HAL) למעט RenderScript נטענים במרחב השמות של ה-linker sphal
. RenderScript נטען למרחב השמות הספציפי של RenderScript rs
, מיקום שמאפשר אכיפה מעט פחות מחמירה של ספריות RenderScript. מכיוון שההטמעה של RS צריכה לטעון את הקוד הבינארי המהדר, הערך /data/*/*.so
מתווסף לנתיב של מרחב השמות rs
(לא מורשים SP-HAL אחרים לטעון ספריות מהמחיצה של הנתונים).
בנוסף, מרחב השמות rs
מאפשר יותר ספריות מאשר מרחבי שמות אחרים. libmediandk.so
ו-libft2.so
חשופים למרחב השמות rs
כי
ל-libRS_internal.so
יש תלות פנימית בספריות האלה.
איור 2. הגדרת מרחב שמות לקישור.
טעינה של מנהלי התקנים
נתיב חלופי למעבד (CPU)
בהתאם לנוכחות הבייט RS_CONTEXT_LOW_LATENCY
כשיוצרים הקשר RS, המערכת בוחרת את הנתיב ל-CPU או ל-GPU. כשבוחרים את הנתיב של המעבד, libRS_internal.so
(ההטמעה הראשית של מסגרת RS) מופיע ישירות ב-dlopen
של מרחב השמות שמוגדר כברירת מחדל ב-linker, שבו מוצגת גרסת הפלטפורמה של ספריות RS.
כשהמערכת עוברת לנתיב החלופי של המעבד, לא נעשה שימוש כלל בהטמעת RS HAL מהספק, ונוצר אובייקט RsContext
עם mVendorDriverName
null. libRSDriver.so
מdlopen
(כברירת מחדל) וספריית הנהג נטענת ממרחב השמות default
כי מבצע הקריאה החוזרת (libRS_internal.so
) נטען גם הוא במרחב השמות default
.
איור 3. נתיב חלופי ל-CPU.
נתיב ה-GPU
לנתיב ה-GPU, השדה libRS_internal.so
נטען באופן שונה.
קודם כול, libRS.so
משתמש ב-android.hardware.renderscript@1.0.so
(ובבסיסו
libhidltransport.so
) כדי לטעון את
android.hardware.renderscript@1.0-impl.so
(הטמעה של
ספק של RS HAL) למרחב שמות אחר לקישור בשם sphal
. לאחר מכן, ה-HAL של RS dlopen
s libRS_internal.so
במרחב שמות אחר של קישור שנקרא rs
.
ספקים יכולים לספק מנהל התקן RS משלהם על ידי הגדרת הדגל OVERRIDE_RS_DRIVER
בזמן ה-build, שמוטמע בהטמעת ה-HAL של RS (hardware/interfaces/renderscript/1.0/default/Context.cpp
). לאחר מכן, שם מנהל ההתקן הזה עובר dlopen
לצורך הקשר של RS בנתיב ה-GPU.
היצירה של האובייקט RsContext
מועברת להטמעה של RS HAL. ה-HAL מבצע קריאה חוזרת למסגרת RS באמצעות הפונקציה rsContextCreateVendor()
, עם שם הנהג שישמש כארגומנט. לאחר מכן, מסגרת RS טוענת את מנהל ההתקן שצוין כשהשדה RsContext
מופעל. במקרה הזה, ספריית הנהגים נטענת למרחב השמות rs
כי האובייקט RsContext
נוצר בתוך מרחב השמות rs
ו-/vendor/lib
נמצא בנתיב החיפוש של מרחב השמות.
איור 4. נתיב חלופי ל-GPU.
במעבר ממרחב השמות default
למרחב השמות sphal
, libhidltransport.so
משתמשת בפונקציה android_load_sphal_library()
כדי להורות במפורש למקשר הדינמי לטעון את הספרייה -impl.so
ממרחב השמות sphal
.
במעבר ממרחב השמות sphal
למרחב השמות rs
, הטעינה מתבצעת באופן עקיף באמצעות השורה הבאה ב-/system/etc/ld.config.txt
:
namespace.sphal.link.rs.shared_libs = libRS_internal.so
השורה הזו קובעת שהמקשר הדינמי צריך לטעון את libRS_internal.so
ממרחב השמות rs
כשלא ניתן למצוא או לטעון את הספרייה ממרחב השמות sphal
(זה תמיד המצב כי מרחב השמות sphal
לא מחפש את /system/lib/vndk-sp
שבו נמצאת libRS_internal.so
). עם ההגדרה הזו, קריאה פשוטה של dlopen()
ל-libRS_internal.so
מספיקה כדי לבצע את המעבר במרחב השמות.
טעינת הפלאגין של 'עותק מוסתר'
bcc plugin
היא ספרייה שסופקה על ידי ספק, שנטענה במהדר (compiler) bcc
. מכיוון ש-bcc
הוא תהליך מערכת בספרייה /system/bin
, אפשר להתייחס לספרייה bcc plugin
כ-SP-HAL (כלומר HAL של ספק שאפשר לטעון ישירות לתהליך המערכת בלי להשתמש ב-binder). כספריית SP-HAL, הספרייה bcc-plugin
:
- אי אפשר לקשר לספריות של framework בלבד כמו
libLLVM.so
. - אפשר לקשר רק לספריות VNDK-SP שזמינות לספק.
כדי לאכוף את ההגבלה הזו, מעמיסים את bcc plugin
למרחב השמות sphal
באמצעות הפונקציה android_sphal_load_library()
. בגרסאות קודמות של Android, שם הפלאגין צוין באמצעות האפשרות -load
והספרייה נטענה באמצעות dlopen()
הפשוט על ידי libLLVM.so
. ב-Android מגרסה 8.0 ואילך, האפשרות הזו מצוינה באפשרות -plugin
והספרייה נטענת ישירות על ידי bcc
עצמו. האפשרות הזו מאפשרת להשתמש בנתיב לא ספציפי ל-Android לפרויקט LLVM בקוד פתוח.
איור 5. טעינת הפלאגין של bcc, Android 7.x וגרסאות קודמות.
איור 6. טעינת הפלאגין 'הוספת נמען ללא הודעה', Android מגרסה 8.0 ואילך.
נתיבי חיפוש של ld.mc
כשמריצים את ld.mc
, חלק מהlibs של זמן הריצה של RS ניתנים כקלט למקשר. הביטקוד של ה-RS מהאפליקציה מקושר אל ה-libs של סביבת זמן הריצה,
וכשהביטקוד שהומר נטען לתהליך של אפליקציה, ה-libs של סביבת זמן הריצה
מקושרים שוב באופן דינמי מהביטקוד שהומר.
ספריות זמן הריצה כוללות:
libcompiler_rt.so
libm.so
libc.so
- דרייבר RS (
libRSDriver.so
אוOVERRIDE_RS_DRIVER
)
כשאתם מעמיסים את הקוד המקודד ל-bitcode בתהליך האפליקציה, עליכם לספק את אותה ספרייה בדיוק שבה השתמש ld.mc
. אחרת, יכול להיות שהקוד המקודד לא ימצא סמל שהיה זמין כשהוא קושר.
כדי לעשות זאת, מסגרת RS משתמשת בנתיבי חיפוש שונים לספריות בסביבת זמן הריצה בזמן ביצוע ld.mc
, בהתאם לכך שמסגרת RS עצמה נטענת מ-/system/lib
או מ-/system/lib/vndk-sp
.
כדי לקבוע זאת, אפשר לקרוא את הכתובת של סמל שרירותי של מסגרת RSA, ולהשתמש ב-dladdr()
כדי למפות את נתיב הקובץ לכתובת.
מדיניות SELinux
כתוצאה משינויי המדיניות של SELinux ב-Android 8.0 ואילך, עליכם לפעול לפי כללים ספציפיים (שמופעלים באמצעות neverallows
) כשאתם מסמנים קבצים נוספים במחיצה vendor
:
vendor_file
חייבת להיות תווית ברירת המחדל לכל הקבצים במחיצהvendor
. מדיניות הפלטפורמה מחייבת גישה כזו כדי לגשת להטמעות של פרוטוקול העברת נתונים (HAL).- כל פריט
exec_types
חדש שנוסף במחיצהvendor
באמצעות SEPolicy של הספק, חייב לכלול מאפייןvendor_file_type
. האכיפה מתבצעת באמצעותneverallows
. - כדי למנוע התנגשויות עם עדכונים עתידיים של הפלטפורמה או של framework, מומלץ להימנע מתיוג של קבצים שאינם
exec_types
במחיצה שלvendor
. - יש לתייג את כל יחסי התלות של ספריות ל-HAL של תהליך שמזוהה על ידי AOSP כ-
same_process_hal_file
.
אפשר לקרוא פרטים נוספים על המדיניות של SELinux במאמר Linux עם שיפור אבטחה ב-Android.
תאימות ABI לביטקוד
אם לא יתווספו ממשקי API חדשים, כלומר לא תהיה עלייה בגרסה של HAL, מסגרות ה-RS ימשיכו להשתמש במנהל ההתקן הקיים של GPU (HAL 1.0).
בשינויים קטנים ב-HAL (HAL 1.1) שלא משפיעים על קוד ה-bit, המסגרות צריכות לעבור ל-CPU עבור ממשקי ה-API החדשים שנוספו ולהמשיך להשתמש ב-GPU (HAL 1.0) במקום אחר.
כשיש שינויים משמעותיים ב-HAL (HAL 2.0) שמשפיעים על הידור או קישור של קוד ביט, צריך להחליט לא לטעון את מנהלי ה-GPU שסופקו על ידי הספק, אלא להשתמש בנתיב של המעבד או של Vulkan לצורך האצה.
השימוש בקוד הבייט של RenderScript מתבצע בשלושה שלבים:
שלב | פרטים |
---|---|
הדרכה ל-Compile |
|
קישור |
|
טעינה |
|
בנוסף ל-HAL, ממשקי ה-API בסביבת זמן הריצה והסמלים המיוצאים הם גם ממשקים. ממשק המשתמש לא השתנה מאז Android 7.0 (API 24), ואין תוכניות מיידיות לשינוי שלו ב-Android 8.0 ואילך. עם זאת, אם הממשק ישתנה, גם גרסת ה-HAL תתווסף.
הטמעות של ספקים
עבור Android מגרסה 8.0 ואילך, נדרשים שינויים מסוימים במנהל ההתקן של ה-GPU כדי שמנהל ההתקן של ה-GPU יפעל כראוי.
מודולים של מנהלי התקנים
- המודולים של מנהלי ההתקנים לא יכולים להיות תלויים בספריות מערכת שלא מופיעות ברשימה.
- הנהג חייב לספק
android.hardware.renderscript@1.0-impl_{NAME}
משלו, או להצהיר על ההטמעהandroid.hardware.renderscript@1.0-impl
שמוגדרת כברירת מחדל כיחס התלות שלו. - ההטמעה של המעבד
libRSDriver.so
היא דוגמה טובה להסרת יחסי תלות שאינם של VNDK-SP.
מהדר ביטקוד
יש שתי דרכים לקמפל קוד בייט של RenderScript עבור מנהל ההתקן של הספק:
- הפעלת מהדר (compiler) ספציפי לספק ב-
/vendor/bin/
(השיטה המועדפת להדרת GPU). בדומה למודולרים אחרים של הנהג, קובץ הבינארי של המהדר של הספק לא יכול להסתמך על ספריית מערכת שלא נכללת ברשימת ספריות RenderScript שזמינות לספקים. - הפעלת 'עותק מוסתר של המערכת':
/system/bin/bcc
עםbcc plugin
שסופק על ידי הספק. הפלאגין הזה לא יכול להסתמך על ספריית מערכת שלא מופיעה ברשימה של libs של RenderScript שזמינים לספקים.
אם הספק bcc plugin
צריך להפריע ל-compilation של המעבד, ואי אפשר להסיר בקלות את התלות שלו ב-libLLVM.so
, הספק צריך להעתיק את bcc
(ואת כל יחסי התלות שאינם LL-NDK, כולל libLLVM.so
, libbcc.so
) למחיצה /vendor
.
בנוסף, הספקים צריכים לבצע את השינויים הבאים:
איור 7. שינויים ב-driver של הספק.
- מעתיקים את
libclcore.bc
למחיצה/vendor
. כך אפשר לוודא שהסנכרון שלlibclcore.bc
, שלlibLLVM.so
ושלlibbcc.so
. - משנים את הנתיב לקובץ ההפעלה
bcc
על ידי הגדרה של הערךRsdCpuScriptImpl::BCC_EXE_PATH
מההטמעה של RS HAL.
מדיניות SELinux
מדיניות SELinux משפיעה גם על הדרייבר וגם על קובצי ההפעלה של המהדר. כל המודולים של מנהלי ההתקנים חייבים להיות מסומנים בתווית same_process_hal_file
בקובץ file_contexts
של המכשיר. לדוגמה:
/vendor/lib(64)?/libRSDriver_EXAMPLE\.so u:object_r:same_process_hal_file:s0
תהליך האפליקציה צריך להיות מסוגל להפעיל את קובץ ההפעלה של המהדר, כמו גם את העותק של bcc (/vendor/bin/bcc
) מהספק. לדוגמה:
device/vendor_foo/device_bar/sepolicy/file_contexts: /vendor/bin/bcc u:object_r:same_process_hal_file:s0
מכשירים מדור קודם
מכשירים מדור קודם הם מכשירים שעומדים בתנאים הבאים:
- הערך של PRODUCT_SHIPPING_API_LEVEL נמוך מ-26.
- PRODUCT_FULL_TREBLE_OVERRIDE לא מוגדר.
במכשירים מדור קודם, ההגבלות לא נאכפות כשמשדרגים
ל-Android 8.0 ואילך. המשמעות היא שמנהלי ההתקנים יוכלו להמשיך לקשר לספריות
ב-/system/lib[64]
. עם זאת, בגלל השינוי בארכיטקטורה שקשור ל-OVERRIDE_RS_DRIVER
, צריך להתקין את android.hardware.renderscript@1.0-impl
במחיצה /vendor
. אם לא עושים זאת, זמן הריצה של RenderScript יאלץ לעבור לנתיב של המעבד.
למידע על המניעים להוצאה משימוש של Renderscript, כדאי לעיין בבלוג למפתחי Android: Android GPU Compute Going Forward. מידע על המשאבים שיופסקו כולל את הפרטים הבאים:
- מעבר מ-Renderscript
- דוגמה של RenderScript Migration
- README של ערכת הכלים להחלפת מאפיינים מובנים
- החלפת רכיבים מובניםToolkit.kt