Loading core/java/android/net/INetworkStatsService.aidl +10 −0 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,16 @@ interface INetworkStatsService { /** Return data layer snapshot of UID network usage. */ /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); 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. */ /** Return set of any ifaces associated with mobile networks since boot. */ String[] getMobileIfaces(); String[] getMobileIfaces(); Loading core/java/android/net/NetworkStats.java +52 −12 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,9 @@ public class NetworkStats implements Parcelable { /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ public static final int SET_DBG_VPN_OUT = 1002; 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. */ /** {@link #tag} value for total data across all tags. */ // TODO: Rename TAG_NONE to TAG_ALL. // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; public static final int TAG_NONE = 0; Loading Loading @@ -366,23 +369,27 @@ public class NetworkStats implements Parcelable { capacity = newLength; capacity = newLength; } } iface[size] = entry.iface; setValues(size, entry); 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; size++; size++; return this; 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. * Return specific stats entry. */ */ Loading Loading @@ -831,6 +838,39 @@ public class NetworkStats implements Parcelable { return stats; 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) { public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); Loading core/java/android/os/INetworkManagementService.aidl +4 −2 Original line number Original line Diff line number Diff line Loading @@ -268,10 +268,12 @@ interface INetworkManagementService NetworkStats getNetworkStatsDetail(); 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. * 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. * Return summary of network statistics all tethering interfaces. Loading core/java/com/android/internal/net/NetworkStatsFactory.java +53 −19 Original line number Original line Diff line number Diff line Loading @@ -22,16 +22,14 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; import android.net.NetworkStats; import android.net.NetworkStats; import android.os.StrictMode; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemClock; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; import com.android.internal.util.ProcFileReader; import com.google.android.collect.Lists; import libcore.io.IoUtils; import libcore.io.IoUtils; Loading @@ -41,8 +39,10 @@ import java.io.FileInputStream; import java.io.FileReader; import java.io.FileReader; import java.io.IOException; import java.io.IOException; import java.net.ProtocolException; import java.net.ProtocolException; import java.util.ArrayList; import java.util.Arrays; import java.util.Objects; import java.util.HashSet; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** /** * Creates {@link NetworkStats} instances by parsing various {@code /proc/} * Creates {@link NetworkStats} instances by parsing various {@code /proc/} Loading Loading @@ -72,18 +72,55 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; private boolean mUseBpfStats; // TODO: to improve testability and avoid global state, do not use a static variable. // TODO: only do adjustments in NetworkStatsService and remove this. @GuardedBy("sStackedIfaces") /** private static final ArrayMap<String, String> sStackedIfaces = new ArrayMap<>(); * (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) { public static void noteStackedIface(String stackedIface, String baseIface) { synchronized (sStackedIfaces) { if (stackedIface != null && baseIface != null) { if (baseIface != null) { sStackedIfaces.put(stackedIface, baseIface); sStackedIfaces.put(stackedIface, baseIface); } else { sStackedIfaces.remove(stackedIface); } } } } /** * 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() { public NetworkStatsFactory() { Loading Loading @@ -252,12 +289,9 @@ public class NetworkStatsFactory { NetworkStats lastStats) throws IOException { NetworkStats lastStats) throws IOException { final NetworkStats stats = final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); 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. // 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 NetworkStats.Entry entry = null; // For recycling Loading @@ -271,7 +305,7 @@ public class NetworkStatsFactory { if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { continue; continue; } } final String baseIface = stackedIfaces.get(entry.iface); final String baseIface = sStackedIfaces.get(entry.iface); if (baseIface == null) { if (baseIface == null) { continue; continue; } } Loading services/core/java/com/android/server/ConnectivityService.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -5314,7 +5314,6 @@ public class ConnectivityService extends IConnectivityManager.Stub for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) { for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) { final String stackedIface = stacked.getInterfaceName(); final String stackedIface = stacked.getInterfaceName(); bs.noteNetworkInterfaceType(stackedIface, type); bs.noteNetworkInterfaceType(stackedIface, type); NetworkStatsFactory.noteStackedIface(stackedIface, baseIface); } } } catch (RemoteException ignored) { } catch (RemoteException ignored) { } } Loading Loading
core/java/android/net/INetworkStatsService.aidl +10 −0 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,16 @@ interface INetworkStatsService { /** Return data layer snapshot of UID network usage. */ /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); 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. */ /** Return set of any ifaces associated with mobile networks since boot. */ String[] getMobileIfaces(); String[] getMobileIfaces(); Loading
core/java/android/net/NetworkStats.java +52 −12 Original line number Original line Diff line number Diff line Loading @@ -64,6 +64,9 @@ public class NetworkStats implements Parcelable { /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ public static final int SET_DBG_VPN_OUT = 1002; 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. */ /** {@link #tag} value for total data across all tags. */ // TODO: Rename TAG_NONE to TAG_ALL. // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; public static final int TAG_NONE = 0; Loading Loading @@ -366,23 +369,27 @@ public class NetworkStats implements Parcelable { capacity = newLength; capacity = newLength; } } iface[size] = entry.iface; setValues(size, entry); 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; size++; size++; return this; 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. * Return specific stats entry. */ */ Loading Loading @@ -831,6 +838,39 @@ public class NetworkStats implements Parcelable { return stats; 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) { public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); Loading
core/java/android/os/INetworkManagementService.aidl +4 −2 Original line number Original line Diff line number Diff line Loading @@ -268,10 +268,12 @@ interface INetworkManagementService NetworkStats getNetworkStatsDetail(); 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. * 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. * Return summary of network statistics all tethering interfaces. Loading
core/java/com/android/internal/net/NetworkStatsFactory.java +53 −19 Original line number Original line Diff line number Diff line Loading @@ -22,16 +22,14 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; import android.net.NetworkStats; import android.net.NetworkStats; import android.os.StrictMode; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemClock; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; import com.android.internal.util.ProcFileReader; import com.google.android.collect.Lists; import libcore.io.IoUtils; import libcore.io.IoUtils; Loading @@ -41,8 +39,10 @@ import java.io.FileInputStream; import java.io.FileReader; import java.io.FileReader; import java.io.IOException; import java.io.IOException; import java.net.ProtocolException; import java.net.ProtocolException; import java.util.ArrayList; import java.util.Arrays; import java.util.Objects; import java.util.HashSet; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** /** * Creates {@link NetworkStats} instances by parsing various {@code /proc/} * Creates {@link NetworkStats} instances by parsing various {@code /proc/} Loading Loading @@ -72,18 +72,55 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; private boolean mUseBpfStats; // TODO: to improve testability and avoid global state, do not use a static variable. // TODO: only do adjustments in NetworkStatsService and remove this. @GuardedBy("sStackedIfaces") /** private static final ArrayMap<String, String> sStackedIfaces = new ArrayMap<>(); * (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) { public static void noteStackedIface(String stackedIface, String baseIface) { synchronized (sStackedIfaces) { if (stackedIface != null && baseIface != null) { if (baseIface != null) { sStackedIfaces.put(stackedIface, baseIface); sStackedIfaces.put(stackedIface, baseIface); } else { sStackedIfaces.remove(stackedIface); } } } } /** * 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() { public NetworkStatsFactory() { Loading Loading @@ -252,12 +289,9 @@ public class NetworkStatsFactory { NetworkStats lastStats) throws IOException { NetworkStats lastStats) throws IOException { final NetworkStats stats = final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); 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. // 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 NetworkStats.Entry entry = null; // For recycling Loading @@ -271,7 +305,7 @@ public class NetworkStatsFactory { if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { continue; continue; } } final String baseIface = stackedIfaces.get(entry.iface); final String baseIface = sStackedIfaces.get(entry.iface); if (baseIface == null) { if (baseIface == null) { continue; continue; } } Loading
services/core/java/com/android/server/ConnectivityService.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -5314,7 +5314,6 @@ public class ConnectivityService extends IConnectivityManager.Stub for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) { for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) { final String stackedIface = stacked.getInterfaceName(); final String stackedIface = stacked.getInterfaceName(); bs.noteNetworkInterfaceType(stackedIface, type); bs.noteNetworkInterfaceType(stackedIface, type); NetworkStatsFactory.noteStackedIface(stackedIface, baseIface); } } } catch (RemoteException ignored) { } catch (RemoteException ignored) { } } Loading