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 カーネル構成テストは、正しい構成が有効になっていることを確認する際に有用です。
以前の 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 にあります。
単体テストは次の場所にあります。