eBPF ネットワーク トラフィック ツールは、カーネルとユーザー空間の実装の組み合わせを使用して、デバイスの最後の起動以降のデバイスのネットワーク使用状況を監視します。ソケットのタグ付け、フォアグラウンド/バックグラウンド トラフィックの分離、UID ごとのファイアウォールなどの追加機能を提供して、電話の状態に応じてネットワーク アクセスからアプリをブロックします。ツールから収集された統計は、 eBPF maps
と呼ばれるカーネル データ構造に保存され、その結果はNetworkStatsService
などのサービスによって使用され、最後の起動以降の永続的なトラフィック統計が提供されます。
例とソース
ユーザー空間の変更は、主にsystem/netd
およびframework/base
プロジェクトにあります。開発は AOSP で行われているため、AOSP コードは常に最新の状態になります。ソースは主にsystem/netd/server/TrafficController*
、 system/netd/bpfloader
、およびsystem/netd/libbpf/
にあります。必要なフレームワークの変更は、 framework/base/
とsystem/core
にもあります。
実装
Android 9 以降、カーネル 4.9 以降で実行され、元々 P リリースに同梱されていた Android デバイスは、 xt_qtaguid の代わりにxt_qtaguid
ベースのネットワーク トラフィック モニタリング アカウンティングを使用する必要があります。新しいインフラストラクチャは、より柔軟で保守しやすく、ツリー外のカーネル コードを必要としません。
レガシー トラフィック モニタリングと eBPF トラフィック モニタリングの主な設計上の違いを図 1 に示します。
図 1.レガシー (左) と eBPF (右) のトラフィック監視設計の違い
新しいtrafficController
の設計は、カーネル内のcgroup
eBPF フィルターとxt_bpf
netfilter モジュールに基づいています。これらの eBPF フィルターは、フィルターを通過するときにパケット tx/rx に適用されます。 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 カーネル構成テストは、正しい構成がオンになっていることを確認するときに役立ちます。
-
デバイスの
MEM_LOCK
rlimit は 8 MB 以上に設定する必要があります。
従来の xt_qtaguid 非推奨プロセス
新しい eBPF ツールは、 xt_qtaguid
モジュールとそのベースとなっているxt_owner
モジュールを置き換えます。 Android カーネルからxt_qtaguid
モジュールの削除を開始し、不要な構成を無効にします。
Android 9 リリースでは、 xt_qtaguid
モジュールがすべてのデバイスで有効になっていますが、 xt_qtaguid
モジュールの proc ファイルを直接読み取るすべてのパブリック API はNetworkManagement
Service に移動されています。デバイスのカーネル バージョンと最初の API レベルに応じて、 NetworkManagement
Service は eBPF ツールがオンになっているかどうかを認識し、各アプリのネットワーク使用統計情報を取得するための適切なモジュールを選択します。 SDK レベル 28 以降のアプリは、sepolicy によってxt_qtaguid
proc ファイルへのアクセスがブロックされます。
9 以降の次の Android リリースでは、これらのxt_qtaguid
proc ファイルへのアプリ アクセスは完全にブロックされ、新しい Android 共通カーネルからxt_qtaguid
モジュールの削除を開始します。削除後、そのカーネル バージョンの Android ベース構成を更新して、 xt_qtaguid
モジュールを明示的にオフにします。 Android リリースの最小カーネル バージョン要件が 4.9 以上の場合、 xt_qtaguid
モジュールは完全に非推奨になります。
Android 9 リリースでは、Android 9 リリースで起動するデバイスのみが新しい eBPF 機能を持つ必要があります。 eBPF ツールをサポートできるカーネルが付属しているデバイスの場合、Android 9 リリースにアップグレードするときに、新しい eBPF 機能に更新することをお勧めします。その更新を実施するための CTS テストはありません。
検証
Android 共通カーネルと Android AOSP マスターから定期的にパッチを適用する必要があります。実装が該当する 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 テストはありません。ただし、元々 Android 9 リリースに同梱されていたカーネル バージョン 4.9 以降のデバイス (つまり、最初の API レベル >= 28) の場合、GSI で CTS テストを実行して、新しいモジュールが正しく構成されていることを検証します。 TrafficStatsTest
、 NetworkUsageStatsTest
、 CtsNativeNetTestCases
などの古い CTS テストを使用して、動作が古い UID モジュールと一致していることを確認できます。
手動テスト
system/netd/
にはいくつかの単体テストがあります ( netd_unit_test
、 netd_integration_test
、およびlibbpf_test
)。ステータスを手動でチェックするための dumpsys サポートがあります。コマンドdumpsys netd
は、 trafficController
モジュールの基本ステータスと、eBPF が正しくオンになっているかどうかを示します。 eBPF がオンになっている場合、コマンドdumpsys netd trafficcontroller
は、タグ付きソケット情報、タグごとの統計、UID と iface、所有者 UID の一致など、各 eBPF マップの詳細な内容を表示します。
テスト場所
CTS テストは次の場所にあります。
- https://android.googlesource.com/platform/cts/+/master/tests/tests/net/src/android/net/cts/TrafficStatsTest.java {: .external}
- https://android.googlesource.com/platform/cts/+/master/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java {: .external}
- https://android.googlesource.com/platform/system/netd/+/master/tests/bpf_base_test.cpp {: .external}
VTS テストはhttps://android.googlesource.com/kernel/tests/+/master/net/test/bpf_test.pyにあります。
単体テストは次の場所にあります。