service-t/jni/com_android_server_net_NetworkStats{Factory,Service}: improve jni

Note that we no longer need the (void*) casts, this is because:
  MAKE_JNI_NATIVE_METHOD() checks function args match
  MAKE_JNI_NATIVE_METHOD_AUTOSIG() autogenerates the signature

Additionally:
  nativeGetTotalStat()
  nativeGetIfaceStat()
  nativeGetUidStat()
should be faster now, by virtue of caching a bunch of calls.

This more-or-less mirrors what was already done in the other file.

Test: TreeHugger
Flag: EXEMPT mainline
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I5a715d15ca5c01b625b8b7a62bc0e10bc0cc213f
This commit is contained in:
Maciej Żenczykowski 2025-08-09 21:18:04 -07:00
commit 3e2a811ecf
2 changed files with 98 additions and 103 deletions

View file

@ -24,6 +24,7 @@
#include <jni.h>
#include <nativehelper/jni_macros.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedLocalRef.h>
@ -64,9 +65,7 @@ static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, i
{
if (!grow) {
jobjectArray array = (jobjectArray)env->GetObjectField(obj, field);
if (array != NULL) {
return array;
}
if (array) return array;
}
return env->NewObjectArray(size, gStringClass, NULL);
}
@ -75,9 +74,7 @@ static jintArray get_int_array(JNIEnv* env, jobject obj, jfieldID field, int siz
{
if (!grow) {
jintArray array = (jintArray)env->GetObjectField(obj, field);
if (array != NULL) {
return array;
}
if (array) return array;
}
return env->NewIntArray(size);
}
@ -86,9 +83,7 @@ static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int s
{
if (!grow) {
jlongArray array = (jlongArray)env->GetObjectField(obj, field);
if (array != NULL) {
return array;
}
if (array) return array;
}
return env->NewLongArray(size);
}
@ -101,40 +96,51 @@ static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
ScopedLocalRef<jobjectArray> iface(env, get_string_array(env, stats,
gNetworkStatsClassInfo.iface, size, grow));
if (iface.get() == NULL) return -1;
if (!iface.get()) return -1;
ScopedIntArrayRW uid(env, get_int_array(env, stats,
gNetworkStatsClassInfo.uid, size, grow));
if (uid.get() == NULL) return -1;
if (!uid.get()) return -1;
ScopedIntArrayRW set(env, get_int_array(env, stats,
gNetworkStatsClassInfo.set, size, grow));
if (set.get() == NULL) return -1;
if (!set.get()) return -1;
ScopedIntArrayRW tag(env, get_int_array(env, stats,
gNetworkStatsClassInfo.tag, size, grow));
if (tag.get() == NULL) return -1;
if (!tag.get()) return -1;
ScopedIntArrayRW metered(env, get_int_array(env, stats,
gNetworkStatsClassInfo.metered, size, grow));
if (metered.get() == NULL) return -1;
if (!metered.get()) return -1;
ScopedIntArrayRW roaming(env, get_int_array(env, stats,
gNetworkStatsClassInfo.roaming, size, grow));
if (roaming.get() == NULL) return -1;
if (!roaming.get()) return -1;
ScopedIntArrayRW defaultNetwork(env, get_int_array(env, stats,
gNetworkStatsClassInfo.defaultNetwork, size, grow));
if (defaultNetwork.get() == NULL) return -1;
if (!defaultNetwork.get()) return -1;
ScopedLongArrayRW rxBytes(env, get_long_array(env, stats,
gNetworkStatsClassInfo.rxBytes, size, grow));
if (rxBytes.get() == NULL) return -1;
if (!rxBytes.get()) return -1;
ScopedLongArrayRW rxPackets(env, get_long_array(env, stats,
gNetworkStatsClassInfo.rxPackets, size, grow));
if (rxPackets.get() == NULL) return -1;
if (!rxPackets.get()) return -1;
ScopedLongArrayRW txBytes(env, get_long_array(env, stats,
gNetworkStatsClassInfo.txBytes, size, grow));
if (txBytes.get() == NULL) return -1;
if (!txBytes.get()) return -1;
ScopedLongArrayRW txPackets(env, get_long_array(env, stats,
gNetworkStatsClassInfo.txPackets, size, grow));
if (txPackets.get() == NULL) return -1;
if (!txPackets.get()) return -1;
ScopedLongArrayRW operations(env, get_long_array(env, stats,
gNetworkStatsClassInfo.operations, size, grow));
if (operations.get() == NULL) return -1;
if (!operations.get()) return -1;
for (int i = 0; i < size; i++) {
ScopedLocalRef<jstring> ifaceString(env, env->NewStringUTF(lines[i].iface));
@ -173,8 +179,7 @@ static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats) {
std::vector<stats_line> lines;
if (parseBpfNetworkStatsDetail(&lines) < 0)
return -1;
if (parseBpfNetworkStatsDetail(&lines) < 0) return -1;
return statsLinesToNetworkStats(env, clazz, stats, lines);
}
@ -182,25 +187,26 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats) {
static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) {
std::vector<stats_line> lines;
if (parseBpfNetworkStatsDev(&lines) < 0)
return -1;
if (parseBpfNetworkStatsDev(&lines) < 0) return -1;
return statsLinesToNetworkStats(env, clazz, stats, lines);
}
static const JNINativeMethod gMethods[] = {
{ "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;)I",
(void*) readNetworkStatsDetail },
{ "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I",
(void*) readNetworkStatsDev },
MAKE_JNI_NATIVE_METHOD("nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;)I", readNetworkStatsDetail),
MAKE_JNI_NATIVE_METHOD("nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I", readNetworkStatsDev),
};
int register_android_server_net_NetworkStatsFactory(JNIEnv* env) {
int err = jniRegisterNativeMethods(env,
"android/net/connectivity/com/android/server/net/NetworkStatsFactory", gMethods,
NELEM(gMethods));
if (jniRegisterNativeMethods(env,
"android/net/connectivity/com/android/server/net/NetworkStatsFactory",
gMethods,
NELEM(gMethods))) abort();
gStringClass = env->FindClass("java/lang/String");
if (!gStringClass) abort();
gStringClass = static_cast<jclass>(env->NewGlobalRef(gStringClass));
if (!gStringClass) abort();
jclass clazz = env->FindClass("android/net/NetworkStats");
gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I");
@ -218,7 +224,7 @@ int register_android_server_net_NetworkStatsFactory(JNIEnv* env) {
gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J");
gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J");
return err;
return 0;
}
}

View file

@ -22,6 +22,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <jni.h>
#include <nativehelper/jni_macros.h>
#include <nativehelper/ScopedUtfChars.h>
#include <sys/stat.h>
#include <sys/types.h>
@ -39,73 +40,54 @@ using android::bpf::NetworkTraceHandler;
namespace android {
static struct {
jclass theClass;
jmethodID constructor;
jfieldID rxBytes;
jfieldID txBytes;
jfieldID rxPackets;
jfieldID txPackets;
} gNetworkStatsEntry;
static void nativeRegisterIface(JNIEnv* env, jclass clazz, jstring iface) {
ScopedUtfChars iface8(env, iface);
if (iface8.c_str() == nullptr) return;
if (!iface8.c_str()) return;
bpfRegisterIface(iface8.c_str());
}
static jobject statsValueToEntry(JNIEnv* env, StatsValue* stats) {
// Find the Java class that represents the structure
jclass gEntryClass = env->FindClass("android/net/NetworkStats$Entry");
if (gEntryClass == nullptr) {
return nullptr;
}
// Find the constructor.
jmethodID constructorID = env->GetMethodID(gEntryClass, "<init>", "()V");
if (constructorID == nullptr) {
return nullptr;
}
// Create a new instance of the Java class
jobject result = env->NewObject(gEntryClass, constructorID);
if (result == nullptr) {
return nullptr;
}
jobject result = env->NewObject(gNetworkStatsEntry.theClass, gNetworkStatsEntry.constructor);
if (!result) return nullptr;
// Set the values of the structure fields in the Java object
env->SetLongField(result, env->GetFieldID(gEntryClass, "rxBytes", "J"), stats->rxBytes);
env->SetLongField(result, env->GetFieldID(gEntryClass, "txBytes", "J"), stats->txBytes);
env->SetLongField(result, env->GetFieldID(gEntryClass, "rxPackets", "J"), stats->rxPackets);
env->SetLongField(result, env->GetFieldID(gEntryClass, "txPackets", "J"), stats->txPackets);
env->SetLongField(result, gNetworkStatsEntry.rxBytes, stats->rxBytes);
env->SetLongField(result, gNetworkStatsEntry.txBytes, stats->txBytes);
env->SetLongField(result, gNetworkStatsEntry.rxPackets, stats->rxPackets);
env->SetLongField(result, gNetworkStatsEntry.txPackets, stats->txPackets);
return result;
}
static jobject nativeGetTotalStat(JNIEnv* env, jclass clazz) {
StatsValue stats = {};
if (bpfGetIfaceStats(nullptr, &stats) == 0) {
return statsValueToEntry(env, &stats);
} else {
return nullptr;
}
if (bpfGetIfaceStats(nullptr, &stats)) return nullptr;
return statsValueToEntry(env, &stats);
}
static jobject nativeGetIfaceStat(JNIEnv* env, jclass clazz, jstring iface) {
ScopedUtfChars iface8(env, iface);
if (iface8.c_str() == nullptr) {
return nullptr;
}
if (!iface8.c_str()) return nullptr;
StatsValue stats = {};
if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
return statsValueToEntry(env, &stats);
} else {
return nullptr;
}
if (bpfGetIfaceStats(iface8.c_str(), &stats)) return nullptr;
return statsValueToEntry(env, &stats);
}
static jobject nativeGetUidStat(JNIEnv* env, jclass clazz, jint uid) {
StatsValue stats = {};
if (bpfGetUidStats(uid, &stats) == 0) {
return statsValueToEntry(env, &stats);
} else {
return nullptr;
}
if (bpfGetUidStats(uid, &stats)) return nullptr;
return statsValueToEntry(env, &stats);
}
static void nativeInitNetworkTracing(JNIEnv* env, jclass clazz) {
@ -113,37 +95,44 @@ static void nativeInitNetworkTracing(JNIEnv* env, jclass clazz) {
}
static const JNINativeMethod gMethods[] = {
{
"nativeRegisterIface",
"(Ljava/lang/String;)V",
(void*)nativeRegisterIface
},
{
"nativeGetTotalStat",
"()Landroid/net/NetworkStats$Entry;",
(void*)nativeGetTotalStat
},
{
"nativeGetIfaceStat",
"(Ljava/lang/String;)Landroid/net/NetworkStats$Entry;",
(void*)nativeGetIfaceStat
},
{
"nativeGetUidStat",
"(I)Landroid/net/NetworkStats$Entry;",
(void*)nativeGetUidStat
},
{
"nativeInitNetworkTracing",
"()V",
(void*)nativeInitNetworkTracing
},
MAKE_JNI_NATIVE_METHOD_AUTOSIG("nativeRegisterIface", nativeRegisterIface),
MAKE_JNI_NATIVE_METHOD("nativeGetTotalStat", "()Landroid/net/NetworkStats$Entry;", nativeGetTotalStat),
MAKE_JNI_NATIVE_METHOD("nativeGetIfaceStat", "(Ljava/lang/String;)Landroid/net/NetworkStats$Entry;", nativeGetIfaceStat),
MAKE_JNI_NATIVE_METHOD("nativeGetUidStat", "(I)Landroid/net/NetworkStats$Entry;", nativeGetUidStat),
MAKE_JNI_NATIVE_METHOD_AUTOSIG("nativeInitNetworkTracing", nativeInitNetworkTracing),
};
int register_android_server_net_NetworkStatsService(JNIEnv* env) {
return jniRegisterNativeMethods(env,
"android/net/connectivity/com/android/server/net/NetworkStatsService", gMethods,
NELEM(gMethods));
if (jniRegisterNativeMethods(env,
"android/net/connectivity/com/android/server/net/NetworkStatsService",
gMethods,
NELEM(gMethods))) abort();
// Find the Java class that represents the structure
jclass clazz = env->FindClass("android/net/NetworkStats$Entry");
if (!clazz) abort();
clazz = static_cast<jclass>(env->NewGlobalRef(clazz));
if (!clazz) abort();
gNetworkStatsEntry.theClass = clazz;
// Find the constructor.
gNetworkStatsEntry.constructor = env->GetMethodID(clazz, "<init>", "()V");
if (!gNetworkStatsEntry.constructor) abort();
// and the individual fields...
gNetworkStatsEntry.rxBytes = env->GetFieldID(clazz, "rxBytes", "J");
if (!gNetworkStatsEntry.rxBytes) abort();
gNetworkStatsEntry.txBytes = env->GetFieldID(clazz, "txBytes", "J");
if (!gNetworkStatsEntry.txBytes) abort();
gNetworkStatsEntry.rxPackets = env->GetFieldID(clazz, "rxPackets", "J");
if (!gNetworkStatsEntry.rxPackets) abort();
gNetworkStatsEntry.txPackets = env->GetFieldID(clazz, "txPackets", "J");
if (!gNetworkStatsEntry.txPackets) abort();
return 0;
}
}