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=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 に移行されます。NetworkManagement
Service は、デバイスのカーネル バージョンと初期 API レベルに応じて eBPF ツールがオンになっているかどうかを把握し、アプリのネットワーク使用状況の統計情報ごとに適切なモジュールを選択します。SDK レベル 28 以上のアプリは、sepolicy によって xt_qtaguid
proc ファイルに対するアクセスがブロックされます。
9 以降の Android リリースでは、このような 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 マスターからパッチを定期的に取得する必要があります。実装が、該当する 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/+/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 にあります。
単体テストは次の場所にあります。