From 2dc99dc44545a6ee25436818c0c435cf561ce11f Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Wed, 18 Apr 2018 15:44:46 -0700 Subject: [PATCH] Use eBPF map data for per iface stats After adding the xt_bpf module and ifaceStatsMap, eBPF tool can now support reading per interface data. So networkStatsFactory should move away from parsing proc/net/dev and use the eBPF map stats instead. Bug: 72111305 Test: atest com.android.server.net.NetworkStatsServiceTest Change-Id: Ibcc6150d00835b3bd33af22a72e4a86e172581cf --- .../internal/net/NetworkStatsFactory.java | 19 ++++- ...droid_internal_net_NetworkStatsFactory.cpp | 81 +++++++++++-------- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 8561bf0279..814b811e64 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -176,6 +176,14 @@ public class NetworkStatsFactory { return stats; } + public NetworkStats readBpfNetworkStatsDev() throws IOException { + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); + if (nativeReadNetworkStatsDev(stats) != 0) { + throw new IOException("Failed to parse bpf iface stats"); + } + return stats; + } + /** * Parse and return interface-level summary {@link NetworkStats} measured * using {@code /proc/net/dev} style hooks, which may include non IP layer @@ -186,9 +194,9 @@ public class NetworkStatsFactory { */ public NetworkStats readNetworkStatsSummaryDev() throws IOException { - // Return the stats get from /proc/net/dev if switched to bpf module. + // Return xt_bpf stats if switched to bpf module. if (mUseBpfStats) - return readNetworkStatsIfaceDev(); + return readBpfNetworkStatsDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); @@ -242,9 +250,9 @@ public class NetworkStatsFactory { */ public NetworkStats readNetworkStatsSummaryXt() throws IOException { - // Return the stats get from /proc/net/dev if qtaguid module is replaced. + // Return xt_bpf stats if qtaguid module is replaced. if (mUseBpfStats) - return readNetworkStatsIfaceDev(); + return readBpfNetworkStatsDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); @@ -406,4 +414,7 @@ public class NetworkStatsFactory { @VisibleForTesting public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats); + + @VisibleForTesting + public static native int nativeReadNetworkStatsDev(NetworkStats stats); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 99d9839570..c15b7ee4fe 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -205,37 +205,8 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, return 0; } -static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, - jint limitUid, jobjectArray limitIfacesObj, jint limitTag, - jboolean useBpfStats) { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - return -1; - } - - std::vector limitIfaces; - if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { - int num = env->GetArrayLength(limitIfacesObj); - for (int i = 0; i < num; i++) { - jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); - ScopedUtfChars string8(env, string); - if (string8.c_str() != NULL) { - limitIfaces.push_back(std::string(string8.c_str())); - } - } - } - std::vector lines; - - - if (useBpfStats) { - if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) - return -1; - } else { - if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, - limitUid, path8.c_str()) < 0) - return -1; - } - +static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats, + std::vector& lines) { int size = lines.size(); bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity); @@ -308,14 +279,58 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray()); } - return 0; } +static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, + jint limitUid, jobjectArray limitIfacesObj, jint limitTag, + jboolean useBpfStats) { + ScopedUtfChars path8(env, path); + if (path8.c_str() == NULL) { + return -1; + } + + std::vector limitIfaces; + if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { + int num = env->GetArrayLength(limitIfacesObj); + for (int i = 0; i < num; i++) { + jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); + ScopedUtfChars string8(env, string); + if (string8.c_str() != NULL) { + limitIfaces.push_back(std::string(string8.c_str())); + } + } + } + std::vector lines; + + + if (useBpfStats) { + if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) + return -1; + } else { + if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, + limitUid, path8.c_str()) < 0) + return -1; + } + + return statsLinesToNetworkStats(env, clazz, stats, lines); +} + +static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) { + std::vector lines; + + if (parseBpfNetworkStatsDev(&lines) < 0) + return -1; + + return statsLinesToNetworkStats(env, clazz, stats, lines); +} + static const JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I", - (void*) readNetworkStatsDetail } + (void*) readNetworkStatsDetail }, + { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I", + (void*) readNetworkStatsDev }, }; int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {