eBPF 網路流量工具會結合核心和使用者空間實作項目,監控裝置自上次啟動以來的網路用量。這項功能提供額外功能,例如插座標記、區分前景/背景流量,以及根據手機狀態,透過每個 UID 的防火牆封鎖應用程式的網路存取權。工具收集的統計資料會儲存在名為 eBPF maps
的核心資料結構中,而 NetworkStatsService
等服務會使用這些結果,提供自上次啟動以來持續性的流量統計資料。
範例和來源
使用者空間的變更主要在 system/netd
和 framework/base
專案中。開發作業是在 Android 開放原始碼計畫中進行,因此 Android 開放原始碼計畫程式碼一律會保持最新狀態。來源主要位於
system/netd/server/TrafficController*
、
system/netd/bpfloader
和
system/netd/libbpf/
。
framework/base/
和 system/core
也進行了必要的架構變更。
實作
從 Android 9 開始,搭載核心 4.9 以上版本且原先隨附 P 版本的 Android 裝置,必須使用 eBPF 型網路流量監控會計系統,而非 xt_qtaguid
。新基礎架構更具彈性,也更容易維護,而且不需要任何樹外核心程式碼。
圖 1 說明舊版和 eBPF 流量監控之間的主要設計差異。
圖 1. 舊版 (左) 和 eBPF (右) 流量監控設計差異
新的 trafficController
設計是以每個 cgroup
eBPF 篩選器為基礎,以及核心內的 xt_bpf
netfilter 模組。這些 eBPF 篩選器會在封包通過篩選器時套用至封包傳輸/接收。cgroup
eBPF 篩選器位於傳輸層,負責根據通訊端 UID 和使用者空間設定,針對正確的 UID 計算流量。xt_bpf
netfilter 會在 bw_raw_PREROUTING
和 bw_mangle_POSTROUTING
鏈結中掛接,負責計算正確介面的流量。
在啟動時,使用者空間程序 trafficController
會建立用於資料收集的 eBPF 對應,並將所有對應固定為 sys/fs/bpf
的虛擬檔案。
接著,具備權限的程序 bpfloader
會將預先編譯的 eBPF 程式載入核心,並附加至正確的 cgroup
。所有流量都有單一根目錄 cgroup
,因此預設所有程序都應包含在該 cgroup
中。
在執行階段,trafficController
可以透過寫入 traffic_cookie_tag_map
和 traffic_uid_counterSet_map
來標記/取消標記通訊端。NetworkStatsService
可以讀取 traffic_tag_stats_map
、traffic_uid_stats_map
和 traffic_iface_stats_map
的流量統計資料。除了流量統計資料收集函式外,trafficController
和 cgroup
eBPF 篩選器也負責根據手機設定,封鎖來自特定 UID 的流量。以 UID 為基礎的網路流量封鎖功能,可取代核心內的 xt_owner
模組,並透過寫入 traffic_powersave_uid_map
、traffic_standby_uid_map
和 traffic_dozable_uid_map
來設定詳細模式。
新實作方式會遵循舊版 xt_qtaguid
模組實作方式,因此 TrafficController
和 NetworkStatsService
會使用舊版或新版實作方式執行。如果應用程式使用公開 API,無論背景使用 xt_qtaguid
或 eBPF 工具,都不應有任何差異。
如果裝置核心是以 Android 通用核心 4.9 (SHA 39c856663dcc81739e52b02b77d6af259eb838f6 以上版本) 為基礎,則實作新的 eBPF 工具時,不需要修改 HAL、驅動程式或核心程式碼。
需求條件
核心設定必須啟用下列設定:
CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_NETFILTER_XT_MATCH_BPF=y
CONFIG_INET_UDP_DIAG=y
VTS 核心設定測試有助於確認是否已啟用正確的設定。
舊版 xt_qtaguid 淘汰程序
新的 eBPF 工具將取代 xt_qtaguid
模組和以該模組為基礎的 xt_owner
模組。我們將開始從 Android 核心移除 xt_qtaguid
模組,並停用不必要的設定。
在 Android 9 版本中,所有裝置都會開啟 xt_qtaguid
模組,但直接讀取 xt_qtaguid
模組 proc 檔案的所有公開 API 都會移至 NetworkManagement
服務。NetworkManagement
服務會根據裝置核心版本和第一個 API 級別,判斷 eBPF 工具是否已開啟,並選擇正確的模組來取得每個應用程式的網路用量統計資料。SDK 級別 28 以上的應用程式會受到 sepolicy 阻擋,無法存取 xt_qtaguid
proc 檔案。
在 Android 9 之後的下一個版本中,應用程式將完全無法存取這些 xt_qtaguid
proc 檔案,我們也會開始從新的 Android 通用核心中移除 xt_qtaguid
模組。移除後,我們會更新該核心版本的 Android 基本設定,明確關閉 xt_qtaguid
模組。當 Android 版本的最低核心版本需求為 4.9 以上時,xt_qtaguid
模組將完全淘汰。
在 Android 9 版本中,只有隨 Android 9 版本推出的裝置才需要具備新的 eBPF 功能。如果裝置出廠時搭載的 Kernel 支援 eBPF 工具,建議您在升級至 Android 9 時,更新至新的 eBPF 功能。沒有 CTS 測試可強制執行這項更新。
驗證
您應定期從 Android 通用核心和 Android AOSP
main 取得修補程式。請確保導入作業通過適用的 VTS 和 CTS 測試、netd_unit_test
,以及 libbpf_test
。
測試
請使用核心 net_tests,確保已啟用必要功能,並回溯移植必要的核心修補程式。這些測試已整合為 Android 9 版本 VTS 測試的一部分。system/netd/
中有一些單元測試 (netd_unit_test
和 libbpf_test
)。netd_integration_test
中有一些測試,可驗證新工具的整體行為。
CTS 和 CTS 驗證器
由於 Android 9 版本支援這兩個流量監控模組,因此沒有 CTS 測試會強制在所有裝置上實作新模組。不過,如果裝置的 Kernel 版本高於 4.9,且原廠設定是搭載 Android 9 (也就是第一個 API 級別 >= 28),則 GSI 上會有 CTS 測試,可驗證新模組是否已正確設定。您可以透過舊版 CTS 測試 (例如 TrafficStatsTest
、NetworkUsageStatsTest
和 CtsNativeNetTestCases
) 驗證行為是否與舊版 UID 模組一致。
手動測試
system/netd/
中有一些單元測試 (netd_unit_test
、netd_integration_test
和 libbpf_test
)。您可以使用 dumpsys 手動檢查狀態。dumpsys netd
指令會顯示 trafficController
模組的基本狀態,以及 eBPF 是否已正確開啟。如果已開啟 eBPF,指令 dumpsys netd trafficcontroller
會顯示每個 eBPF 對應的詳細內容,包括已標記的通訊端資訊、每個標記的統計資料、UID 和介面,以及擁有者 UID 相符情形。
測試地點
CTS 測試位於:
- https://android.googlesource.com/platform/cts/+/android16-release/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
- https://android.googlesource.com/platform/cts/+/android16-release/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
- https://android.googlesource.com/platform/system/netd/+/android16-release/tests/bpf_base_test.cpp
VTS 測試位於 https://android.googlesource.com/kernel/tests/+/android16-release/net/test/bpf_test.py。
單元測試位於: