為了提高設備安全性,Android 7.0 將單一的mediaserver
進程分解為多個進程,其權限和功能僅限於每個進程所需的權限和功能。這些更改通過以下方式緩解媒體框架安全漏洞:
- 將 AV 管道組件拆分為特定於應用程序的沙盒進程。
- 啟用可更新的媒體組件(提取器、編解碼器等)。
這些更改還通過顯著降低大多數與媒體相關的安全漏洞的嚴重性、保持最終用戶設備和數據的安全來提高最終用戶的安全性。
OEM 和 SoC 供應商需要更新其 HAL 和框架更改,以使其與新架構兼容。具體來說,由於供應商提供的 Android 代碼通常假定所有內容都在同一進程中運行,因此供應商必須更新其代碼以傳遞跨進程有意義的本機句柄 ( native_handle
)。有關與媒體強化相關的更改的參考實現,請參閱frameworks/av
和frameworks/native
。
架構變化
以前的 Android 版本使用具有大量權限(攝像頭訪問、音頻訪問、視頻驅動程序訪問、文件訪問、網絡訪問等)的單一、單一的mediaserver
進程。 Android 7.0 將mediaserver
進程拆分為幾個新進程,每個進程需要的權限要少得多:
這種新架構確保即使進程受到破壞,惡意代碼也無法訪問以前由 mediaserver 持有的完整權限集。進程受 SElinux 和 seccomp 策略的限制。
注意:由於供應商依賴性,一些編解碼器仍然在mediaserver
中運行,因此授予mediaserver
比必要更多的權限。具體來說, mediaserver
Classic 繼續在適用於 Android 7.0 的媒體服務器中運行。
媒體服務器更改
在 Android 7.0 中, mediaserver
進程用於驅動播放和錄製,例如在組件和進程之間傳遞和同步緩衝區。進程通過標準的 Binder 機制進行通信。
在標準的本地文件播放會話中,應用程序將文件描述符 (FD) 傳遞給mediaserver
(通常通過 MediaPlayer Java API),然後mediaserver
:
- 將 FD 包裝到一個 Binder DataSource 對像中,該對像傳遞給提取器進程,該進程使用它使用 Binder IPC 從文件中讀取。 (mediaextractor 沒有獲取 FD,而是讓 Binder 回調到
mediaserver
以獲取數據。) - 檢查文件,為文件類型(例如 MP3Extractor 或 MPEG4Extractor)創建適當的提取器,並將提取器的 Binder 接口返回給
mediaserver
進程。 - 使 Binder IPC 調用提取器以確定文件中數據的類型(例如 MP3 或 H.264 數據)。
- 調用
mediacodec
進程以創建所需類型的編解碼器;接收這些編解碼器的 Binder 接口。 - 重複 Binder IPC 調用提取器讀取編碼樣本,使用 Binder IPC 將編碼數據發送到
mediacodec
進程進行解碼,並接收解碼數據。
在某些用例中,不涉及編解碼器(例如卸載播放,其中編碼數據直接發送到輸出設備),或者編解碼器可以直接渲染解碼數據而不是返回解碼數據的緩衝區(視頻播放)。
MediaCodecService 更改
編解碼器服務是編碼器和解碼器所在的位置。由於供應商依賴性,並非所有編解碼器都存在於編解碼器進程中。在 Android 7.0 中:
- 非安全解碼器和軟件編碼器存在於編解碼器過程中。
- 安全解碼器和硬件編碼器位於
mediaserver
中(未更改)。
應用程序(或媒體服務器)調用編解碼器進程以創建所需類型的編解碼器,然後調用該編解碼器以傳入編碼數據並檢索解碼數據(用於解碼)或傳入解碼數據並檢索編碼數據(用於編碼) .與編解碼器之間的數據傳輸已經使用共享內存,因此該過程保持不變。
MediaDrmServer 更改
DRM 服務器用於播放受 DRM 保護的內容,例如 Google Play 電影中的電影。它以安全的方式處理加密數據的解密,因此可以訪問證書和密鑰存儲以及其他敏感組件。由於供應商依賴性,DRM 流程尚未在所有情況下都使用。
音頻服務器更改
AudioServer 進程託管音頻相關組件,例如音頻輸入和輸出、確定音頻路由的策略管理器服務和 FM 廣播服務。有關音頻更改和實施指南的詳細信息,請參閱實施音頻。
相機服務器更改
CameraServer 控制攝像頭,用於在錄製視頻時從攝像頭獲取視頻幀,然後將它們傳遞給mediaserver
進行進一步處理。有關 CameraServer 更改的更改和實施指南的詳細信息,請參閱Camera Framework Hardening 。
ExtractorService 更改
提取器服務託管提取器、解析媒體框架支持的各種文件格式的組件。提取器服務是所有服務中權限最低的——它無法讀取 FD,因此它調用 Binder 接口(由mediaserver for
每個播放會話提供)來訪問文件。
應用程序(或mediaserver
)調用提取器進程以獲取IMediaExtractor
,調用該IMediaExtractor
以獲取文件中包含的軌道的IMediaSources
,然後調用IMediaSources
以從中讀取數據。
為了在進程之間傳輸數據,應用程序(或mediaserver
)將 reply-Parcel 中的數據包含在 Binder 事務中或使用共享內存:
- 使用共享內存需要額外的 Binder 調用來釋放共享內存,但對於大緩衝區來說速度更快且功耗更低。
- 使用in-Parcel需要額外的複制,但對於小於 64KB 的緩衝區,速度更快且功耗更低。
執行
為了支持將MediaDrm
和MediaCrypto
組件移動到新的mediadrmserver
進程中,供應商必須更改安全緩衝區的分配方法,以允許在進程之間共享緩衝區。
在之前的 Android 版本中,安全緩衝區由OMX::allocateBuffer
在mediaserver
中分配,並在同一進程中解密時使用,如下所示:
在 Android 7.0 中,緩衝區分配過程已更改為一種新機制,該機制提供了靈活性,同時將對現有實現的影響降至最低。在新的mediadrmserver
進程中使用MediaDrm
和MediaCrypto
堆棧,緩衝區的分配方式不同,供應商必須更新安全緩衝區句柄,以便在MediaCodec
調用MediaCrypto
上的解密操作時可以跨綁定器傳輸它們。
使用本機句柄
OMX::allocateBuffer
必須返回一個指向native_handle
結構的指針,該結構包含文件描述符 (FD) 和其他整數數據。 native_handle
具有使用 FD 的所有優點,包括現有的對序列化/反序列化的 binder 支持,同時為當前不使用 FD 的供應商提供更大的靈活性。
使用native_handle_create()
分配本機句柄。框架代碼擁有分配的native_handle
結構的所有權,並負責在native_handle
最初分配的進程和反序列化的進程中釋放資源。該框架使用native_handle_close()
和 native_handle_delete() 釋放本機句柄,並使用Parcel::writeNativeHandle()/readNativeHandle()
native_handle_delete()
化/反序列化native_handle
。
使用 FD 表示安全緩衝區的 SoC 供應商可以使用他們的 FD 填充native_handle
中的 FD。不使用 FD 的供應商可以使用native_buffer
中的附加字段來表示安全緩衝區。
設置解密位置
供應商必須更新在 native_handle 上運行的native_handle
解密方法,以執行使native_handle
在新進程空間中可用所需的任何供應商特定操作(更改通常包括對 OEMCrypto 庫的更新)。
由於allocateBuffer
是標準的 OMX 操作,Android 7.0 包含一個新的 OMX 擴展 ( OMX.google.android.index.allocateNativeHandle
) 來查詢此支持和一個OMX_SetParameter
調用,通知 OMX 實現它應該使用本機句柄。