RenderScript 是一種架構,可用於在 Android 上以高效能執行需要進行大量運算的工作。這項服務專為資料平行運算設計,但也可為序列工作負載帶來好處。RenderScript 執行階段會透過裝置上可用的各個處理器 (例如多核心 CPU 和 GPU) 平行處理工作,讓開發人員可以專注於表示演算法,而非安排執行工作。RenderScript 特別適合用於執行圖片處理作業、計算攝影或電腦視覺的應用程式。
搭載 Android 8.0 以上版本的裝置會使用下列 RenderScript 架構和供應商 HAL:
圖 1. 連結至內部程式庫的供應商程式碼。
與 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 程式庫
本節列出可供供應商程式碼使用的算繪指令程式庫 (稱為供應商 NDK 同進程式 HAL 或 VNDK-SP),並可連結至這些程式庫。它也詳細說明與 RenderScript 無關,但也提供給供應商程式的其他程式庫。
雖然不同 Android 版本的程式庫清單可能不同,但特定 Android 版本的程式庫清單不會變更;如需最新的程式庫清單,請參閱 /system/etc/ld.config.txt
。
RenderScript 程式庫 | 非 RenderScript 程式庫 |
---|---|
|
|
連結器命名空間設定
在執行階段使用連結器命名空間時,會強制執行連結限制,以防止供應商程式碼使用不在 VNDK-SP 中的程式庫。(詳情請參閱 VNDK Design 簡報)。
在搭載 Android 8.0 以上版本的裝置上,所有相同程序 HAL (SP-HAL) 除了 RenderScript 以外,都會載入至連結器命名空間 sphal
中。RenderScript 會載入至專屬於 RenderScript 的命名空間 rs
,這個位置可讓 RenderScript 程式庫的執行較為寬鬆。由於 RS 實作需要載入已編譯的位元碼,因此 /data/*/*.so
會新增至 rs
命名空間的路徑中 (系統不允許其他 SP-HAL 從資料分區載入程式庫)。
此外,rs
命名空間允許的程式庫比其他命名空間提供的程式庫更多。libmediandk.so
和 libft2.so
會向 rs
命名空間公開,因為 libRS_internal.so
具有這些程式庫的內部依附元件。
圖 2. 連結器的命名空間設定。
負載驅動程式
CPU 備用路徑
視建立 RS 情境時是否存在 RS_CONTEXT_LOW_LATENCY
位元而定,系統會選取 CPU 或 GPU 路徑。選取 CPU 路徑後,系統會直接從提供 RS 程式庫平台版本的預設連接器命名空間的 libRS_internal.so
(RS 架構的主要實作) 直接 dlopen
。
當採用 CPU 備用路徑,並使用空值 mVendorDriverName
建立 RsContext
物件時,系統完全不會使用供應商的 RS HAL 實作項目。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
的不同連結器命名空間。RS HAL 可以在另一個名為 rs
的連結器命名空間中 dlopen
和 libRS_internal.so
。
供應商可以設定建構時間旗標 OVERRIDE_RS_DRIVER
(嵌入 RS HAL 實作項目 (hardware/interfaces/renderscript/1.0/default/Context.cpp
) 來提供自己的 RS 驅動程式。之後,這個驅動程式名稱會dlopen
用於 GPU 路徑的 RS 情境。
RsContext
物件的建立作業會委派給 RS HAL 實作。HAL 會使用 rsContextCreateVendor()
函式回呼至 RS 架構,並使用驅動程式的名稱做為引數。接著,RS 架構會在 RsContext
初始化時載入指定的驅動程式。在本範例中,驅動程式程式庫會載入至 rs
命名空間,因為 RsContext
物件是在 rs
命名空間中建立,/vendor/lib
則位於命名空間的搜尋路徑中。
圖 4. GPU 備用路徑。
從 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
命名空間不會搜尋 libRS_internal.so
所在的 /system/lib/vndk-sp
)。有了這項設定,只要對 libRS_internal.so
發出簡單的 dlopen()
呼叫,就能進行命名空間轉換。
載入密件副本外掛程式
bcc plugin
是供應商提供的程式庫,已載入至 bcc
編譯器。由於 bcc
是 /system/bin
目錄中的系統程序,因此 bcc plugin
程式庫可視為 SP-HAL (也就是可直接載入系統程序的供應商 HAL,無須繫結)。bcc-plugin
程式庫是 SP-HAL,可執行以下操作:
- 無法連結至僅限架構的程式庫,例如
libLLVM.so
。 - 只能連結供應商可用的 VNDK-SP 程式庫。
這項限制是透過使用 android_sphal_load_library()
函式,將 bcc plugin
載入 sphal
命名空間來強制執行。在舊版 Android 中,外掛程式名稱是使用 -load
選項指定,而程式庫則是使用 libLLVM.so
的簡易 dlopen()
載入。在 Android 8.0 以上版本中,-plugin
選項會指定這個項目,而 bcc
本身會直接載入 lib。這個選項可啟用非 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 政策
由於 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),架構應為這些新加入的 API 改用 CPU,並在其他地方繼續使用 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
叫用系統密件副本:/system/bin/bcc
;這個外掛程式不得依附任何未列在 RenderScript 程式庫清單中的系統程式庫。
如果供應商 bcc plugin
需要干擾 CPU 編譯作業,且其對 libLLVM.so
的依附元件無法輕易移除,供應商應將 bcc
(以及所有非 LL-NDK 依附元件,包括 libLLVM.so
、libbcc.so
) 複製到 /vendor
分割區。
此外,供應商也必須進行以下變更:
圖 7. 供應商驅動程式變更。
- 將
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 Compute 的未來發展。這項淘汰作業的資源資訊包括:
- 從 Renderscript 遷移
- RenderScriptMigration 範例
- 內建函式替換工具包 README
- 內建函式替換工具包 Toolkit.kt