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 ではなく eBPF ベースのネットワーク トラフィック モニタリング アカウンティングを使用する必要があります。新しいインフラストラクチャは柔軟性とメンテナンス性が高く、ツリー外のカーネルコードを必要としません。
以前のトラフィック モニタリングと 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 にアタッチします。すべてのトラフィックに 1 つのルート 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=yCONFIG_BPF=yCONFIG_BPF_SYSCALL=yCONFIG_NETFILTER_XT_MATCH_BPF=yCONFIG_INET_UDP_DIAG=y
VTS カーネル構成テストは、正しい構成が有効になっていることを確認する際に有用です。
以前の xt_qtaguid のサポート終了プロセス
新しい eBPF ツールは、xt_qtaguid モジュールとベースになっている xt_owner モジュールに代わるものです。まず、Android カーネルから xt_qtaguid モジュールを削除し、必要のない構成を無効にします。
Android 9 リリースでは、xt_qtaguid モジュールがすべてのデバイスでオンになりますが、xt_qtaguid モジュール proc ファイルを読み取るすべての公開 API が NetworkManagement Service に移行されます。NetworkManagement Service は、デバイスのカーネル バージョンと初期 API レベルに応じて eBPF ツールがオンになっているかどうかを把握し、アプリのネットワーク使用状況の統計情報ごとに適切なモジュールを選択します。SDK レベル 28 以上のアプリは、sepolicy によって xt_qtaguid proc ファイルに対するアクセスがブロックされます。
Android 9 より後のリリースでは、このような xt_qtaguid proc ファイルに対するアプリからのアクセスが完全にブロックされ、新しい Android 共通カーネルから xt_qtaguid モジュールが削除されます。削除後は、そのカーネル バージョン用の Android ベース構成が更新され、xt_qtaguid モジュールは明示的にオフになります。xt_qtaguid モジュールは、Android リリースの最小カーネル バージョン要件が 4.9 以上に達した段階で、完全にサポートを終了します。
Android 9 リリースでは、Android 9 リリースを搭載するデバイスのみが新しい eBPF 機能を必要とします。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 テストはありません。ただし、元々 Android 9 リリース(すなわち初期 API レベルが 28 以上)が搭載された、カーネル バージョン 4.9 以降のデバイスの場合、新しいモジュールが正しく構成されていることを確認する CTS テストが GSI にあります。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/+/main/tests/tests/net/src/android/net/cts/TrafficStatsTest.java
- https://android.googlesource.com/platform/cts/+/main/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
- https://android.googlesource.com/platform/system/netd/+/main/tests/bpf_base_test.cpp
VTS テストは https://android.googlesource.com/kernel/tests/+/main/net/test/bpf_test.py にあります。
単体テストは次の場所にあります。