RenderScript הוא מסגרת להרצת משימות עם עומס חישוב גבוה בביצועים גבוהים ב-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
. לא ניתן לקשר אותם לספריות ב-/system/lib
כי הספריות בספרייה הזו נוצרו עבור הפלטפורמה, ולכן יכול להיות שהן לא תואמות לקוד של הספק (כלומר, יכול להיות שסמלים יוסרו). אם תעשו זאת, לא תוכלו לבצע עדכון OTA רק של המסגרת.
עיצוב
בקטעים הבאים מפורטת תכנון של RenderScript ב-Android מגרסה 8.0 ואילך.
ספריות RenderScript שזמינות לספקים
בקטע הזה מפורטות ספריות RenderScript (שנקראות Vendor NDK for Same-Process HALs או VNDK-SP) שזמינות לקוד של הספק ואפשר לקשר אליהן. בנוסף, הוא מפרט ספריות נוספות שלא קשורות ל-RenderScript, אבל הן גם מסופקות לקוד של הספק.
רשימת הספריות הבאה עשויה להשתנות בין גרסאות Android, אבל היא לא משתנה בגרסה ספציפית של Android. רשימה עדכנית של הספריות הזמינות מופיעה במאמר /system/etc/ld.config.txt
.
ספריות RenderScript | ספריות שאינן 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
מופעל. במקרה כזה, ספריית ה-driver נטענת במרחב השמות 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
היא ספרייה שספק מסוים מספק, שנטענת במהדר bcc
. מכיוון ש-bcc
הוא תהליך מערכת בספרייה /system/bin
, אפשר להתייחס לספרייה bcc plugin
כ-SP-HAL (כלומר HAL של ספק שאפשר לטעון ישירות לתהליך המערכת בלי להשתמש ב-binder). כספריית SP-HAL, הספרייה bcc-plugin
:
- אי אפשר ליצור קישור לספריות של מסגרות בלבד, כמו
libLLVM.so
. - אפשר לקשר רק לספריות VNDK-SP שזמינות לספק.
כדי לאכוף את ההגבלה הזו, מעמיסים את bcc plugin
למרחב השמות sphal
באמצעות הפונקציה android_sphal_load_library()
. בגרסאות קודמות של Android, שם הפלאגין צוין באמצעות האפשרות -load
והספרייה נטענה באמצעות dlopen()
הפשוט על ידי libLLVM.so
. ב-Android מגרסה 8.0 ואילך, האפשרות הזו מצוינה באפשרות -plugin
וה-lib נטען ישירות על ידי bcc
עצמו. האפשרות הזו מאפשרת להשתמש בנתיב לא ספציפי ל-Android לפרויקט LLVM בקוד פתוח.

איור 5. טעינת הפלאגין של bcc, Android 7.x וגרסאות קודמות.

איור 6. טעינת הפלאגין 'הוספת נמען ללא הודעה', Android מגרסה 8.0 ואילך.
נתיבי חיפוש של ld.mc
כשמריצים את ld.mc
, חלק מהספריות של RS בסביבת זמן הריצה ניתנות כקלט למקשר. קוד ה-bitcode של RS מהאפליקציה מקושר לספריות של סביבת זמן הריצה, וכשהקוד ה-bitcode המומר נטען בתהליך של האפליקציה, ספריות סביבת זמן הריצה מקושרות שוב באופן דינמי מהקוד ה-bitcode המומר.
ספריות זמן הריצה כוללות:
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
.
אפשר לקבוע זאת על ידי קריאת הכתובת של סמל שרירותי של ספריית framework של RS, ולהשתמש ב-dladdr()
כדי לקבל את נתיב הקובץ שממופה לכתובת.
מדיניות SELinux
כתוצאה משינויי המדיניות של SELinux ב-Android 8.0 ואילך, עליכם לפעול לפי כללים ספציפיים (המאוכפים באמצעות neverallows
) כשאתם מסמנים קבצים נוספים במחיצה vendor
:
- התווית
vendor_file
חייבת להיות תווית ברירת המחדל לכל הקבצים במחיצהvendor
. המדיניות של הפלטפורמה דורשת זאת כדי לגשת להטמעות HAL של העברה דרך. - כל
exec_types
חדש שנוסף במחיצהvendor
דרך SEPolicy של הספק חייב לכלול את המאפייןvendor_file_type
. האכיפה מתבצעת באמצעותneverallows
. - כדי למנוע התנגשויות עם עדכונים עתידיים של פלטפורמה או מסגרת, מומלץ לא לתייג קבצים אחרים מלבד
exec_types
במחיצהvendor
. - כל יחסי התלות בספריות של ממשקי HAL לאותו תהליך שזוהו ב-AOSP חייבים להיות מסומנים בתווית
same_process_hal_file
.
פרטים על מדיניות SELinux זמינים במאמר Security-Enhanced 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.
מודולים של דרייברים
- אסור שמודולים של מנהלי התקנים יהיו תלויים בספריות מערכת שלא מופיעות ברשימה.
- הנהג חייב לספק
android.hardware.renderscript@1.0-impl_{NAME}
משלו, או להצהיר על ההטמעהandroid.hardware.renderscript@1.0-impl
שמוגדרת כברירת מחדל כיחס התלות שלו. - ההטמעה של המעבד
libRSDriver.so
היא דוגמה טובה להסרת יחסי תלות שאינם VNDK-SP.
קומפיילר של ביטקוד
יש שתי דרכים לקמפל קוד בייט של RenderScript עבור מנהל ההתקן של הספק:
- קריאה למהדר RenderScript ספציפי לספק ב-
/vendor/bin/
(השיטה המועדפת להדרה של GPU). בדומה למודולרים אחרים של הנהג, קובץ הבינארי של המהדר של הספק לא יכול להסתמך על ספריית מערכת שלא נכללת ברשימת ספריות RenderScript שזמינות לספקים. - קריאה ל-system bcc:
/system/bin/bcc
עםbcc plugin
שסופק על ידי הספק. הפלאגין הזה לא יכול להסתמך על ספריית מערכת שלא נמצאת ברשימת ספריות 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
- RenderScriptMigration Sample
- README של ערכת הכלים להחלפת מאפיינים מובנים
- החלפת רכיבים מובניםToolkit.kt