Loading core/java/com/android/internal/net/NetworkStatsFactory.java +63 −5 Original line number Diff line number Diff line Loading @@ -31,13 +31,17 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; import com.google.android.collect.Lists; import libcore.io.IoUtils; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.net.ProtocolException; import java.util.ArrayList; import java.util.Objects; /** Loading @@ -55,6 +59,8 @@ public class NetworkStatsFactory { // Used for correct stats accounting on clatd interfaces. private static final int IPV4V6_HEADER_DELTA = 20; /** Path to {@code /proc/net/dev}. */ private final File mStatsIfaceDev; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ Loading @@ -62,6 +68,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<String, String> sStackedIfaces = new ArrayMap<>(); Loading @@ -77,14 +85,54 @@ 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) { mStatsIfaceDev = new File(procRoot, "net/dev"); 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; } @VisibleForTesting public NetworkStats readNetworkStatsIfaceDev() throws IOException { final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); final NetworkStats.Entry entry = new NetworkStats.Entry(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(mStatsIfaceDev)); // skip first two header lines reader.readLine(); reader.readLine(); // parse remaining lines String line; while ((line = reader.readLine()) != null) { String[] values = line.trim().split("\\:?\\s+"); entry.iface = values[0]; entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; entry.rxBytes = Long.parseLong(values[1]); entry.rxPackets = Long.parseLong(values[2]); entry.txBytes = Long.parseLong(values[9]); entry.txPackets = Long.parseLong(values[10]); stats.addValues(entry); } } catch (NullPointerException|NumberFormatException e) { throw new ProtocolException("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); } return stats; } /** Loading @@ -96,6 +144,11 @@ public class NetworkStatsFactory { * @throws IllegalStateException when problem parsing stats. */ public NetworkStats readNetworkStatsSummaryDev() throws IOException { // Return the stats get from /proc/net/dev if switched to bpf module. if (mUseBpfStats) return readNetworkStatsIfaceDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); Loading Loading @@ -147,6 +200,11 @@ public class NetworkStatsFactory { * @throws IllegalStateException when problem parsing stats. */ public NetworkStats readNetworkStatsSummaryXt() throws IOException { // Return the stats get from /proc/net/dev if qtaguid module is replaced. if (mUseBpfStats) return readNetworkStatsIfaceDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); // return null when kernel doesn't support Loading Loading @@ -252,7 +310,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) { Loading Loading @@ -346,6 +404,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); } core/jni/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -215,6 +215,8 @@ cc_library_shared { ], shared_libs: [ "libbpf", "libnetdutils", "libmemtrack", "libandroidfw", "libappfuse", Loading core/jni/com_android_internal_net_NetworkStatsFactory.cpp +48 −37 Original line number Diff line number Diff line Loading @@ -30,7 +30,14 @@ #include <utils/Log.h> #include <utils/misc.h> #include <utils/Vector.h> #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 { Loading @@ -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) { Loading Loading @@ -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<stats_line>* lines, const std::vector<std::string>& limitIfaces, int limitTag, int limitUid, const char* path) { FILE* fp = fopen(path, "r"); if (fp == NULL) { return -1; } Vector<String8> limitIfaces; if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { int num = env->GetArrayLength(limitIfacesObj); limitIfaces.setCapacity(num); for (int i=0; i<num; i++) { jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); ScopedUtfChars string8(env, string); if (string8.c_str() != NULL) { limitIfaces.add(String8(string8.c_str())); } } } Vector<stats_line> lines; int lastIdx = 1; int idx; char buffer[384]; Loading Loading @@ -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); } Loading @@ -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<std::string> 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<stats_line> 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<jobjectArray> iface(env, get_string_array(env, stats, Loading Loading @@ -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 } }; Loading core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); } } } services/core/java/com/android/server/net/NetworkStatsService.java +10 −6 Original line number Diff line number Diff line Loading @@ -887,17 +887,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getUidStats(int uid, int type) { return nativeGetUidStat(uid, type); return nativeGetUidStat(uid, type, checkBpfStatsEnable()); } @Override public long getIfaceStats(String iface, int type) { return nativeGetIfaceStat(iface, type); return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); } @Override public long getTotalStats(int type) { return nativeGetTotalStat(type); return nativeGetTotalStat(type, checkBpfStatsEnable()); } private boolean checkBpfStatsEnable() { return new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); } /** Loading Loading @@ -1668,7 +1672,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static int TYPE_TCP_RX_PACKETS; private static int TYPE_TCP_TX_PACKETS; private static native long nativeGetTotalStat(int type); private static native long nativeGetIfaceStat(String iface, int type); private static native long nativeGetUidStat(int uid, int type); private static native long nativeGetTotalStat(int type, boolean useBpfStats); private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats); private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats); } Loading
core/java/com/android/internal/net/NetworkStatsFactory.java +63 −5 Original line number Diff line number Diff line Loading @@ -31,13 +31,17 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; import com.google.android.collect.Lists; import libcore.io.IoUtils; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.net.ProtocolException; import java.util.ArrayList; import java.util.Objects; /** Loading @@ -55,6 +59,8 @@ public class NetworkStatsFactory { // Used for correct stats accounting on clatd interfaces. private static final int IPV4V6_HEADER_DELTA = 20; /** Path to {@code /proc/net/dev}. */ private final File mStatsIfaceDev; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ Loading @@ -62,6 +68,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<String, String> sStackedIfaces = new ArrayMap<>(); Loading @@ -77,14 +85,54 @@ 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) { mStatsIfaceDev = new File(procRoot, "net/dev"); 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; } @VisibleForTesting public NetworkStats readNetworkStatsIfaceDev() throws IOException { final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); final NetworkStats.Entry entry = new NetworkStats.Entry(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(mStatsIfaceDev)); // skip first two header lines reader.readLine(); reader.readLine(); // parse remaining lines String line; while ((line = reader.readLine()) != null) { String[] values = line.trim().split("\\:?\\s+"); entry.iface = values[0]; entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; entry.rxBytes = Long.parseLong(values[1]); entry.rxPackets = Long.parseLong(values[2]); entry.txBytes = Long.parseLong(values[9]); entry.txPackets = Long.parseLong(values[10]); stats.addValues(entry); } } catch (NullPointerException|NumberFormatException e) { throw new ProtocolException("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); } return stats; } /** Loading @@ -96,6 +144,11 @@ public class NetworkStatsFactory { * @throws IllegalStateException when problem parsing stats. */ public NetworkStats readNetworkStatsSummaryDev() throws IOException { // Return the stats get from /proc/net/dev if switched to bpf module. if (mUseBpfStats) return readNetworkStatsIfaceDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); Loading Loading @@ -147,6 +200,11 @@ public class NetworkStatsFactory { * @throws IllegalStateException when problem parsing stats. */ public NetworkStats readNetworkStatsSummaryXt() throws IOException { // Return the stats get from /proc/net/dev if qtaguid module is replaced. if (mUseBpfStats) return readNetworkStatsIfaceDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); // return null when kernel doesn't support Loading Loading @@ -252,7 +310,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) { Loading Loading @@ -346,6 +404,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); }
core/jni/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -215,6 +215,8 @@ cc_library_shared { ], shared_libs: [ "libbpf", "libnetdutils", "libmemtrack", "libandroidfw", "libappfuse", Loading
core/jni/com_android_internal_net_NetworkStatsFactory.cpp +48 −37 Original line number Diff line number Diff line Loading @@ -30,7 +30,14 @@ #include <utils/Log.h> #include <utils/misc.h> #include <utils/Vector.h> #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 { Loading @@ -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) { Loading Loading @@ -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<stats_line>* lines, const std::vector<std::string>& limitIfaces, int limitTag, int limitUid, const char* path) { FILE* fp = fopen(path, "r"); if (fp == NULL) { return -1; } Vector<String8> limitIfaces; if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { int num = env->GetArrayLength(limitIfacesObj); limitIfaces.setCapacity(num); for (int i=0; i<num; i++) { jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); ScopedUtfChars string8(env, string); if (string8.c_str() != NULL) { limitIfaces.add(String8(string8.c_str())); } } } Vector<stats_line> lines; int lastIdx = 1; int idx; char buffer[384]; Loading Loading @@ -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); } Loading @@ -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<std::string> 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<stats_line> 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<jobjectArray> iface(env, get_string_array(env, stats, Loading Loading @@ -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 } }; Loading
core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); } } }
services/core/java/com/android/server/net/NetworkStatsService.java +10 −6 Original line number Diff line number Diff line Loading @@ -887,17 +887,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getUidStats(int uid, int type) { return nativeGetUidStat(uid, type); return nativeGetUidStat(uid, type, checkBpfStatsEnable()); } @Override public long getIfaceStats(String iface, int type) { return nativeGetIfaceStat(iface, type); return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); } @Override public long getTotalStats(int type) { return nativeGetTotalStat(type); return nativeGetTotalStat(type, checkBpfStatsEnable()); } private boolean checkBpfStatsEnable() { return new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); } /** Loading Loading @@ -1668,7 +1672,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static int TYPE_TCP_RX_PACKETS; private static int TYPE_TCP_TX_PACKETS; private static native long nativeGetTotalStat(int type); private static native long nativeGetIfaceStat(String iface, int type); private static native long nativeGetUidStat(int uid, int type); private static native long nativeGetTotalStat(int type, boolean useBpfStats); private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats); private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats); }