diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index f64bec73e4..3670b914ec 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -256,6 +256,15 @@ public final class NetworkStats implements AutoCloseable { return tag; } + private static @Metered int convertMetered(int metered) { + switch (metered) { + case android.net.NetworkStats.METERED_ALL : return METERED_ALL; + case android.net.NetworkStats.METERED_NO: return METERED_NO; + case android.net.NetworkStats.METERED_YES: return METERED_YES; + } + return 0; + } + private static @Roaming int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; @@ -530,8 +539,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - // TODO: Implement metered tracking. - bucketOut.mMetered = Bucket.METERED_ALL; + bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index e805fabc79..da5aa61f1f 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -52,16 +52,17 @@ import android.util.Log; * {@link #querySummaryForUser}

* {@link #querySummary}

* These queries aggregate network usage across the whole interval. Therefore there will be only one - * bucket for a particular key and state and roaming combination. In case of the user-wide and - * device-wide summaries a single bucket containing the totalised network usage is returned. + * bucket for a particular key, state, metered and roaming combination. In case of the user-wide + * and device-wide summaries a single bucket containing the totalised network usage is returned. *

* History queries *

* {@link #queryDetailsForUid}

* {@link #queryDetails}

- * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there - * can be multiple buckets for a particular key but all Bucket's state is going to be - * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be + * These queries do not aggregate over time but do aggregate over state, metered and roaming. + * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to + * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

* NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the @@ -104,10 +105,11 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This - * means the bucket's start and end timestamp are going to be the same as the 'startTime' and - * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid - * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE} + * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and + * roaming. This means the bucket's start and end timestamp are going to be the same as the + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL}, * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -143,8 +145,10 @@ public class NetworkStatsManager { * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid - * {@link NetworkStats.Bucket#UID_ALL}. + * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -178,9 +182,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid. This means buckets' start and end - * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. - * State and uid are going to vary, and tag is going to be the same. + * end timestamps. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -263,10 +268,12 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time or uid. This means - * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' - * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be + * calling user. Result is aggregated over state but not aggregated over time, uid, tag, + * metered, nor roaming. This means buckets' start and end timestamps are going to be between + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d570e66a24..c704ef0c9c 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -171,7 +171,8 @@ public class NetworkIdentity implements Comparable { String subscriberId = null; String networkId = null; boolean roaming = false; - boolean metered = false; + boolean metered = !state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED); if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { @@ -185,9 +186,6 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; roaming = state.networkInfo.isRoaming(); - metered = !state.networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f65a50f02d..77ce65b081 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -68,11 +68,18 @@ public class NetworkStats implements Parcelable { // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #set} value for all roaming values. */ + /** {@link #metered} value to account for all metered states. */ + public static final int METERED_ALL = -1; + /** {@link #metered} value where native, unmetered data is accounted. */ + public static final int METERED_NO = 0; + /** {@link #metered} value where metered data is accounted. */ + public static final int METERED_YES = 1; + + /** {@link #roaming} value to account for all roaming states. */ public static final int ROAMING_ALL = -1; - /** {@link #set} value where native, non-roaming data is accounted. */ + /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; - /** {@link #set} value where roaming data is accounted. */ + /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; // TODO: move fields to "mVariable" notation @@ -88,6 +95,7 @@ public class NetworkStats implements Parcelable { private int[] uid; private int[] set; private int[] tag; + private int[] metered; private int[] roaming; private long[] rxBytes; private long[] rxPackets; @@ -100,6 +108,12 @@ public class NetworkStats implements Parcelable { public int uid; public int set; public int tag; + /** + * Note that this is only populated w/ the default value when read from /proc or written + * to disk. We merge in the correct value when reporting this value to clients of + * getSummary(). + */ + public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of @@ -123,16 +137,17 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets, - operations); + this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes, + txPackets, operations); } - public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { + public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; + this.metered = metered; this.roaming = roaming; this.rxBytes = rxBytes; this.rxPackets = rxPackets; @@ -165,6 +180,7 @@ public class NetworkStats implements Parcelable { builder.append(" uid=").append(uid); builder.append(" set=").append(setToString(set)); builder.append(" tag=").append(tagToString(tag)); + builder.append(" metered=").append(meteredToString(metered)); builder.append(" roaming=").append(roamingToString(roaming)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); @@ -178,13 +194,18 @@ public class NetworkStats implements Parcelable { public boolean equals(Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming - && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes - && txPackets == e.txPackets && operations == e.operations - && iface.equals(e.iface); + return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered + && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets + && txBytes == e.txBytes && txPackets == e.txPackets + && operations == e.operations && iface.equals(e.iface); } return false; } + + @Override + public int hashCode() { + return Objects.hash(uid, set, tag, metered, roaming, iface); + } } public NetworkStats(long elapsedRealtime, int initialSize) { @@ -196,6 +217,7 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.set = new int[initialSize]; this.tag = new int[initialSize]; + this.metered = new int[initialSize]; this.roaming = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; @@ -209,6 +231,7 @@ public class NetworkStats implements Parcelable { this.uid = EmptyArray.INT; this.set = EmptyArray.INT; this.tag = EmptyArray.INT; + this.metered = EmptyArray.INT; this.roaming = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; @@ -226,6 +249,7 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); set = parcel.createIntArray(); tag = parcel.createIntArray(); + metered = parcel.createIntArray(); roaming = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); @@ -243,6 +267,7 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(set); dest.writeIntArray(tag); + dest.writeIntArray(metered); dest.writeIntArray(roaming); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); @@ -277,10 +302,11 @@ public class NetworkStats implements Parcelable { } @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming, + public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( - iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations)); + iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, + operations)); } /** @@ -294,6 +320,7 @@ public class NetworkStats implements Parcelable { uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); + metered = Arrays.copyOf(metered, newLength); roaming = Arrays.copyOf(roaming, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); @@ -307,6 +334,7 @@ public class NetworkStats implements Parcelable { uid[size] = entry.uid; set[size] = entry.set; tag[size] = entry.tag; + metered[size] = entry.metered; roaming[size] = entry.roaming; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; @@ -327,6 +355,7 @@ public class NetworkStats implements Parcelable { entry.uid = uid[i]; entry.set = set[i]; entry.tag = tag[i]; + entry.metered = metered[i]; entry.roaming = roaming[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; @@ -381,7 +410,8 @@ public class NetworkStats implements Parcelable { * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, + entry.roaming); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -409,10 +439,11 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag, int roaming) { + public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -424,7 +455,7 @@ public class NetworkStats implements Parcelable { * search around the hinted index as an optimization. */ @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int roaming, + public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -438,7 +469,8 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -452,7 +484,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]); if (j == -1) { operations[i] = 0; } else { @@ -542,6 +574,7 @@ public class NetworkStats implements Parcelable { entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.rxBytes = 0; entry.rxPackets = 0; @@ -637,11 +670,12 @@ public class NetworkStats implements Parcelable { entry.uid = left.uid[i]; entry.set = left.set[i]; entry.tag = left.tag[i]; + entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.roaming, i); + entry.metered, entry.roaming, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = left.rxBytes[i]; @@ -687,6 +721,7 @@ public class NetworkStats implements Parcelable { entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.operations = 0L; @@ -716,6 +751,7 @@ public class NetworkStats implements Parcelable { entry.iface = IFACE_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; for (int i = 0; i < size; i++) { @@ -762,6 +798,7 @@ public class NetworkStats implements Parcelable { pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); + pw.print(" metered="); pw.print(meteredToString(metered[i])); pw.print(" roaming="); pw.print(roamingToString(roaming[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); @@ -829,6 +866,22 @@ public class NetworkStats implements Parcelable { return "0x" + Integer.toHexString(tag); } + /** + * Return text description of {@link #metered} value. + */ + public static String meteredToString(int metered) { + switch (metered) { + case METERED_ALL: + return "ALL"; + case METERED_NO: + return "NO"; + case METERED_YES: + return "YES"; + default: + return "UNKNOWN"; + } + } + /** * Return text description of {@link #roaming} value. */ @@ -998,6 +1051,7 @@ public class NetworkStats implements Parcelable { tmpEntry.uid = uid[i]; tmpEntry.tag = tag[i]; tmpEntry.set = set[i]; + tmpEntry.metered = metered[i]; tmpEntry.roaming = roaming[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { @@ -1017,24 +1071,25 @@ public class NetworkStats implements Parcelable { moved.set = SET_DBG_VPN_OUT; moved.tag = TAG_NONE; moved.iface = underlyingIface; + moved.metered = METERED_ALL; moved.roaming = ROAMING_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. // - // Relies on the fact that the underlying traffic only has state ROAMING_NO, which - // should be the case as it comes directly from the /proc file. We only blend in the + // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, + // which should be the case as it comes directly from the /proc file. We only blend in the // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 9fa90acc02..4a2b88142e 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -43,6 +43,7 @@ static struct { jfieldID uid; jfieldID set; jfieldID tag; + jfieldID metered; jfieldID roaming; jfieldID rxBytes; jfieldID rxPackets; @@ -239,6 +240,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ScopedIntArrayRW tag(env, get_int_array(env, stats, gNetworkStatsClassInfo.tag, size, grow)); if (tag.get() == NULL) return -1; + ScopedIntArrayRW metered(env, get_int_array(env, stats, + gNetworkStatsClassInfo.metered, size, grow)); + if (metered.get() == NULL) return -1; ScopedIntArrayRW roaming(env, get_int_array(env, stats, gNetworkStatsClassInfo.roaming, size, grow)); if (roaming.get() == NULL) return -1; @@ -265,7 +269,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, uid[i] = lines[i].uid; set[i] = lines[i].set; tag[i] = lines[i].tag; - // Roaming is populated in Java-land by inspecting the iface properties. + // Metered and Roaming are populated in Java-land by inspecting the iface properties. rxBytes[i] = lines[i].rxBytes; rxPackets[i] = lines[i].rxPackets; txBytes[i] = lines[i].txBytes; @@ -279,6 +283,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); @@ -311,6 +316,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); + gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 959a823290..c48f43058f 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -91,6 +91,19 @@ public class NetworkIdentitySet extends HashSet implements } } + /** @return whether any {@link NetworkIdentity} in this set is considered metered. */ + public boolean isAnyMemberMetered() { + if (isEmpty()) { + return false; + } + for (NetworkIdentity ident : this) { + if (ident.getMetered()) { + return true; + } + } + return false; + } + /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */ public boolean isAnyMemberRoaming() { if (isEmpty()) { diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 673dd8fbbd..c45b4169f5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,6 +17,8 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.NetworkStats.SET_ALL; @@ -242,6 +244,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; + entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; entry.rxPackets = historyEntry.rxPackets;