Use NetworkStatsService to get stats for apps

Move the native implementation of TrafficStats to NetworkStatsService
and apps need to get the NetworkStatsService binder interface from
system_server in order to get the network usage stats since boot. This
implementation can hide the detail of retrieving network traffic
information from apps and the NetworkStatsService can choose which
methoed it use to get the data depending on the kernel version of the
device.

Bug: 30950746
Test: CtsNetTestCases -t android.net.cts.TrafficStatsTest
Change-Id: I53bbefd19aa0b783b9b4b42ea4d76db3e9ec07a3
This commit is contained in:
Chenbo Feng
2017-11-14 17:54:17 -08:00
parent cd534c6990
commit aa7ba31c8e
4 changed files with 146 additions and 25 deletions

View File

@@ -67,4 +67,13 @@ interface INetworkStatsService {
/** Unregisters a callback on data usage. */ /** Unregisters a callback on data usage. */
void unregisterUsageRequest(in DataUsageRequest request); void unregisterUsageRequest(in DataUsageRequest request);
/** Get the uid stats information since boot */
long getUidStats(int uid, int type);
/** Get the iface stats information since boot */
long getIfaceStats(String iface, int type);
/** Get the total network stats information since boot */
long getTotalStats(int type);
} }

View File

@@ -505,7 +505,12 @@ public class TrafficStats {
public static long getMobileTcpRxPackets() { public static long getMobileTcpRxPackets() {
long total = 0; long total = 0;
for (String iface : getMobileIfaces()) { for (String iface : getMobileIfaces()) {
final long stat = nativeGetIfaceStat(iface, TYPE_TCP_RX_PACKETS); long stat = UNSUPPORTED;
try {
stat = getStatsService().getIfaceStats(iface, TYPE_TCP_RX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if (stat != UNSUPPORTED) { if (stat != UNSUPPORTED) {
total += stat; total += stat;
} }
@@ -517,7 +522,12 @@ public class TrafficStats {
public static long getMobileTcpTxPackets() { public static long getMobileTcpTxPackets() {
long total = 0; long total = 0;
for (String iface : getMobileIfaces()) { for (String iface : getMobileIfaces()) {
final long stat = nativeGetIfaceStat(iface, TYPE_TCP_TX_PACKETS); long stat = UNSUPPORTED;
try {
stat = getStatsService().getIfaceStats(iface, TYPE_TCP_TX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
if (stat != UNSUPPORTED) { if (stat != UNSUPPORTED) {
total += stat; total += stat;
} }
@@ -527,46 +537,78 @@ public class TrafficStats {
/** {@hide} */ /** {@hide} */
public static long getTxPackets(String iface) { public static long getTxPackets(String iface) {
return nativeGetIfaceStat(iface, TYPE_TX_PACKETS); try {
return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** {@hide} */ /** {@hide} */
public static long getRxPackets(String iface) { public static long getRxPackets(String iface) {
return nativeGetIfaceStat(iface, TYPE_RX_PACKETS); try {
return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** {@hide} */ /** {@hide} */
public static long getTxBytes(String iface) { public static long getTxBytes(String iface) {
return nativeGetIfaceStat(iface, TYPE_TX_BYTES); try {
return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** {@hide} */ /** {@hide} */
public static long getRxBytes(String iface) { public static long getRxBytes(String iface) {
return nativeGetIfaceStat(iface, TYPE_RX_BYTES); try {
return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** {@hide} */ /** {@hide} */
@TestApi @TestApi
public static long getLoopbackTxPackets() { public static long getLoopbackTxPackets() {
return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_PACKETS); try {
return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** {@hide} */ /** {@hide} */
@TestApi @TestApi
public static long getLoopbackRxPackets() { public static long getLoopbackRxPackets() {
return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_PACKETS); try {
return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** {@hide} */ /** {@hide} */
@TestApi @TestApi
public static long getLoopbackTxBytes() { public static long getLoopbackTxBytes() {
return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_BYTES); try {
return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_BYTES);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** {@hide} */ /** {@hide} */
@TestApi @TestApi
public static long getLoopbackRxBytes() { public static long getLoopbackRxBytes() {
return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_BYTES); try {
return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_BYTES);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** /**
@@ -579,7 +621,11 @@ public class TrafficStats {
* return {@link #UNSUPPORTED} on devices where statistics aren't available. * return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/ */
public static long getTotalTxPackets() { public static long getTotalTxPackets() {
return nativeGetTotalStat(TYPE_TX_PACKETS); try {
return getStatsService().getTotalStats(TYPE_TX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** /**
@@ -592,7 +638,11 @@ public class TrafficStats {
* return {@link #UNSUPPORTED} on devices where statistics aren't available. * return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/ */
public static long getTotalRxPackets() { public static long getTotalRxPackets() {
return nativeGetTotalStat(TYPE_RX_PACKETS); try {
return getStatsService().getTotalStats(TYPE_RX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** /**
@@ -605,7 +655,11 @@ public class TrafficStats {
* return {@link #UNSUPPORTED} on devices where statistics aren't available. * return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/ */
public static long getTotalTxBytes() { public static long getTotalTxBytes() {
return nativeGetTotalStat(TYPE_TX_BYTES); try {
return getStatsService().getTotalStats(TYPE_TX_BYTES);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** /**
@@ -618,7 +672,11 @@ public class TrafficStats {
* return {@link #UNSUPPORTED} on devices where statistics aren't available. * return {@link #UNSUPPORTED} on devices where statistics aren't available.
*/ */
public static long getTotalRxBytes() { public static long getTotalRxBytes() {
return nativeGetTotalStat(TYPE_RX_BYTES); try {
return getStatsService().getTotalStats(TYPE_RX_BYTES);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} }
/** /**
@@ -644,7 +702,11 @@ public class TrafficStats {
// unsupported value. The real filtering is done at the kernel level. // unsupported value. The real filtering is done at the kernel level.
final int callingUid = android.os.Process.myUid(); final int callingUid = android.os.Process.myUid();
if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
return nativeGetUidStat(uid, TYPE_TX_BYTES); try {
return getStatsService().getUidStats(uid, TYPE_TX_BYTES);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else { } else {
return UNSUPPORTED; return UNSUPPORTED;
} }
@@ -673,7 +735,11 @@ public class TrafficStats {
// unsupported value. The real filtering is done at the kernel level. // unsupported value. The real filtering is done at the kernel level.
final int callingUid = android.os.Process.myUid(); final int callingUid = android.os.Process.myUid();
if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
return nativeGetUidStat(uid, TYPE_RX_BYTES); try {
return getStatsService().getUidStats(uid, TYPE_RX_BYTES);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else { } else {
return UNSUPPORTED; return UNSUPPORTED;
} }
@@ -702,7 +768,11 @@ public class TrafficStats {
// unsupported value. The real filtering is done at the kernel level. // unsupported value. The real filtering is done at the kernel level.
final int callingUid = android.os.Process.myUid(); final int callingUid = android.os.Process.myUid();
if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
return nativeGetUidStat(uid, TYPE_TX_PACKETS); try {
return getStatsService().getUidStats(uid, TYPE_TX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else { } else {
return UNSUPPORTED; return UNSUPPORTED;
} }
@@ -731,7 +801,11 @@ public class TrafficStats {
// unsupported value. The real filtering is done at the kernel level. // unsupported value. The real filtering is done at the kernel level.
final int callingUid = android.os.Process.myUid(); final int callingUid = android.os.Process.myUid();
if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
return nativeGetUidStat(uid, TYPE_RX_PACKETS); try {
return getStatsService().getUidStats(uid, TYPE_RX_PACKETS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else { } else {
return UNSUPPORTED; return UNSUPPORTED;
} }
@@ -859,8 +933,4 @@ public class TrafficStats {
private static final int TYPE_TX_PACKETS = 3; private static final int TYPE_TX_PACKETS = 3;
private static final int TYPE_TCP_RX_PACKETS = 4; private static final int TYPE_TCP_RX_PACKETS = 4;
private static final int TYPE_TCP_TX_PACKETS = 5; private static final int TYPE_TCP_TX_PACKETS = 5;
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);
} }

View File

@@ -873,6 +873,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
} }
} }
@Override
public long getUidStats(int uid, int type) {
return nativeGetUidStat(uid, type);
}
@Override
public long getIfaceStats(String iface, int type) {
return nativeGetIfaceStat(iface, type);
}
@Override
public long getTotalStats(int type) {
return nativeGetTotalStat(type);
}
/** /**
* Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
* reflect current {@link #mPersistThreshold} value. Always defers to * reflect current {@link #mPersistThreshold} value. Always defers to
@@ -1626,4 +1641,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return getGlobalLong(NETSTATS_UID_TAG_PERSIST_BYTES, def); return getGlobalLong(NETSTATS_UID_TAG_PERSIST_BYTES, def);
} }
} }
private static int TYPE_RX_BYTES;
private static int TYPE_RX_PACKETS;
private static int TYPE_TX_BYTES;
private static int TYPE_TX_PACKETS;
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);
} }

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
#define LOG_TAG "TrafficStats" #define LOG_TAG "NetworkStatsNative"
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
@@ -191,8 +191,24 @@ static const JNINativeMethod gMethods[] = {
{"nativeGetUidStat", "(II)J", (void*) getUidStat}, {"nativeGetUidStat", "(II)J", (void*) getUidStat},
}; };
int register_android_net_TrafficStats(JNIEnv* env) { int register_android_server_net_NetworkStatsService(JNIEnv* env) {
return RegisterMethodsOrDie(env, "android/net/TrafficStats", gMethods, NELEM(gMethods)); jclass netStatsService = env->FindClass("com/android/server/net/NetworkStatsService");
jfieldID rxBytesId = env->GetStaticFieldID(netStatsService, "TYPE_RX_BYTES", "I");
jfieldID rxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_RX_PACKETS", "I");
jfieldID txBytesId = env->GetStaticFieldID(netStatsService, "TYPE_TX_BYTES", "I");
jfieldID txPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TX_PACKETS", "I");
jfieldID tcpRxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_RX_PACKETS", "I");
jfieldID tcpTxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_TX_PACKETS", "I");
env->SetStaticIntField(netStatsService, rxBytesId, RX_BYTES);
env->SetStaticIntField(netStatsService, rxPacketsId, RX_PACKETS);
env->SetStaticIntField(netStatsService, txBytesId, TX_BYTES);
env->SetStaticIntField(netStatsService, txPacketsId, TX_PACKETS);
env->SetStaticIntField(netStatsService, tcpRxPacketsId, TCP_RX_PACKETS);
env->SetStaticIntField(netStatsService, tcpTxPacketsId, TCP_TX_PACKETS);
return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods,
NELEM(gMethods));
} }
} }