From 828f1b45fb302f68b5eb8934bf474177fa249c7c Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Mon, 20 Nov 2017 17:03:59 -0800 Subject: [PATCH] Add bpf support for NetworkStatsFactory Add the native method used to read the detail information of network stats from bpf maps. The native method of NetworkStatsFactory should choose the correct implementation to get the stats detail depending on the kernel version. Currently the bpf result is printed as a reference and the actual behavior of NetworkStatsFactory should not change. Test: NetworkStatsFactory related cts test should not fail. Bug: 30950746 Change-Id: I4715a23559b5b2306bd556cea0431f0ed172a993 --- .../internal/net/NetworkStatsFactory.java | 13 +-- core/jni/Android.bp | 2 + ...droid_internal_net_NetworkStatsFactory.cpp | 85 +++++++++++-------- .../net/NetworkStatsFactoryBenchmark.java | 2 +- .../internal/net/NetworkStatsFactoryTest.java | 2 +- 5 files changed, 60 insertions(+), 44 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index b576a20db53a2..47666b57e8fdd 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -62,6 +62,8 @@ public class NetworkStatsFactory { /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; + private boolean mUseBpfStats; + // TODO: to improve testability and avoid global state, do not use a static variable. @GuardedBy("sStackedIfaces") private static final ArrayMap sStackedIfaces = new ArrayMap<>(); @@ -77,14 +79,15 @@ public class NetworkStatsFactory { } public NetworkStatsFactory() { - this(new File("/proc/")); + this(new File("/proc/"), new File("/sys/fs/bpf/traffic_uid_stats_map").exists()); } @VisibleForTesting - public NetworkStatsFactory(File procRoot) { + public NetworkStatsFactory(File procRoot, boolean useBpfStats) { mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); + mUseBpfStats = useBpfStats; } /** @@ -252,7 +255,7 @@ public class NetworkStatsFactory { stats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, - limitIfaces, limitTag) != 0) { + limitIfaces, limitTag, mUseBpfStats) != 0) { throw new IOException("Failed to parse network stats"); } if (SANITY_CHECK_NATIVE) { @@ -346,6 +349,6 @@ public class NetworkStatsFactory { * are expected to monotonically increase since device boot. */ @VisibleForTesting - public static native int nativeReadNetworkStatsDetail( - NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag); + public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path, + int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats); } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index bc98716ebc9cb..b3fb43d586564 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -215,6 +215,8 @@ cc_library_shared { ], shared_libs: [ + "libbpf", + "libnetdutils", "libmemtrack", "libandroidfw", "libappfuse", diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index d254de65f7654..99d983957075a 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -30,7 +30,14 @@ #include #include -#include + +#include "android-base/unique_fd.h" +#include "bpf/BpfNetworkStats.h" +#include "bpf/BpfUtils.h" + +using android::bpf::hasBpfSupport; +using android::bpf::parseBpfNetworkStatsDetail; +using android::bpf::stats_line; namespace android { @@ -53,17 +60,6 @@ static struct { jfieldID operations; } gNetworkStatsClassInfo; -struct stats_line { - char iface[32]; - int32_t uid; - int32_t set; - int32_t tag; - int64_t rxBytes; - int64_t rxPackets; - int64_t txBytes; - int64_t txPackets; -}; - static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) { if (!grow) { @@ -97,33 +93,14 @@ static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int s return env->NewLongArray(size); } -static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, - jstring path, jint limitUid, jobjectArray limitIfacesObj, jint limitTag) { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - return -1; - } - - FILE *fp = fopen(path8.c_str(), "r"); +static int legacyReadNetworkStatsDetail(std::vector* lines, + const std::vector& limitIfaces, + int limitTag, int limitUid, const char* path) { + FILE* fp = fopen(path, "r"); if (fp == NULL) { return -1; } - Vector limitIfaces; - if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { - int num = env->GetArrayLength(limitIfacesObj); - limitIfaces.setCapacity(num); - for (int i=0; iGetObjectArrayElement(limitIfacesObj, i); - ScopedUtfChars string8(env, string); - if (string8.c_str() != NULL) { - limitIfaces.add(String8(string8.c_str())); - } - } - } - - Vector lines; - int lastIdx = 1; int idx; char buffer[384]; @@ -215,7 +192,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, //ALOGI("skipping due to uid: %s", buffer); continue; } - lines.push_back(s); + lines->push_back(s); } else { //ALOGI("skipping due to bad remaining fields: %s", pos); } @@ -225,8 +202,42 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ALOGE("Failed to close netstats file"); return -1; } + 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; + } int size = lines.size(); + bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity); ScopedLocalRef iface(env, get_string_array(env, stats, @@ -303,7 +314,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, static const JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", - "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I", + "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I", (void*) readNetworkStatsDetail } }; diff --git a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java b/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java index e62fbd6568f71..c2134649655a3 100644 --- a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java +++ b/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java @@ -53,7 +53,7 @@ public class NetworkStatsFactoryBenchmark { stats, mStats.getAbsolutePath(), NetworkStats.UID_ALL, // Looks like this was broken by change d0c5b9abed60b7bc056d026bf0f2b2235410fb70 // Fixed compilation problem but needs addressing properly. - new String[0], 999); + new String[0], 999, false); } } } diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java index 56b8e608dad18..b267cb53d3cad 100644 --- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java @@ -67,7 +67,7 @@ public class NetworkStatsFactoryTest { IoUtils.deleteContents(mTestProc); } - mFactory = new NetworkStatsFactory(mTestProc); + mFactory = new NetworkStatsFactory(mTestProc, false); } @After