RenderScript是一個在 Android 上以高效能運行運算密集型任務的框架。它設計用於資料並行計算,儘管串行工作負載也可以受益。 RenderScript 運行時可跨裝置上可用的處理器(例如多核心 CPU 和 GPU)並行化工作,使開發人員能夠專注於表達演算法而不是調度工作。 RenderScript 對於執行影像處理、計算攝影或電腦視覺的應用程式特別有用。
運行 Android 8.0 及更高版本的裝置使用以下 RenderScript 框架和供應商 HAL:
與 Android 7.x 及更低版本中的 RenderScript 的差異包括:
- 進程中 RenderScript 內部庫的兩個實例。一組用於 CPU 後備路徑,直接來自
/system/lib
;另一組用於 GPU 路徑,來自/system/lib/vndk-sp
。 -
/system/lib
中的 RS 內部庫是作為平台的一部分建構的,並隨著system.img
的升級而更新。但是,/system/lib/vndk-sp
中的庫是為供應商構建的,並且在升級system.img
時不會更新(雖然可以更新它們以進行安全修復,但它們的 ABI 保持不變)。 - 供應商程式碼(RS HAL、RS 驅動程式和
bcc plugin
)與位於/system/lib/vndk-sp
RenderScript 內部庫連結。它們無法連結到/system/lib
中的庫,因為該目錄中的庫是為平台構建的,因此可能與供應商代碼不相容(即,符號可能被刪除)。這樣做會使純框架 OTA 變得不可能。
設計
以下部分詳細介紹了 Android 8.0 及更高版本中的 RenderScript 設計。
供應商可用的 RenderScript 庫
本部分列出了可供供應商程式碼使用且可連結的 RenderScript 程式庫(稱為相同進程 HAL 的供應商 NDK 或 VNDK-SP)。它還詳細介紹了與 RenderScript 無關但也提供給供應商程式碼的其他程式庫。
雖然以下庫列表可能因 Android 版本而異,但對於特定 Android 版本來說是不可變的;有關可用庫的最新列表,請參閱/system/etc/ld.config.txt
。
渲染腳本庫 | 非 RenderScript 庫 |
---|---|
|
|
連結器命名空間配置
防止供應商程式碼使用不在 VNDK-SP 中的庫的連結限制是在運行時使用連結器命名空間強制執行的。 (有關詳細信息,請參閱VNDK 設計演示。)
在運行 Android 8.0 及更高版本的裝置上,除 RenderScript 之外的所有同進程 HAL (SP-HAL) 均載入到連結器命名空間sphal
內。 RenderScript 被載入到 RenderScript 特定的命名空間rs
中,該位置可以稍微寬鬆地執行 RenderScript 函式庫。由於RS實作需要載入編譯後的bitcode,因此將/data/*/*.so
加入到rs
命名空間的路徑中(其他SP-HAL不允許從data分區載入lib)。
此外, rs
命名空間允許比其他命名空間提供的更多庫。 libmediandk.so
和libft2.so
暴露於rs
命名空間,因為libRS_internal.so
對這些函式庫具有內部依賴性。
載入驅動程式
CPU 後備路徑
根據建立 RS 上下文時RS_CONTEXT_LOW_LATENCY
位元的存在情況,選擇 CPU 或 GPU 路徑。選擇 CPU 路徑後, libRS_internal.so
(RS 框架的主要實作)會直接從提供 RS 函式庫的平台版本的預設連結器命名空間中dlopen
。
當採用 CPU 回退路徑時,完全不使用供應商的 RS HAL 實現,並且使用 null mVendorDriverName
建立RsContext
物件。 libRSDriver.so
(預設)是dlopen
編輯的,且驅動程式庫是從default
命名空間載入的,因為呼叫者 ( libRS_internal.so
) 也是在default
命名空間中載入的。
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
。然後,RS HAL 在另一個名為rs
的連結器命名空間中dlopen
s libRS_internal.so
。
供應商可以透過設定建置時標誌OVERRIDE_RS_DRIVER
來提供自己的 RS 驅動程序,該標誌嵌入到 RS HAL 實作中 ( hardware/interfaces/renderscript/1.0/default/Context.cpp
)。然後,該驅動程式名稱將被dlopen
編輯為 GPU 路徑的 RS 上下文。
RsContext
物件的創建委託給 RS HAL 實作。 HAL 使用rsContextCreateVendor()
函數回呼 RS 框架,並將驅動程式的名稱用作參數。然後,RS 框架會在RsContext
初始化時載入指定的驅動程式。在這種情況下,驅動程式庫被載入到rs
命名空間中,因為RsContext
物件是在rs
命名空間內建立的,並且/vendor/lib
位於命名空間的搜尋路徑中。
從default
命名空間轉換到sphal
命名空間時, libhidltransport.so
使用android_load_sphal_library()
函數明確指令動態連結器從sphal
命名空間載入-impl.so
函式庫。
從sphal
命名空間轉換到rs
命名空間時,載入是透過/system/etc/ld.config.txt
中的以下行間接完成的:
namespace.sphal.link.rs.shared_libs = libRS_internal.so
此行指定當無法從sphal
命名空間找到/載入 lib 時,動態連結器應從rs
命名空間載入libRS_internal.so
(這種情況總是如此,因為sphal
命名空間不會搜尋/system/lib/vndk-sp
其中libRS_internal.so
駐留)。使用此配置,對libRS_internal.so
進行簡單的dlopen()
呼叫就足以進行命名空間轉換。
載入密件副本插件
bcc plugin
是供應商提供的函式庫,載入到bcc
編譯器中。因為bcc
是/system/bin
目錄中的系統進程,所以bcc plugin
庫可以被認為是 SP-HAL(即可以直接載入到系統進程中而無需綁定的供應商 HAL)。作為 SP-HAL, bcc-plugin
庫:
- 無法連結僅限框架的函式庫,例如
libLLVM.so
。 - 只能連結到供應商可用的 VNDK-SP 庫。
透過使用android_sphal_load_library()
函數將bcc plugin
載入到sphal
命名空間中來強制執行此限制。在先前版本的 Android 中,外掛程式名稱是使用-load
選項指定的,並且libLLVM.so
使用簡單的dlopen()
載入程式庫。在 Android 8.0 及更高版本中,這是在-plugin
選項中指定的,並且 lib 由bcc
本身直接加載。此選項啟用開源 LLVM 專案的非 Android 特定路徑。
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 政策
由於 Android 8.0 及更高版本中的 SELinux 策略發生變化,在標記vendor
分區中的其他文件時,您必須遵循特定規則(透過neverallows
強制執行):
-
vendor_file
必須是vendor
分區中所有檔案的預設標籤。平台策略要求它存取直通 HAL 實現。 - 透過供應商 SEPolicy 在
vendor
分區中新增的所有新exec_types
必須具有vendor_file_type
屬性。這是透過neverallows
強制執行的。 - 為了避免與未來的平台/框架更新發生衝突,請避免在
vendor
分區中標記除exec_types
以外的檔案。 - AOSP 識別的相同進程 HAL 的所有庫相依性必須標記為
same_process_hal_file
。
有關 SELinux 策略的詳細信息,請參閱Android 中的安全增強型 Linux 。
位元碼的 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 位元碼分三個階段進行:
階段 | 細節 |
---|---|
編譯 |
|
關聯 |
|
載入 |
|
除了 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 依賴項的一個很好的範例。
位元碼編譯器
您可以透過兩種方式為供應商驅動程式編譯 RenderScript 位元程式碼:
- 在
/vendor/bin/
中呼叫特定於供應商的 RenderScript 編譯器(GPU 編譯的首選方法)。與其他驅動程式模組類似,供應商編譯器二進位檔案不能依賴任何不在供應商可用的 RenderScript 程式庫清單中的系統程式庫。 - 使用供應商提供的
bcc plugin
呼叫系統 bcc:/system/bin/bcc
;該插件不能依賴任何不在供應商可用的 RenderScript 庫列表中的系統庫。
如果供應商bcc plugin
需要乾擾 CPU 編譯並且無法輕鬆刪除其對libLLVM.so
依賴項,則供應商應將bcc
(以及所有非 LL-NDK 依賴項,包括libLLVM.so
、 libbcc.so
)複製到/vendor
分區。
此外,供應商還需要進行以下更改:
- 將
libclcore.bc
複製到/vendor
分區。這可確保libclcore.bc
、libLLVM.so
和libbcc.so
同步。 - 透過從 RS HAL 實作設定
RsdCpuScriptImpl::BCC_EXE_PATH
來變更bcc
可執行檔的路徑。
SELinux 政策
SELinux 策略會影響驅動程式和編譯器執行檔。所有驅動程式模組必須在裝置的file_contexts
中標記為same_process_hal_file
。例如:
/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 開發人員部落格: Android GPU 運算的發展。此棄用的資源資訊包括以下內容:
- 從 Renderscript 遷移
- 渲染腳本遷移範例
- 內在函數替換工具包自述文件
- 內在函數替換工具包.kt