RenderScript היא מסגרת להרצת משימות עתירות חישוב בביצועים גבוהים ב-Android. הוא מיועד לשימוש עם חישוב מקביל לנתונים, אבל יכול להועיל גם לעומסי עבודה סדרתיים. סביבת זמן הריצה של RenderScript מבצעת עבודה במקביל בין המעבדים שזמינים במכשיר, כמו מעבדי CPU מרובי ליבות ומעבדי GPU, וכך מאפשרת למפתחים להתמקד בביטוי אלגוריתמים במקום בתזמון עבודה. RenderScript שימושי במיוחד לאפליקציות שמבצעות עיבוד תמונות, צילום חישובי או ראייה ממוחשבת.
במכשירים עם Android 8.0 ומעלה נעשה שימוש במסגרת RenderScript הבאה וב-HALs של הספק:
איור 1. קוד הספק שמקשר לספריות פנימיות.
ההבדלים מ-RenderScript ב-Android 7.x ומטה כוללים:
- שני מופעים של ספריות פנימיות של RenderScript בתהליך. קבוצה אחת מיועדת לנתיב חלופי של CPU ומגיעה ישירות מ-
/system/lib, והקבוצה השנייה מיועדת לנתיב GPU ומגיעה מ-/system/lib/vndk-sp. - ספריות פנימיות של RS ב-
/system/libנוצרות כחלק מהפלטפורמה ומתעדכנות כשמבצעים שדרוג של/system/lib.system.imgעם זאת, ספריות (libs) ב-/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 עבור HALs באותו תהליך או VNDK-SP) שזמינות לקוד של ספקים ואפשר לקשר אותן. בנוסף, מפורטות בו ספריות נוספות שלא קשורות ל-RenderScript, אבל מסופקות גם לקוד של הספק.
הרשימה הבאה של ספריות עשויה להיות שונה בין גרסאות Android, אבל היא קבועה לגרסת Android ספציפית. כדי לראות רשימה עדכנית של הספריות הזמינות, אפשר לעיין בקישור /system/etc/ld.config.txt.
| ספריות RenderScript | ספריות שאינן RenderScript |
|---|---|
|
|
הגדרת מרחב שמות של Linker
ההגבלה על הקישור שמונעת שימוש בספריות שלא נמצאות ב-VNDK-SP על ידי קוד הספק נאכפת בזמן הריצה באמצעות מרחב השמות של ה-linker. (פרטים נוספים זמינים במצגת VNDK Design).
במכשיר עם Android מגרסה 8.0 ואילך, כל ה-HALs של אותו תהליך (SP-HALs)
למעט RenderScript נטענים בתוך מרחב השמות של ה-linker
sphal. RenderScript נטען למרחב השמות הספציפי ל-RenderScript rs, מיקום שמאפשר אכיפה קצת פחות מחמירה של ספריות RenderScript. הטמעת ה-RS צריכה לטעון את הביטקוד המהודר, ולכן /data/*/*.so נוסף לנתיב של מרחב השמות rs (ל-SP-HAL אחרים אסור לטעון ספריות ממחיצת הנתונים).
בנוסף, מרחב השמות rs מאפשר להשתמש ביותר ספריות מאשר מרחבי שמות אחרים. libmediandk.so ו-libft2.so חשופים למרחב השמות rs כי ל-libRS_internal.so יש תלות פנימית בספריות האלה.
איור 2. הגדרת מרחב שמות עבור הכלי לקישור.
מניעים לרכישה
נתיב חלופי של המעבד
בהתאם לקיום של הביט RS_CONTEXT_LOW_LATENCY כשיוצרים הקשר של RS, נבחר הנתיב של ה-CPU או של ה-GPU. כשבוחרים בנתיב של המעבד, מתבצעת הפניה ישירות אל libRS_internal.so (ההטמעה הראשית של מסגרת RS) ממרחב השמות של מקשר ברירת המחדל, שבו מסופקות ספריות RS של גרסת הפלטפורמה.dlopen
היישום של RS HAL מהספק לא נמצא בשימוש בכלל כשמשתמשים בנתיב חלופי של CPU, ואובייקט 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
אז dlopens libRS_internal.so במרחב שמות אחר של linker שנקרא rs.
ספקים יכולים לספק מנהל התקן משלהם של RS על ידי הגדרת הדגל של משך זמן של תהליך build
OVERRIDE_RS_DRIVER, שמוטמע בהטמעה של RS HAL
(hardware/interfaces/renderscript/1.0/default/Context.cpp). שם מנהל ההתקן הזה dlopened עבור הקשר של 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() כדי להורות ל-linker הדינמי לטעון את הספרייה -impl.so ממרחב השמות sphal.
כשעוברים ממרחב השמות sphal למרחב השמות rs, הטעינה מתבצעת באופן עקיף על ידי השורה הבאה בקובץ /system/etc/ld.config.txt:
namespace.sphal.link.rs.shared_libs = libRS_internal.so
בשורה הזו מצוין שהמקשר הדינמי צריך לטעון את libRS_internal.so ממרחב השמות rs אם אי אפשר למצוא או לטעון את lib ממרחב השמות 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:
- אי אפשר לקשר לספריות שמבוססות על 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. טעינת הפלאגין bcc, Android 8.0 ומעלה.
נתיבי חיפוש של ld.mc
כשמבצעים את ld.mc, ספריות זמן ריצה מסוימות של RS ניתנות כקלט למקשר. קוד הביט של RS מהאפליקציה מקושר לספריות של זמן הריצה, וכשקוד הביט שהומר נטען בתהליך של האפליקציה, הספריות של זמן הריצה מקושרות שוב באופן דינמי מקוד הביט שהומר.
ספריות זמן הריצה כוללות:
libcompiler_rt.solibm.solibc.so- נהג/ת RS (
libRSDriver.soאוOVERRIDE_RS_DRIVER)
כשמעלים את קוד הביטקוד שעבר קומפילציה לתהליך האפליקציה, צריך לספק את אותה ספרייה שבה נעשה שימוש ב-ld.mc. אחרת, יכול להיות שקוד הביטקוד המהודר
לא ימצא סמל שהיה זמין כשהוא קושר.
כדי לעשות זאת, מסגרת RS משתמשת בנתיבי חיפוש שונים לספריות זמן הריצה כשמבצעים ld.mc, בהתאם לשאלה אם מסגרת RS עצמה נטענת מ-/system/lib או מ-/system/lib/vndk-sp.
אפשר לקבוע את זה על ידי קריאת הכתובת של סמל שרירותי של ספריית מסגרת RS ושימוש ב-dladdr() כדי לקבל את נתיב הקובץ שממופה לכתובת.
מדיניות SELinux
בעקבות השינויים במדיניות SELinux ב-Android מגרסה 8.0 ואילך, צריך לפעול לפי כללים ספציפיים (שנאכפים באמצעות neverallows) כשמגדירים תוויות לקבצים נוספים במחיצה vendor:
-
vendor_fileחייבת להיות התווית שמוגדרת כברירת מחדל לכל הקבצים במחיצהvendor. מדיניות הפלטפורמה מחייבת את זה כדי לגשת להטמעות של HAL passthrough. - לכל
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) שלא משפיעים על bitcode, המסגרות צריכות לחזור לשימוש במעבד (CPU) עבור ממשקי ה-API החדשים האלה ולהמשיך להשתמש במנהל ההתקן של מעבד גרפי (GPU) (גרסה HAL 1.0) במקומות אחרים.
במקרה של שינויים משמעותיים ב-HAL (HAL 2.0) שמשפיעים על הידור או קישור של bitcode, במסגרות RS לא כדאי לטעון מנהלי התקנים של GPU שסופקו על ידי הספק, ועדיף להשתמש בנתיב CPU או Vulkan להאצה.
השימוש בביטקוד של RenderScript מתבצע בשלושה שלבים:
| במה | פרטים |
|---|---|
| לקמפל |
|
| קישור |
|
| טעינה |
|
בנוסף ל-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כתלות שלו. - ההטמעה של CPU
libRSDriver.soהיא דוגמה טובה להסרת תלות שאינה VNDK-SP.
מהדר ביטקוד
יש שתי דרכים לקמפל bitcode של RenderScript עבור מנהל ההתקן של הספק:
- הפעלת קומפיילר RenderScript ספציפי לספק ב-
/vendor/bin/(השיטה המועדפת לקומפילציה של GPU). בדומה למודולי דרייבר אחרים, קובץ הבינארי של מהדר הספק לא יכול להיות תלוי בספריית מערכת שלא מופיעה ברשימה של ספריות RenderScript שזמינות לספקים. - הפעלת מערכת ה-BCC:
/system/bin/bccעם ספק שסיפקbcc plugin; הפלאגין הזה לא יכול להיות תלוי בספריית מערכת שלא נמצאת ברשימה של ספריות RenderScript שזמינות לספקים.
אם הספק bcc plugin צריך להתערב בהידור של המעבד והתלות שלו ב-libLLVM.so לא ניתנת להסרה בקלות, הספק צריך להעתיק את bcc (ואת כל התלויות שאינן LL-NDK, כולל libLLVM.so, libbcc.so) למחיצה /vendor.
בנוסף, ספקים צריכים לבצע את השינויים הבאים:
איור 7. שינויים בדרייבר של הספק.
- העתקה של
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 יחזור לנתיב של ה-CPU.
מידע על הסיבות להוצאה משימוש של Renderscript זמין בבלוג Android Developers: Android GPU Compute Going Forward. פרטי המשאבים שיוצאו משימוש כוללים את הפרטים הבאים:
- העברה מ-RenderScript
- RenderScriptMigration Sample
- ערכת כלים להחלפת פונקציות פנימיות README
- החלפת פונקציות פנימיותToolkit.kt