eBPF トラフィック モニタリング

eBPF ネットワーク トラフィック ツールは、カーネルとユーザー空間の実装の組み合わせを使用して、直近のデバイス起動以降のデバイスにおけるネットワーク使用量を監視します。ソケットのタグ付け、フォアグラウンド / バックグラウンド トラフィックの分離、UID ごとのファイアウォールなどの追加機能を備え、スマートフォンのステータスに応じてアプリをネットワーク アクセスからブロックします。ツールから収集された統計情報は、eBPF maps というカーネルデータ構造に格納されます。NetworkStatsService などのサービスがこの結果を使用して、前回の起動以降の永続的なトラフィック統計情報を提供します。

例とソース

ユーザー空間の変更は主に system/netd プロジェクトと framework/base プロジェクトで行われます。開発は AOSP で行われているため、AOSP コードは常に最新のものになります。ソースは主に system/netd/server/TrafficController*system/netd/bpfloadersystem/netd/libbpf/ にあります。 一部の必要なフレームワークの変更は framework/base/system/core にもあります。

実装

Android 9 以降、カーネル 4.9 以上で動作し元々 P リリースで出荷された Android デバイスは、xt_qtaguid ではなく eBPF ベースのネットワーク トラフィック モニタリング アカウンティングを使用する必要があります。新しいインフラストラクチャは柔軟性とメンテナンス性が高く、ツリー外のカーネルコードを必要としません。

以前のトラフィック モニタリングと eBPF トラフィック モニタリングの設計上の主な違いを図 1 に示します。

以前のトラフィック モニタリングと eBPF トラフィック モニタリングの設計上の違い

図 1. 以前のトラフィック モニタリング(左)と eBPF トラフィック モニタリング(右)の設計上の違い

新しい trafficController 設計は、cgroup ごとの eBPF フィルタと、カーネル内部の xt_bpf netfilter モジュールに基づいています。これらの eBPF フィルタは、フィルタを通過するときにパケット tx/rx に適用されます。cgroup eBPF フィルタはトランスポート層にあり、ソケット UID とユーザー空間の設定に応じて、正しい UID に対するトラフィックをカウントします。xt_bpf netfilter は、bw_raw_PREROUTINGbw_mangle_POSTROUTING のチェーンでフックされ、正しいインターフェースに対するトラフィックをカウントします。

起動時に、ユーザー空間プロセス trafficController はデータ収集に使用する eBPF マップを作成し、sys/fs/bpf ですべてのマップを仮想ファイルとして固定します。次に、特権プロセス bpfloader は、プリコンパイルされた eBPF プログラムをカーネルに読み込んで、正しい cgroup にアタッチします。すべてのトラフィックに 1 つのルート cgroup が存在するため、デフォルトでは、すべてのプロセスをその cgroup に含める必要があります。

実行時に、trafficControllertraffic_cookie_tag_maptraffic_uid_counterSet_map に書き込むことでソケットのタグ付け / タグ解除を行うことができます。NetworkStatsService は、traffic_tag_stats_maptraffic_uid_stats_maptraffic_iface_stats_map からトラフィック統計データを読み取ることができます。トラフィック統計情報収集機能の他に、trafficControllercgroup の eBPF フィルタは、スマートフォンの設定に応じて特定の UID からのトラフィックをブロックします。UID ベースのネットワーキング トラフィックのブロック機能はカーネル内部の xt_owner モジュールの置き換えであり、詳細モードは、traffic_powersave_uid_maptraffic_standby_uid_maptraffic_dozable_uid_map に書き込むことで構成できます。

新しい実装は以前の xt_qtaguid モジュール実装に準拠しているため、TrafficControllerNetworkStatsService は以前の実装か新しい実装のいずれかで実行されます。アプリが公開 API を使用している場合は、バックグラウンドで xt_qtaguid ツールと eBPF ツールのいずれを使用しても違いは生じません。

デバイス カーネルが Android 共通カーネル 4.9(SHA 39c856663dcc81739e52b02b77d6af259eb838f6 以上)に基づいている場合、新しい eBPF ツールを実装するために、HAL、ドライバ、またはカーネルコードを変更する必要はありません。

要件

  1. カーネル設定では、次の設定を有効にしておく必要があります。

    1. CONFIG_CGROUP_BPF=y
    2. CONFIG_BPF=y
    3. CONFIG_BPF_SYSCALL=y
    4. CONFIG_NETFILTER_XT_MATCH_BPF=y
    5. 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_testlibbpf_test に合格していることを確認してください。

テスト

必要な機能が有効になっており、必要なカーネルパッチがバックポートされていることを確認する、カーネル net_tests があります。テストは、Android 9 リリース VTS テストの一部として統合されています。単体テストは、system/netd/netd_unit_testlibbpf_test)にあります。netd_integration_test には、新しいツールの全体的な動作を検証するためのテストがあります。

CTS と CTS 検証ツール

Android 9 リリースでは両方のトラフィック モニタリング モジュールがサポートされているため、新しいモジュールの実装をすべてのデバイスに強制する CTS テストはありません。ただし、元々 Android 9 リリース(すなわち初期 API レベルが 28 以上)が搭載された、カーネル バージョン 4.9 以降のデバイスの場合、新しいモジュールが正しく構成されていることを確認する CTS テストが GSI にあります。TrafficStatsTestNetworkUsageStatsTestCtsNativeNetTestCases などの古い CTS テストを使用して、古い UID モジュールとの動作の整合性を確認できます。

手動テスト

system/netd/ には、単体テストがあります(netd_unit_testnetd_integration_testlibbpf_test)。ステータスを手動で確認するための dumpsys サポートがあります。コマンド dumpsys netd は、trafficController モジュールの基本ステータスと、eBPF が正しくオンになっているかどうかを表示します。eBPF がオンの場合、コマンド dumpsys netd trafficcontroller は、タグ付きのソケット情報、タグごとの統計情報、UID と iface、所有者 UID の一致など、各 eBPF マップの詳細を表示します。

テストの場所

CTS テストは次の場所にあります。

VTS テストは https://android.googlesource.com/kernel/tests/+/main/net/test/bpf_test.py にあります。

単体テストは次の場所にあります。