RenderScript เป็นเฟรมเวิร์กสำหรับเรียกใช้งานที่ต้องใช้การประมวลผลอย่างหนักที่มีประสิทธิภาพสูงบน Android โดยออกแบบมาเพื่อให้ใช้กับการประมวลผลข้อมูลแบบขนานกัน แม้ว่าภาระงานแบบอนุกรมจะได้ประโยชน์ด้วยเช่นกัน รันไทม์ RenderScript จะทำงานแบบขนานในโปรเซสเซอร์ที่มีอยู่ในอุปกรณ์ เช่น CPU และ GPU แบบหลายแกน ซึ่งช่วยให้นักพัฒนาแอปมุ่งเน้นที่การแสดงอัลกอริทึมแทนการจัดตารางงาน RenderScript มีประโยชน์อย่างยิ่งสำหรับแอปที่ประมวลผลรูปภาพ การถ่ายภาพเชิงคำนวณ หรือคอมพิวเตอร์วิทัศน์
อุปกรณ์ที่ใช้ Android 8.0 ขึ้นไปจะใช้เฟรมเวิร์ก RenderScript และ HAL ของผู้ให้บริการต่อไปนี้
รูปที่ 1 โค้ดผู้ให้บริการที่ลิงก์กับไลบรารีภายใน
ความแตกต่างจาก RenderScript ใน Android 7.x และต่ำกว่ามีดังนี้
- อินสแตนซ์ของไลบรารีภายในของ RenderScript 2 รายการในกระบวนการ ชุดหนึ่งมีไว้สำหรับเส้นทางสำรองของ CPU และมาจาก
/system/lib
โดยตรง ส่วนอีกชุดมีไว้สำหรับเส้นทาง GPU และมาจาก/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 (หรือที่เรียกว่า NDK ของผู้ให้บริการสำหรับ HAL ในกระบวนการเดียวกันหรือ VNDK-SP) ที่พร้อมใช้งานสำหรับโค้ดของผู้ให้บริการและสามารถลิงก์ได้ รวมถึงแสดงรายละเอียดไลบรารีเพิ่มเติมที่ไม่เกี่ยวข้องกับ RenderScript แต่มีให้สำหรับโค้ดของผู้ให้บริการด้วย
แม้ว่ารายการไลบรารีต่อไปนี้อาจแตกต่างกันระหว่างรุ่นต่างๆ ของ Android แต่รายการดังกล่าวจะเปลี่ยนแปลงไม่ได้สำหรับ Android บางรุ่น โปรดดูรายการไลบรารีที่พร้อมใช้งานล่าสุดที่ /system/etc/ld.config.txt
ไลบรารี RenderScript | ไลบรารีที่ไม่ใช่ RenderScript |
---|---|
|
|
การกำหนดค่าเนมสเปซของ Linker
ระบบจะบังคับใช้ข้อจำกัดการลิงก์ที่ป้องกันไม่ให้โค้ดของผู้ให้บริการใช้ไลบรารีที่ไม่ได้อยู่ใน VNDK-SP ขณะรันไทม์โดยใช้เนมสเปซของ linker (ดูรายละเอียดได้ในการออกแบบ VNDK)
ในอุปกรณ์ที่ใช้ Android 8.0 ขึ้นไป ระบบจะโหลด HAL ที่อยู่ในกระบวนการเดียวกัน (SP-HAL) ทั้งหมดยกเว้น RenderScript ไว้ในเนมสเปซของ linker
sphal
ระบบจะโหลด RenderScript ลงในเนมสเปซ rs
สำหรับ RenderScript โดยเฉพาะ ซึ่งเป็นตำแหน่งที่ช่วยให้สามารถบังคับใช้ไลบรารี RenderScript ได้แบบหลวมๆ มากขึ้น เนื่องจากการใช้งาน RS ต้องโหลดโค้ดไบต์ที่คอมไพล์แล้ว ระบบจึงเพิ่ม /data/*/*.so
ลงในเส้นทางของเนมสเปซ rs
(ไม่อนุญาตให้ SP-HAL อื่นๆ โหลดไลบรารีจากพาร์ติชันข้อมูล)
นอกจากนี้ เนมสเปซ rs
ยังอนุญาตให้ใช้ไลบรารีได้มากกว่าที่เนมสเปซอื่นๆ อนุญาต libmediandk.so
และ libft2.so
แสดงในเนมสเปซ rs
เนื่องจาก libRS_internal.so
มีไลบรารีเหล่านี้เป็น Dependency ภายใน
รูปที่ 2 การกำหนดค่าเนมสเปซสําหรับ linker
โหลดไดรเวอร์
เส้นทางสำรองของ CPU
ระบบจะเลือกเส้นทาง CPU หรือ GPU ขึ้นอยู่กับว่ามีบิต RS_CONTEXT_LOW_LATENCY
หรือไม่เมื่อสร้างบริบท RS เมื่อเลือกเส้นทาง CPU แล้ว libRS_internal.so
(การใช้งานหลักของเฟรมเวิร์ก RS) จะdlopen
จากเนมสเปซ linker เริ่มต้นโดยตรงซึ่งมีไลบรารี RS เวอร์ชันแพลตฟอร์ม
ระบบจะไม่ใช้งาน RS HAL จากผู้ให้บริการเลยเมื่อมีการใช้เส้นทางสำรองของ CPU และออบเจ็กต์ RsContext
จะสร้างขึ้นด้วย mVendorDriverName
ที่ไม่มีข้อมูล 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 ของผู้ให้บริการ) ลงในเนมสเปซ linker อื่นที่เรียกว่า sphal
จากนั้น RS
HAL จะdlopen
libRS_internal.so
ในเนมสเปซของโปรแกรมลิงก์อีกชื่อหนึ่งที่เรียกว่า rs
ผู้ให้บริการสามารถระบุไดรเวอร์ RS ของตนเองได้โดยการตั้งค่า Flag ของเวลาสร้าง OVERRIDE_RS_DRIVER
ซึ่งฝังอยู่ในการใช้งาน 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
เมื่อไม่พบ/โหลด 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 ของผู้ให้บริการที่โหลดลงในกระบวนการของระบบได้โดยตรงโดยไม่มีการผูก) ในฐานะ SP-HAL ไลบรารี bcc-plugin
จะมีลักษณะดังนี้
- ลิงก์กับไลบรารีที่เป็นเฟรมเวิร์กเท่านั้นไม่ได้ เช่น
libLLVM.so
- ลิงก์กับไลบรารี VNDK-SP ที่ใช้ได้กับผู้ให้บริการเท่านั้น
ระบบจะบังคับใช้ข้อจำกัดนี้โดยการโหลด bcc plugin
ลงในเนมสเปซ sphal
โดยใช้ฟังก์ชัน android_sphal_load_library()
ใน Android เวอร์ชันก่อนหน้า ระบบจะระบุชื่อปลั๊กอินโดยใช้ตัวเลือก -load
และโหลด lib โดยใช้ dlopen()
ธรรมดาโดย libLLVM.so
ใน Android 8.0 ขึ้นไป จะมีการระบุไว้ในตัวเลือก -plugin
และ Lib จะโหลดโดยตัว bcc
โดยตรง ตัวเลือกนี้จะเปิดใช้เส้นทางที่ไม่ใช่ Android โดยเฉพาะไปยังโปรเจ็กต์ LLVM แบบโอเพนซอร์ส
รูปที่ 5 กำลังโหลดปลั๊กอิน bcc, Android 7.x และต่ำกว่า
รูปที่ 6 กำลังโหลดปลั๊กอิน bcc, Android 8.0 ขึ้นไป
เส้นทางการค้นหาสำหรับ ld.mc
เมื่อเรียกใช้ ld.mc
ระบบจะส่งไลบรารีรันไทม์ RS บางรายการเป็นอินพุตให้กับโปรแกรมลิงก์ ระบบจะลิงก์บิตโค้ด RS จากแอปกับไลบรารีรันไทม์ และเมื่อโหลดบิตโค้ดที่แปลงแล้วลงในกระบวนการของแอป ระบบจะลิงก์ไลบรารีรันไทม์อีกครั้งจากบิตโค้ดที่แปลงแล้วแบบไดนามิก
ไลบรารีรันไทม์ ได้แก่
libcompiler_rt.so
libm.so
libc.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 แบบส่งผ่านexec_types
ใหม่ทั้งหมดที่เพิ่มในพาร์ติชันvendor
ผ่าน SEPolicy ของผู้ให้บริการต้องมีแอตทริบิวต์vendor_file_type
ซึ่งบังคับใช้ผ่านneverallows
- หลีกเลี่ยงการติดป้ายกำกับไฟล์อื่นที่ไม่ใช่
exec_types
ในพาร์ติชันvendor
เพื่อไม่ให้เกิดความขัดแย้งกับการอัปเดตแพลตฟอร์ม/เฟรมเวิร์กในอนาคต - ไลบรารีทั้งหมดที่ต้องพึ่งพาสำหรับ HAL ของกระบวนการเดียวกันที่ AOSP ระบุต้องติดป้ายกํากับเป็น
same_process_hal_file
ดูรายละเอียดเกี่ยวกับนโยบาย SELinux ได้ที่ Linux ที่เพิ่มประสิทธิภาพการรักษาความปลอดภัยใน Android
ความเข้ากันได้ของ ABI สำหรับบิตโค้ด
หากไม่มีการเพิ่ม API ใหม่ ซึ่งหมายความว่าไม่มีการอัปเกรดเวอร์ชัน HAL เฟรมเวิร์ก RS จะยังคงใช้ไดรเวอร์ GPU (HAL 1.0) ที่มีอยู่ต่อไป
สำหรับการเปลี่ยนแปลง HAL เล็กน้อย (HAL 1.1) ที่ไม่ส่งผลต่อบิตโค้ด เฟรมเวิร์กควรใช้ CPU สำหรับ API ที่เพิ่มเข้ามาใหม่เหล่านี้และใช้ไดรเวอร์ GPU (HAL 1.0) ในส่วนอื่นๆ ต่อไป
สำหรับการเปลี่ยนแปลงที่สำคัญของ HAL (HAL 2.0) ที่ส่งผลต่อการคอมไพล์/การลิงก์บิตโค้ด เฟรมเวิร์ก RS ควรเลือกไม่โหลดไดรเวอร์ GPU ที่ได้จากผู้ให้บริการ และใช้เส้นทาง CPU หรือ Vulkan ในการเร่งความเร็วแทน
การใช้บิตโค้ด RenderScript เกิดขึ้นใน 3 ระยะดังนี้
ระยะ | รายละเอียด |
---|---|
คอมไพล์ |
|
ลิงก์ |
|
โหลด |
|
นอกจาก HAL แล้ว API รันไทม์และสัญลักษณ์ที่ส่งออกยังเป็นอินเทอร์เฟซด้วย อินเทอร์เฟซทั้ง 2 รายการไม่มีการเปลี่ยนแปลงตั้งแต่ 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
เป็นตัวอย่างที่ดีของวิธีนำทรัพยากร Dependency ที่ไม่ใช่ VNDK-SP ออก
คอมไพเลอร์บิตโค้ด
คุณสามารถคอมไพล์โค้ดบิต RenderScript สําหรับไดรเวอร์ของผู้ให้บริการได้ 2 วิธีดังนี้
- เรียกใช้คอมไพเลอร์ RenderScript เฉพาะผู้ให้บริการใน
/vendor/bin/
(วิธีการคอมไพล์ GPU ที่แนะนำ) เช่นเดียวกับโมดูลไดรเวอร์อื่นๆ ไฟล์ไบนารีของคอมไพเลอร์ของผู้ให้บริการต้องไม่ใช้ไลบรารีระบบที่ไม่ได้อยู่ในรายการไลบรารี RenderScript ที่พร้อมให้บริการแก่ผู้ให้บริการ - เรียกใช้ระบบ bcc:
/system/bin/bcc
ด้วยbcc plugin
ที่ผู้ให้บริการให้มา โดยปลั๊กอินนี้ต้องไม่ใช้ไลบรารีระบบที่ไม่ได้อยู่ในรายการไลบรารี RenderScript ที่พร้อมให้บริการแก่ผู้ให้บริการ
หากผู้ให้บริการ bcc plugin
ต้องแทรกแซงการคอมไพล์ CPU และนําการพึ่งพา 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
ไฟล์ปฏิบัติการของคอมไพเลอร์ต้องเรียกใช้ได้ด้วยกระบวนการของแอป เช่นเดียวกับสำเนาของผู้ให้บริการของสำเนาลับ (/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: การประมวลผล GPU ของ Android ในอนาคต ข้อมูลแหล่งข้อมูลสำหรับการเลิกใช้งานนี้มีดังนี้
- ย้ายข้อมูลจาก Renderscript
- RenderScriptMigration Sample
- README ของชุดเครื่องมือการเปลี่ยน Intrinsics
- Intrinsics ReplacementToolkit.kt