Merge "Add method to NetworkStatsService for UID stats."
am: db89ca3c12
Change-Id: I2c6cba3ebbc8c23ade754cfd411ac54a561b020a
This commit is contained in:
@@ -44,6 +44,16 @@ interface INetworkStatsService {
|
||||
|
||||
/** Return data layer snapshot of UID network usage. */
|
||||
NetworkStats getDataLayerSnapshotForUid(int uid);
|
||||
|
||||
/** Get a detailed snapshot of stats since boot for all UIDs.
|
||||
*
|
||||
* <p>Results will not always be limited to stats on requiredIfaces when specified: stats for
|
||||
* interfaces stacked on the specified interfaces, or for interfaces on which the specified
|
||||
* interfaces are stacked on, will also be included.
|
||||
* @param requiredIfaces Interface names to get data for, or {@link NetworkStats#INTERFACES_ALL}.
|
||||
*/
|
||||
NetworkStats getDetailedUidStats(in String[] requiredIfaces);
|
||||
|
||||
/** Return set of any ifaces associated with mobile networks since boot. */
|
||||
String[] getMobileIfaces();
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ public class NetworkStats implements Parcelable {
|
||||
/** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
|
||||
public static final int SET_DBG_VPN_OUT = 1002;
|
||||
|
||||
/** Include all interfaces when filtering */
|
||||
public static final String[] INTERFACES_ALL = null;
|
||||
|
||||
/** {@link #tag} value for total data across all tags. */
|
||||
// TODO: Rename TAG_NONE to TAG_ALL.
|
||||
public static final int TAG_NONE = 0;
|
||||
@@ -359,23 +362,27 @@ public class NetworkStats implements Parcelable {
|
||||
capacity = newLength;
|
||||
}
|
||||
|
||||
iface[size] = entry.iface;
|
||||
uid[size] = entry.uid;
|
||||
set[size] = entry.set;
|
||||
tag[size] = entry.tag;
|
||||
metered[size] = entry.metered;
|
||||
roaming[size] = entry.roaming;
|
||||
defaultNetwork[size] = entry.defaultNetwork;
|
||||
rxBytes[size] = entry.rxBytes;
|
||||
rxPackets[size] = entry.rxPackets;
|
||||
txBytes[size] = entry.txBytes;
|
||||
txPackets[size] = entry.txPackets;
|
||||
operations[size] = entry.operations;
|
||||
setValues(size, entry);
|
||||
size++;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void setValues(int i, Entry entry) {
|
||||
iface[i] = entry.iface;
|
||||
uid[i] = entry.uid;
|
||||
set[i] = entry.set;
|
||||
tag[i] = entry.tag;
|
||||
metered[i] = entry.metered;
|
||||
roaming[i] = entry.roaming;
|
||||
defaultNetwork[i] = entry.defaultNetwork;
|
||||
rxBytes[i] = entry.rxBytes;
|
||||
rxPackets[i] = entry.rxPackets;
|
||||
txBytes[i] = entry.txBytes;
|
||||
txPackets[i] = entry.txPackets;
|
||||
operations[i] = entry.operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return specific stats entry.
|
||||
*/
|
||||
@@ -824,6 +831,39 @@ public class NetworkStats implements Parcelable {
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only keep entries that match all specified filters.
|
||||
*
|
||||
* <p>This mutates the original structure in place. After this method is called,
|
||||
* size is the number of matching entries, and capacity is the previous capacity.
|
||||
* @param limitUid UID to filter for, or {@link #UID_ALL}.
|
||||
* @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}.
|
||||
* @param limitTag Tag to filter for, or {@link #TAG_ALL}.
|
||||
*/
|
||||
public void filter(int limitUid, String[] limitIfaces, int limitTag) {
|
||||
if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entry entry = new Entry();
|
||||
int nextOutputEntry = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
entry = getValues(i, entry);
|
||||
final boolean matches =
|
||||
(limitUid == UID_ALL || limitUid == entry.uid)
|
||||
&& (limitTag == TAG_ALL || limitTag == entry.tag)
|
||||
&& (limitIfaces == INTERFACES_ALL
|
||||
|| ArrayUtils.contains(limitIfaces, entry.iface));
|
||||
|
||||
if (matches) {
|
||||
setValues(nextOutputEntry, entry);
|
||||
nextOutputEntry++;
|
||||
}
|
||||
}
|
||||
|
||||
size = nextOutputEntry;
|
||||
}
|
||||
|
||||
public void dump(String prefix, PrintWriter pw) {
|
||||
pw.print(prefix);
|
||||
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
|
||||
|
||||
@@ -268,10 +268,12 @@ interface INetworkManagementService
|
||||
NetworkStats getNetworkStatsDetail();
|
||||
|
||||
/**
|
||||
* Return detailed network statistics for the requested UID,
|
||||
* Return detailed network statistics for the requested UID and interfaces,
|
||||
* including interface and tag details.
|
||||
* @param uid UID to obtain statistics for, or {@link NetworkStats#UID_ALL}.
|
||||
* @param ifaces Interfaces to obtain statistics for, or {@link NetworkStats#INTERFACES_ALL}.
|
||||
*/
|
||||
NetworkStats getNetworkStatsUidDetail(int uid);
|
||||
NetworkStats getNetworkStatsUidDetail(int uid, in String[] ifaces);
|
||||
|
||||
/**
|
||||
* Return summary of network statistics all tethering interfaces.
|
||||
|
||||
@@ -22,16 +22,14 @@ import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.NetworkStats;
|
||||
import android.os.StrictMode;
|
||||
import android.os.SystemClock;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
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;
|
||||
|
||||
@@ -41,8 +39,10 @@ import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Creates {@link NetworkStats} instances by parsing various {@code /proc/}
|
||||
@@ -70,18 +70,55 @@ public class NetworkStatsFactory {
|
||||
|
||||
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<>();
|
||||
// TODO: only do adjustments in NetworkStatsService and remove this.
|
||||
/**
|
||||
* (Stacked interface) -> (base interface) association for all connected ifaces since boot.
|
||||
*
|
||||
* Because counters must never roll backwards, once a given interface is stacked on top of an
|
||||
* underlying interface, the stacked interface can never be stacked on top of
|
||||
* another interface. */
|
||||
private static final ConcurrentHashMap<String, String> sStackedIfaces
|
||||
= new ConcurrentHashMap<>();
|
||||
|
||||
public static void noteStackedIface(String stackedIface, String baseIface) {
|
||||
synchronized (sStackedIfaces) {
|
||||
if (baseIface != null) {
|
||||
sStackedIfaces.put(stackedIface, baseIface);
|
||||
} else {
|
||||
sStackedIfaces.remove(stackedIface);
|
||||
if (stackedIface != null && baseIface != null) {
|
||||
sStackedIfaces.put(stackedIface, baseIface);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of interfaces containing specified ifaces and stacked interfaces.
|
||||
*
|
||||
* <p>The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces
|
||||
* on which the specified ones are stacked. Stacked interfaces are those noted with
|
||||
* {@link #noteStackedIface(String, String)}, but only interfaces noted before this method
|
||||
* is called are guaranteed to be included.
|
||||
*/
|
||||
public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) {
|
||||
if (requiredIfaces == NetworkStats.INTERFACES_ALL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<String> relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces));
|
||||
// ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse
|
||||
// elements as they existed upon construction exactly once, and may
|
||||
// (but are not guaranteed to) reflect any modifications subsequent to construction".
|
||||
// This is enough here.
|
||||
for (Map.Entry<String, String> entry : sStackedIfaces.entrySet()) {
|
||||
if (relatedIfaces.contains(entry.getKey())) {
|
||||
relatedIfaces.add(entry.getValue());
|
||||
} else if (relatedIfaces.contains(entry.getValue())) {
|
||||
relatedIfaces.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
String[] outArray = new String[relatedIfaces.size()];
|
||||
return relatedIfaces.toArray(outArray);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void clearStackedIfaces() {
|
||||
sStackedIfaces.clear();
|
||||
}
|
||||
|
||||
public NetworkStatsFactory() {
|
||||
@@ -250,12 +287,9 @@ public class NetworkStatsFactory {
|
||||
NetworkStats lastStats) throws IOException {
|
||||
final NetworkStats stats =
|
||||
readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats);
|
||||
final ArrayMap<String, String> stackedIfaces;
|
||||
synchronized (sStackedIfaces) {
|
||||
stackedIfaces = new ArrayMap<>(sStackedIfaces);
|
||||
}
|
||||
// Total 464xlat traffic to subtract from uid 0 on all base interfaces.
|
||||
final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size());
|
||||
// sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically.
|
||||
final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size());
|
||||
|
||||
NetworkStats.Entry entry = null; // For recycling
|
||||
|
||||
@@ -269,7 +303,7 @@ public class NetworkStatsFactory {
|
||||
if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
|
||||
continue;
|
||||
}
|
||||
final String baseIface = stackedIfaces.get(entry.iface);
|
||||
final String baseIface = sStackedIfaces.get(entry.iface);
|
||||
if (baseIface == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -5268,7 +5268,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
|
||||
final String stackedIface = stacked.getInterfaceName();
|
||||
bs.noteNetworkInterfaceType(stackedIface, type);
|
||||
NetworkStatsFactory.noteStackedIface(stackedIface, baseIface);
|
||||
}
|
||||
} catch (RemoteException ignored) {
|
||||
}
|
||||
|
||||
@@ -1867,10 +1867,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkStats getNetworkStatsUidDetail(int uid) {
|
||||
public NetworkStats getNetworkStatsUidDetail(int uid, String[] ifaces) {
|
||||
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
||||
try {
|
||||
return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
|
||||
return mStatsFactory.readNetworkStatsDetail(uid, ifaces, TAG_ALL, null);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
|
||||
import static android.net.ConnectivityManager.isNetworkTypeMobile;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
|
||||
import static android.net.NetworkStats.IFACE_ALL;
|
||||
import static android.net.NetworkStats.INTERFACES_ALL;
|
||||
import static android.net.NetworkStats.METERED_ALL;
|
||||
import static android.net.NetworkStats.ROAMING_ALL;
|
||||
import static android.net.NetworkStats.SET_ALL;
|
||||
@@ -34,6 +35,7 @@ import static android.net.NetworkStats.SET_DEFAULT;
|
||||
import static android.net.NetworkStats.SET_FOREGROUND;
|
||||
import static android.net.NetworkStats.STATS_PER_IFACE;
|
||||
import static android.net.NetworkStats.STATS_PER_UID;
|
||||
import static android.net.NetworkStats.TAG_ALL;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static android.net.NetworkStatsHistory.FIELD_ALL;
|
||||
@@ -128,6 +130,7 @@ import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.net.NetworkStatsFactory;
|
||||
import com.android.internal.net.VpnInfo;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
@@ -143,6 +146,7 @@ import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Collect and persist detailed network statistics, and provide this data to
|
||||
@@ -726,7 +730,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
final NetworkStats networkLayer;
|
||||
try {
|
||||
networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid);
|
||||
networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid,
|
||||
NetworkStats.INTERFACES_ALL);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -747,6 +752,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
return dataLayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkStats getDetailedUidStats(String[] requiredIfaces) {
|
||||
try {
|
||||
final String[] ifacesToQuery =
|
||||
NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces);
|
||||
return getNetworkStatsUidDetail(ifacesToQuery);
|
||||
} catch (RemoteException e) {
|
||||
Log.wtf(TAG, "Error compiling UID stats", e);
|
||||
return new NetworkStats(0L, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getMobileIfaces() {
|
||||
return mMobileIfaces;
|
||||
@@ -1109,6 +1126,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
if (isMobile) {
|
||||
mobileIfaces.add(stackedIface);
|
||||
}
|
||||
|
||||
NetworkStatsFactory.noteStackedIface(stackedIface, baseIface);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1130,7 +1149,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
private void recordSnapshotLocked(long currentTime) throws RemoteException {
|
||||
// snapshot and record current counters; read UID stats first to
|
||||
// avoid over counting dev stats.
|
||||
final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
|
||||
final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL);
|
||||
final NetworkStats xtSnapshot = getNetworkStatsXt();
|
||||
final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev();
|
||||
|
||||
@@ -1464,12 +1483,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
* Return snapshot of current UID statistics, including any
|
||||
* {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations}
|
||||
* values.
|
||||
*
|
||||
* @param ifaces A list of interfaces the stats should be restricted to, or
|
||||
* {@link NetworkStats#INTERFACES_ALL}.
|
||||
*/
|
||||
private NetworkStats getNetworkStatsUidDetail() throws RemoteException {
|
||||
final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
|
||||
private NetworkStats getNetworkStatsUidDetail(String[] ifaces)
|
||||
throws RemoteException {
|
||||
|
||||
final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL,
|
||||
ifaces);
|
||||
|
||||
// fold tethering stats and operations into uid snapshot
|
||||
final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID);
|
||||
tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL);
|
||||
uidSnapshot.combineAllValues(tetherSnapshot);
|
||||
|
||||
final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
|
||||
@@ -1478,10 +1504,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||
// fold video calling data usage stats into uid snapshot
|
||||
final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID);
|
||||
if (vtStats != null) {
|
||||
vtStats.filter(UID_ALL, ifaces, TAG_ALL);
|
||||
uidSnapshot.combineAllValues(vtStats);
|
||||
}
|
||||
|
||||
uidSnapshot.combineAllValues(mUidOperations);
|
||||
|
||||
// TODO: apply tethering & VC 464xlat adjustments here
|
||||
|
||||
return uidSnapshot;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.net;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
|
||||
import static android.net.NetworkStats.INTERFACES_ALL;
|
||||
import static android.net.NetworkStats.METERED_ALL;
|
||||
import static android.net.NetworkStats.METERED_NO;
|
||||
import static android.net.NetworkStats.METERED_YES;
|
||||
@@ -31,6 +32,7 @@ import static android.net.NetworkStats.SET_DBG_VPN_IN;
|
||||
import static android.net.NetworkStats.SET_DBG_VPN_OUT;
|
||||
import static android.net.NetworkStats.SET_ALL;
|
||||
import static android.net.NetworkStats.IFACE_ALL;
|
||||
import static android.net.NetworkStats.TAG_ALL;
|
||||
import static android.net.NetworkStats.TAG_NONE;
|
||||
import static android.net.NetworkStats.UID_ALL;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -641,6 +643,136 @@ public class NetworkStatsTest {
|
||||
ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter_NoFilter() {
|
||||
NetworkStats.Entry entry1 = new NetworkStats.Entry(
|
||||
"test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry2 = new NetworkStats.Entry(
|
||||
"test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry3 = new NetworkStats.Entry(
|
||||
"test2", 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats stats = new NetworkStats(TEST_START, 3)
|
||||
.addValues(entry1)
|
||||
.addValues(entry2)
|
||||
.addValues(entry3);
|
||||
|
||||
stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL);
|
||||
assertEquals(3, stats.size());
|
||||
assertEquals(entry1, stats.getValues(0, null));
|
||||
assertEquals(entry2, stats.getValues(1, null));
|
||||
assertEquals(entry3, stats.getValues(2, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter_UidFilter() {
|
||||
final int testUid = 10101;
|
||||
NetworkStats.Entry entry1 = new NetworkStats.Entry(
|
||||
"test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry2 = new NetworkStats.Entry(
|
||||
"test2", testUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry3 = new NetworkStats.Entry(
|
||||
"test2", testUid, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats stats = new NetworkStats(TEST_START, 3)
|
||||
.addValues(entry1)
|
||||
.addValues(entry2)
|
||||
.addValues(entry3);
|
||||
|
||||
stats.filter(testUid, INTERFACES_ALL, TAG_ALL);
|
||||
assertEquals(2, stats.size());
|
||||
assertEquals(entry2, stats.getValues(0, null));
|
||||
assertEquals(entry3, stats.getValues(1, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter_InterfaceFilter() {
|
||||
final String testIf1 = "testif1";
|
||||
final String testIf2 = "testif2";
|
||||
NetworkStats.Entry entry1 = new NetworkStats.Entry(
|
||||
testIf1, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry2 = new NetworkStats.Entry(
|
||||
"otherif", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry3 = new NetworkStats.Entry(
|
||||
testIf1, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry4 = new NetworkStats.Entry(
|
||||
testIf2, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats stats = new NetworkStats(TEST_START, 4)
|
||||
.addValues(entry1)
|
||||
.addValues(entry2)
|
||||
.addValues(entry3)
|
||||
.addValues(entry4);
|
||||
|
||||
stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL);
|
||||
assertEquals(3, stats.size());
|
||||
assertEquals(entry1, stats.getValues(0, null));
|
||||
assertEquals(entry3, stats.getValues(1, null));
|
||||
assertEquals(entry4, stats.getValues(2, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter_EmptyInterfaceFilter() {
|
||||
NetworkStats.Entry entry1 = new NetworkStats.Entry(
|
||||
"if1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry2 = new NetworkStats.Entry(
|
||||
"if2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats stats = new NetworkStats(TEST_START, 3)
|
||||
.addValues(entry1)
|
||||
.addValues(entry2);
|
||||
|
||||
stats.filter(UID_ALL, new String[] { }, TAG_ALL);
|
||||
assertEquals(0, stats.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter_TagFilter() {
|
||||
final int testTag = 123;
|
||||
final int otherTag = 456;
|
||||
NetworkStats.Entry entry1 = new NetworkStats.Entry(
|
||||
"test1", 10100, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry2 = new NetworkStats.Entry(
|
||||
"test2", 10101, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats.Entry entry3 = new NetworkStats.Entry(
|
||||
"test2", 10101, SET_DEFAULT, otherTag, METERED_NO, ROAMING_NO,
|
||||
DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
|
||||
|
||||
NetworkStats stats = new NetworkStats(TEST_START, 3)
|
||||
.addValues(entry1)
|
||||
.addValues(entry2)
|
||||
.addValues(entry3);
|
||||
|
||||
stats.filter(UID_ALL, INTERFACES_ALL, testTag);
|
||||
assertEquals(2, stats.size());
|
||||
assertEquals(entry1, stats.getValues(0, null));
|
||||
assertEquals(entry2, stats.getValues(1, null));
|
||||
}
|
||||
|
||||
private static void assertContains(NetworkStats stats, String iface, int uid, int set,
|
||||
int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
|
||||
long txBytes, long txPackets, long operations) {
|
||||
|
||||
@@ -184,7 +184,7 @@ public class NetworkStatsFactoryTest {
|
||||
assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L);
|
||||
assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L);
|
||||
|
||||
NetworkStatsFactory.noteStackedIface("v4-wlan0", null);
|
||||
NetworkStatsFactory.clearStackedIfaces();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -212,7 +212,7 @@ public class NetworkStatsFactoryTest {
|
||||
assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
|
||||
assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 647587L);
|
||||
|
||||
NetworkStatsFactory.noteStackedIface("v4-wlan0", null);
|
||||
NetworkStatsFactory.clearStackedIfaces();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,7 @@ import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
|
||||
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
|
||||
import static android.net.NetworkStats.IFACE_ALL;
|
||||
import static android.net.NetworkStats.INTERFACES_ALL;
|
||||
import static android.net.NetworkStats.METERED_ALL;
|
||||
import static android.net.NetworkStats.METERED_NO;
|
||||
import static android.net.NetworkStats.METERED_YES;
|
||||
@@ -58,6 +59,9 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -95,6 +99,7 @@ import android.util.Log;
|
||||
import android.util.TrustedTime;
|
||||
|
||||
import com.android.internal.net.VpnInfo;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.test.BroadcastInterceptingContext;
|
||||
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
|
||||
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
|
||||
@@ -667,6 +672,94 @@ public class NetworkStatsServiceTest {
|
||||
DEFAULT_NETWORK_YES, 1024L, 8L, 512L, 4L, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetailedUidStats() throws Exception {
|
||||
// pretend that network comes online
|
||||
expectDefaultSettings();
|
||||
expectNetworkState(buildWifiState());
|
||||
expectNetworkStatsSummary(buildEmptyStats());
|
||||
expectNetworkStatsUidDetail(buildEmptyStats());
|
||||
expectBandwidthControlCheck();
|
||||
|
||||
mService.forceUpdateIfaces(NETWORKS_WIFI);
|
||||
|
||||
NetworkStats.Entry entry1 = new NetworkStats.Entry(
|
||||
TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
|
||||
NetworkStats.Entry entry2 = new NetworkStats.Entry(
|
||||
TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 50L, 5L, 50L, 5L, 0L);
|
||||
NetworkStats.Entry entry3 = new NetworkStats.Entry(
|
||||
TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, 1024L, 8L, 512L, 4L, 0L);
|
||||
|
||||
incrementCurrentTime(HOUR_IN_MILLIS);
|
||||
expectDefaultSettings();
|
||||
expectNetworkStatsSummary(buildEmptyStats());
|
||||
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
|
||||
.addValues(entry1)
|
||||
.addValues(entry2)
|
||||
.addValues(entry3));
|
||||
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
|
||||
|
||||
NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL);
|
||||
|
||||
assertEquals(3, stats.size());
|
||||
entry1.operations = 1;
|
||||
assertEquals(entry1, stats.getValues(0, null));
|
||||
entry2.operations = 1;
|
||||
assertEquals(entry2, stats.getValues(1, null));
|
||||
assertEquals(entry3, stats.getValues(2, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetailedUidStats_Filtered() throws Exception {
|
||||
// pretend that network comes online
|
||||
expectDefaultSettings();
|
||||
|
||||
final String stackedIface = "stacked-test0";
|
||||
final LinkProperties stackedProp = new LinkProperties();
|
||||
stackedProp.setInterfaceName(stackedIface);
|
||||
final NetworkState wifiState = buildWifiState();
|
||||
wifiState.linkProperties.addStackedLink(stackedProp);
|
||||
expectNetworkState(wifiState);
|
||||
|
||||
expectNetworkStatsSummary(buildEmptyStats());
|
||||
expectNetworkStatsUidDetail(buildEmptyStats());
|
||||
expectBandwidthControlCheck();
|
||||
|
||||
mService.forceUpdateIfaces(NETWORKS_WIFI);
|
||||
|
||||
NetworkStats.Entry uidStats = new NetworkStats.Entry(
|
||||
TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
|
||||
// Stacked on matching interface
|
||||
NetworkStats.Entry tetheredStats1 = new NetworkStats.Entry(
|
||||
stackedIface, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
|
||||
// Different interface
|
||||
NetworkStats.Entry tetheredStats2 = new NetworkStats.Entry(
|
||||
"otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
|
||||
|
||||
final String[] ifaceFilter = new String[] { TEST_IFACE };
|
||||
incrementCurrentTime(HOUR_IN_MILLIS);
|
||||
expectDefaultSettings();
|
||||
expectNetworkStatsSummary(buildEmptyStats());
|
||||
when(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL), any()))
|
||||
.thenReturn(new NetworkStats(getElapsedRealtime(), 1)
|
||||
.addValues(uidStats));
|
||||
when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
|
||||
.thenReturn(new NetworkStats(getElapsedRealtime(), 2)
|
||||
.addValues(tetheredStats1)
|
||||
.addValues(tetheredStats2));
|
||||
|
||||
NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
|
||||
|
||||
verify(mNetManager, times(1)).getNetworkStatsUidDetail(eq(UID_ALL), argThat(ifaces ->
|
||||
ifaces != null && ifaces.length == 2
|
||||
&& ArrayUtils.contains(ifaces, TEST_IFACE)
|
||||
&& ArrayUtils.contains(ifaces, stackedIface)));
|
||||
|
||||
assertEquals(2, stats.size());
|
||||
assertEquals(uidStats, stats.getValues(0, null));
|
||||
assertEquals(tetheredStats1, stats.getValues(1, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForegroundBackground() throws Exception {
|
||||
// pretend that network comes online
|
||||
@@ -1056,7 +1149,7 @@ public class NetworkStatsServiceTest {
|
||||
|
||||
private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats)
|
||||
throws Exception {
|
||||
when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail);
|
||||
when(mNetManager.getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL)).thenReturn(detail);
|
||||
|
||||
// also include tethering details, since they are folded into UID
|
||||
when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);
|
||||
|
||||
Reference in New Issue
Block a user