From 1b5a2a96f793211bfbd39aa29cc41031dfa23950 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 18 Jun 2011 18:34:16 -0700 Subject: Read "qtaguid" network stats, refactor templates. Teach NMS to read qtaguid stats from kernel, but fall back to older stats when kernel doesn't support. Add "tags" to NetworkStats entries to support qtaguid. To work around double-reporting bug, subtract tagged stats from TAG_NONE entry. Flesh out stronger NetworkTemplate. All NetworkStatsService requests now require a template, and moved matching logic into template. Record UID stats keyed on complete NetworkIdentitySet definition, similar to how interface stats are stored. Since previous UID stats didn't have iface breakdown, discard during file format upgrade. Change-Id: I0447b5e7d205d73d28e71c889c568e536e91b8e4 --- core/java/android/net/INetworkStatsService.aidl | 9 +- core/java/android/net/NetworkIdentity.java | 107 +++++++ core/java/android/net/NetworkPolicy.java | 32 +- core/java/android/net/NetworkPolicyManager.java | 2 +- core/java/android/net/NetworkStats.java | 48 ++- core/java/android/net/NetworkStatsHistory.java | 14 +- core/java/android/net/NetworkTemplate.aidl | 19 ++ core/java/android/net/NetworkTemplate.java | 217 ++++++++++++++ core/java/android/net/TrafficStats.java | 45 --- .../src/android/net/NetworkStatsTest.java | 80 +++-- .../android/server/NetworkManagementService.java | 115 +++++-- .../java/com/android/server/ThrottleService.java | 3 +- .../com/android/server/net/InterfaceIdentity.java | 73 ----- .../com/android/server/net/NetworkIdentity.java | 227 -------------- .../com/android/server/net/NetworkIdentitySet.java | 86 ++++++ .../server/net/NetworkPolicyManagerService.java | 60 ++-- .../android/server/net/NetworkStatsService.java | 333 ++++++++++++--------- .../server/NetworkPolicyManagerServiceTest.java | 20 +- .../android/server/NetworkStatsServiceTest.java | 52 ++-- .../com/android/server/ThrottleServiceTest.java | 2 +- 20 files changed, 913 insertions(+), 631 deletions(-) create mode 100644 core/java/android/net/NetworkIdentity.java create mode 100644 core/java/android/net/NetworkTemplate.aidl create mode 100644 core/java/android/net/NetworkTemplate.java delete mode 100644 services/java/com/android/server/net/InterfaceIdentity.java delete mode 100644 services/java/com/android/server/net/NetworkIdentity.java create mode 100644 services/java/com/android/server/net/NetworkIdentitySet.java diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 288112a25cf2..6371500f81d7 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -18,18 +18,19 @@ package android.net; import android.net.NetworkStats; import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; /** {@hide} */ interface INetworkStatsService { /** Return historical stats for traffic that matches template. */ - NetworkStatsHistory getHistoryForNetwork(int networkTemplate); + NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template); /** Return historical stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate); + NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid); /** Return usage summary for traffic that matches template. */ - NetworkStats getSummaryForNetwork(long start, long end, int networkTemplate, String subscriberId); + NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return usage summary per UID for traffic that matches template. */ - NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate); + NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end); } diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java new file mode 100644 index 000000000000..f82d922f9191 --- /dev/null +++ b/core/java/android/net/NetworkIdentity.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.net.ConnectivityManager.isNetworkTypeMobile; + +import android.content.Context; +import android.telephony.TelephonyManager; + +import com.android.internal.util.Objects; + +/** + * Network definition that includes strong identity. Analogous to combining + * {@link NetworkInfo} and an IMSI. + * + * @hide + */ +public class NetworkIdentity { + final int mType; + final int mSubType; + final String mSubscriberId; + + public NetworkIdentity(int type, int subType, String subscriberId) { + this.mType = type; + this.mSubType = subType; + this.mSubscriberId = subscriberId; + } + + @Override + public int hashCode() { + return Objects.hashCode(mType, mSubType, mSubscriberId); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NetworkIdentity) { + final NetworkIdentity ident = (NetworkIdentity) obj; + return mType == ident.mType && mSubType == ident.mSubType + && Objects.equal(mSubscriberId, ident.mSubscriberId); + } + return false; + } + + @Override + public String toString() { + final String typeName = ConnectivityManager.getNetworkTypeName(mType); + final String subTypeName; + if (ConnectivityManager.isNetworkTypeMobile(mType)) { + subTypeName = TelephonyManager.getNetworkTypeName(mSubType); + } else { + subTypeName = Integer.toString(mSubType); + } + + final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null"; + return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId=" + + scrubSubscriberId + "]"; + } + + public int getType() { + return mType; + } + + public int getSubType() { + return mSubType; + } + + public String getSubscriberId() { + return mSubscriberId; + } + + /** + * Build a {@link NetworkIdentity} from the given {@link NetworkState}, + * assuming that any mobile networks are using the current IMSI. + */ + public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) { + final int type = state.networkInfo.getType(); + final int subType = state.networkInfo.getSubtype(); + + // TODO: consider moving subscriberId over to LinkCapabilities, so it + // comes from an authoritative source. + + final String subscriberId; + if (isNetworkTypeMobile(type)) { + final TelephonyManager telephony = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + subscriberId = telephony.getSubscriberId(); + } else { + subscriberId = null; + } + return new NetworkIdentity(type, subType, subscriberId); + } + +} diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 1899281f607a..52cab30f9ccc 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -16,37 +16,38 @@ package android.net; +import static com.android.internal.util.Preconditions.checkNotNull; + import android.os.Parcel; import android.os.Parcelable; /** - * Policy for a specific network, including usage cycle and limits to be - * enforced. + * Policy for networks matching a {@link NetworkTemplate}, including usage cycle + * and limits to be enforced. * * @hide */ public class NetworkPolicy implements Parcelable, Comparable { - public final int networkTemplate; - public final String subscriberId; + public static final long WARNING_DISABLED = -1; + public static final long LIMIT_DISABLED = -1; + + public final NetworkTemplate template; public int cycleDay; public long warningBytes; public long limitBytes; - public static final long WARNING_DISABLED = -1; - public static final long LIMIT_DISABLED = -1; + // TODO: teach how to snooze limit for current cycle - public NetworkPolicy(int networkTemplate, String subscriberId, int cycleDay, long warningBytes, - long limitBytes) { - this.networkTemplate = networkTemplate; - this.subscriberId = subscriberId; + public NetworkPolicy( + NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes) { + this.template = checkNotNull(template, "missing NetworkTemplate"); this.cycleDay = cycleDay; this.warningBytes = warningBytes; this.limitBytes = limitBytes; } public NetworkPolicy(Parcel in) { - networkTemplate = in.readInt(); - subscriberId = in.readString(); + template = in.readParcelable(null); cycleDay = in.readInt(); warningBytes = in.readLong(); limitBytes = in.readLong(); @@ -54,8 +55,7 @@ public class NetworkPolicy implements Parcelable, Comparable { /** {@inheritDoc} */ public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(networkTemplate); - dest.writeString(subscriberId); + dest.writeParcelable(template, flags); dest.writeInt(cycleDay); dest.writeLong(warningBytes); dest.writeLong(limitBytes); @@ -81,8 +81,8 @@ public class NetworkPolicy implements Parcelable, Comparable { @Override public String toString() { - return "NetworkPolicy: networkTemplate=" + networkTemplate + ", cycleDay=" + cycleDay - + ", warningBytes=" + warningBytes + ", limitBytes=" + limitBytes; + return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes=" + + warningBytes + ", limitBytes=" + limitBytes; } public static final Creator CREATOR = new Creator() { diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index bfea16804b33..91af16d0010d 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -59,7 +59,7 @@ public class NetworkPolicyManager { /** * {@link Intent} extra included in {@link #ACTION_DATA_USAGE_WARNING} and * {@link #ACTION_DATA_USAGE_LIMIT} to indicate which - * {@link NetworkPolicy#networkTemplate} it applies to. + * {@link NetworkTemplate} rule it applies to. */ public static final String EXTRA_NETWORK_TEMPLATE = "android.intent.extra.NETWORK_TEMPLATE"; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 60f740e80f53..9d40c42a39d7 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -40,9 +40,8 @@ public class NetworkStats implements Parcelable { public static final String IFACE_ALL = null; /** {@link #uid} value when UID details unavailable. */ public static final int UID_ALL = -1; - - // NOTE: data should only be accounted for once in this structure; if data - // is broken out, the summarized version should not be included. + /** {@link #tag} value for without tag. */ + public static final int TAG_NONE = 0; /** * {@link SystemClock#elapsedRealtime()} timestamp when this data was @@ -52,16 +51,16 @@ public class NetworkStats implements Parcelable { public int size; public String[] iface; public int[] uid; + public int[] tag; public long[] rx; public long[] tx; - // TODO: add fg/bg stats once reported by kernel - public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; this.iface = new String[initialSize]; this.uid = new int[initialSize]; + this.tag = new int[initialSize]; this.rx = new long[initialSize]; this.tx = new long[initialSize]; } @@ -71,21 +70,27 @@ public class NetworkStats implements Parcelable { size = parcel.readInt(); iface = parcel.createStringArray(); uid = parcel.createIntArray(); + tag = parcel.createIntArray(); rx = parcel.createLongArray(); tx = parcel.createLongArray(); } - public NetworkStats addEntry(String iface, int uid, long rx, long tx) { + /** + * Add new stats entry with given values. + */ + public NetworkStats addEntry(String iface, int uid, int tag, long rx, long tx) { if (size >= this.iface.length) { final int newLength = Math.max(this.iface.length, 10) * 3 / 2; this.iface = Arrays.copyOf(this.iface, newLength); this.uid = Arrays.copyOf(this.uid, newLength); + this.tag = Arrays.copyOf(this.tag, newLength); this.rx = Arrays.copyOf(this.rx, newLength); this.tx = Arrays.copyOf(this.tx, newLength); } this.iface[size] = iface; this.uid[size] = uid; + this.tag[size] = tag; this.rx[size] = rx; this.tx[size] = tx; size++; @@ -93,17 +98,29 @@ public class NetworkStats implements Parcelable { return this; } - @Deprecated - public int length() { - return size; + /** + * Combine given values with an existing row, or create a new row if + * {@link #findIndex(String, int, int)} is unable to find match. Can also be + * used to subtract values from existing rows. + */ + public NetworkStats combineEntry(String iface, int uid, int tag, long rx, long tx) { + final int i = findIndex(iface, uid, tag); + if (i == -1) { + // only create new entry when positive contribution + addEntry(iface, uid, tag, rx, tx); + } else { + this.rx[i] += rx; + this.tx[i] += tx; + } + return this; } /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid) { + public int findIndex(String iface, int uid, int tag) { for (int i = 0; i < size; i++) { - if (equal(iface, this.iface[i]) && uid == this.uid[i]) { + if (equal(iface, this.iface[i]) && uid == this.uid[i] && tag == this.tag[i]) { return i; } } @@ -186,12 +203,13 @@ public class NetworkStats implements Parcelable { for (int i = 0; i < size; i++) { final String iface = this.iface[i]; final int uid = this.uid[i]; + final int tag = this.tag[i]; // find remote row that matches, and subtract - final int j = value.findIndex(iface, uid); + final int j = value.findIndex(iface, uid, tag); if (j == -1) { // newly appearing row, return entire value - result.addEntry(iface, uid, this.rx[i], this.tx[i]); + result.addEntry(iface, uid, tag, this.rx[i], this.tx[i]); } else { // existing row, subtract remote value long rx = this.rx[i] - value.rx[j]; @@ -203,7 +221,7 @@ public class NetworkStats implements Parcelable { rx = Math.max(0, rx); tx = Math.max(0, tx); } - result.addEntry(iface, uid, rx, tx); + result.addEntry(iface, uid, tag, rx, tx); } } @@ -221,6 +239,7 @@ public class NetworkStats implements Parcelable { pw.print(prefix); pw.print(" iface="); pw.print(iface[i]); pw.print(" uid="); pw.print(uid[i]); + pw.print(" tag="); pw.print(tag[i]); pw.print(" rx="); pw.print(rx[i]); pw.print(" tx="); pw.println(tx[i]); } @@ -244,6 +263,7 @@ public class NetworkStats implements Parcelable { dest.writeInt(size); dest.writeStringArray(iface); dest.writeIntArray(uid); + dest.writeIntArray(tag); dest.writeLongArray(rx); dest.writeLongArray(tx); } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 5fa8e21a0ca0..ff6e220cac41 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -40,10 +40,9 @@ import java.util.Random; * @hide */ public class NetworkStatsHistory implements Parcelable { - private static final int VERSION_CURRENT = 1; + private static final int VERSION_INIT = 1; - // TODO: teach about zigzag encoding to use less disk space - // TODO: teach how to convert between bucket sizes + // TODO: teach about varint encoding to use less disk space public final long bucketDuration; @@ -83,7 +82,7 @@ public class NetworkStatsHistory implements Parcelable { public NetworkStatsHistory(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { - case VERSION_CURRENT: { + case VERSION_INIT: { bucketDuration = in.readLong(); bucketStart = readLongArray(in); rx = readLongArray(in); @@ -98,7 +97,7 @@ public class NetworkStatsHistory implements Parcelable { } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_CURRENT); + out.writeInt(VERSION_INIT); out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); writeLongArray(out, rx, bucketCount); @@ -115,6 +114,11 @@ public class NetworkStatsHistory implements Parcelable { * distribute across internal buckets, creating new buckets as needed. */ public void recordData(long start, long end, long rx, long tx) { + if (rx < 0 || tx < 0) { + throw new IllegalArgumentException( + "tried recording negative data: rx=" + rx + ", tx=" + tx); + } + // create any buckets needed by this range ensureBuckets(start, end); diff --git a/core/java/android/net/NetworkTemplate.aidl b/core/java/android/net/NetworkTemplate.aidl new file mode 100644 index 000000000000..3d37488d9881 --- /dev/null +++ b/core/java/android/net/NetworkTemplate.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable NetworkTemplate; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java new file mode 100644 index 000000000000..9381f1dec3c2 --- /dev/null +++ b/core/java/android/net/NetworkTemplate.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.ConnectivityManager.TYPE_WIMAX; +import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; +import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; +import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; +import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; +import static android.telephony.TelephonyManager.getNetworkClass; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Objects; + +/** + * Template definition used to generically match {@link NetworkIdentity}, + * usually when collecting statistics. + * + * @hide + */ +public class NetworkTemplate implements Parcelable { + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together. Only uses statistics for requested IMSI. + */ + public static final int MATCH_MOBILE_ALL = 1; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together that roughly meet a "3G" definition, or lower. Only + * uses statistics for requested IMSI. + */ + public static final int MATCH_MOBILE_3G_LOWER = 2; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together that meet a "4G" definition. Only uses statistics for + * requested IMSI. + */ + public static final int MATCH_MOBILE_4G = 3; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style + * networks together. + */ + public static final int MATCH_WIFI = 4; + + final int mMatchRule; + final String mSubscriberId; + + public NetworkTemplate(int matchRule, String subscriberId) { + this.mMatchRule = matchRule; + this.mSubscriberId = subscriberId; + } + + public NetworkTemplate(Parcel in) { + mMatchRule = in.readInt(); + mSubscriberId = in.readString(); + } + + /** {@inheritDoc} */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mMatchRule); + dest.writeString(mSubscriberId); + } + + /** {@inheritDoc} */ + public int describeContents() { + return 0; + } + + @Override + public String toString() { + final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null"; + return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId=" + + scrubSubscriberId; + } + + @Override + public int hashCode() { + return Objects.hashCode(mMatchRule, mSubscriberId); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NetworkTemplate) { + final NetworkTemplate other = (NetworkTemplate) obj; + return mMatchRule == other.mMatchRule + && Objects.equal(mSubscriberId, other.mSubscriberId); + } + return false; + } + + public int getMatchRule() { + return mMatchRule; + } + + public String getSubscriberId() { + return mSubscriberId; + } + + /** + * Test if this network matches the given template and IMEI. + */ + public boolean matches(NetworkIdentity ident) { + switch (mMatchRule) { + case MATCH_MOBILE_ALL: + return matchesMobile(ident); + case MATCH_MOBILE_3G_LOWER: + return matchesMobile3gLower(ident); + case MATCH_MOBILE_4G: + return matchesMobile4g(ident); + case MATCH_WIFI: + return matchesWifi(ident); + default: + throw new IllegalArgumentException("unknown network template"); + } + } + + /** + * Check if mobile network with matching IMEI. Also matches + * {@link #TYPE_WIMAX}. + */ + private boolean matchesMobile(NetworkIdentity ident) { + if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { + return true; + } else if (ident.mType == TYPE_WIMAX) { + return true; + } + return false; + } + + /** + * Check if mobile network classified 3G or lower with matching IMEI. + */ + private boolean matchesMobile3gLower(NetworkIdentity ident) { + if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { + switch (getNetworkClass(ident.mSubType)) { + case NETWORK_CLASS_UNKNOWN: + case NETWORK_CLASS_2_G: + case NETWORK_CLASS_3_G: + return true; + } + } + return false; + } + + /** + * Check if mobile network classified 4G with matching IMEI. Also matches + * {@link #TYPE_WIMAX}. + */ + private boolean matchesMobile4g(NetworkIdentity ident) { + if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { + switch (getNetworkClass(ident.mSubType)) { + case NETWORK_CLASS_4_G: + return true; + } + } else if (ident.mType == TYPE_WIMAX) { + return true; + } + return false; + } + + /** + * Check if matches Wi-Fi network template. + */ + private boolean matchesWifi(NetworkIdentity ident) { + if (ident.mType == TYPE_WIFI) { + return true; + } + return false; + } + + public static String getMatchRuleName(int matchRule) { + switch (matchRule) { + case MATCH_MOBILE_3G_LOWER: + return "MOBILE_3G_LOWER"; + case MATCH_MOBILE_4G: + return "MOBILE_4G"; + case MATCH_MOBILE_ALL: + return "MOBILE_ALL"; + case MATCH_WIFI: + return "WIFI"; + default: + return "UNKNOWN"; + } + } + + public static final Creator CREATOR = new Creator() { + public NetworkTemplate createFromParcel(Parcel in) { + return new NetworkTemplate(in); + } + + public NetworkTemplate[] newArray(int size) { + return new NetworkTemplate[size]; + } + }; +} diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 3725fa64ebab..e163abfebbd7 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -41,40 +41,6 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; - /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together. Only uses statistics for requested IMSI. - * - * @hide - */ - public static final int TEMPLATE_MOBILE_ALL = 1; - - /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together that roughly meet a "3G" definition, or lower. Only - * uses statistics for requested IMSI. - * - * @hide - */ - public static final int TEMPLATE_MOBILE_3G_LOWER = 2; - - /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together that meet a "4G" definition. Only uses statistics for - * requested IMSI. - * - * @hide - */ - public static final int TEMPLATE_MOBILE_4G = 3; - - /** - * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style - * networks together. - * - * @hide - */ - public static final int TEMPLATE_WIFI = 4; - /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. @@ -182,17 +148,6 @@ public class TrafficStats { } } - /** {@hide} */ - public static boolean isNetworkTemplateMobile(int networkTemplate) { - switch (networkTemplate) { - case TEMPLATE_MOBILE_3G_LOWER: - case TEMPLATE_MOBILE_4G: - case TEMPLATE_MOBILE_ALL: - return true; - } - return false; - } - /** * Get the total number of packets transmitted through the mobile interface. * diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java index 5250a7c2ae9e..3cb64c74afb7 100644 --- a/core/tests/coretests/src/android/net/NetworkStatsTest.java +++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java @@ -16,6 +16,8 @@ package android.net; +import static android.net.NetworkStats.TAG_NONE; + import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; @@ -29,14 +31,14 @@ public class NetworkStatsTest extends TestCase { public void testFindIndex() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 3) - .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024) - .addEntry(TEST_IFACE, 102, 1024, 1024); - - assertEquals(2, stats.findIndex(TEST_IFACE, 102)); - assertEquals(2, stats.findIndex(TEST_IFACE, 102)); - assertEquals(0, stats.findIndex(TEST_IFACE, 100)); - assertEquals(-1, stats.findIndex(TEST_IFACE, 6)); + .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L) + .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L) + .addEntry(TEST_IFACE, 102, TAG_NONE, 1024L, 1024L); + + assertEquals(2, stats.findIndex(TEST_IFACE, 102, TAG_NONE)); + assertEquals(2, stats.findIndex(TEST_IFACE, 102, TAG_NONE)); + assertEquals(0, stats.findIndex(TEST_IFACE, 100, TAG_NONE)); + assertEquals(-1, stats.findIndex(TEST_IFACE, 6, TAG_NONE)); } public void testAddEntryGrow() throws Exception { @@ -45,15 +47,15 @@ public class NetworkStatsTest extends TestCase { assertEquals(0, stats.size); assertEquals(2, stats.iface.length); - stats.addEntry(TEST_IFACE, TEST_UID, 1L, 2L); - stats.addEntry(TEST_IFACE, TEST_UID, 2L, 2L); + stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 1L, 2L); + stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 2L, 2L); assertEquals(2, stats.size); assertEquals(2, stats.iface.length); - stats.addEntry(TEST_IFACE, TEST_UID, 3L, 4L); - stats.addEntry(TEST_IFACE, TEST_UID, 4L, 4L); - stats.addEntry(TEST_IFACE, TEST_UID, 5L, 5L); + stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 3L, 4L); + stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 4L, 4L); + stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 5L, 5L); assertEquals(5, stats.size); assertTrue(stats.iface.length >= 5); @@ -65,14 +67,31 @@ public class NetworkStatsTest extends TestCase { assertEquals(5L, stats.rx[4]); } + public void testCombineExisting() throws Exception { + final NetworkStats stats = new NetworkStats(TEST_START, 10); + + stats.addEntry(TEST_IFACE, 1001, TAG_NONE, 512L, 256L); + stats.addEntry(TEST_IFACE, 1001, 0xff, 128L, 128L); + stats.combineEntry(TEST_IFACE, 1001, TAG_NONE, -128L, -128L); + + assertStatsEntry(stats, 0, TEST_IFACE, 1001, TAG_NONE, 384L, 128L); + assertStatsEntry(stats, 1, TEST_IFACE, 1001, 0xff, 128L, 128L); + + // now try combining that should create row + stats.combineEntry(TEST_IFACE, 5005, TAG_NONE, 128L, 128L); + assertStatsEntry(stats, 2, TEST_IFACE, 5005, TAG_NONE, 128L, 128L); + stats.combineEntry(TEST_IFACE, 5005, TAG_NONE, 128L, 128L); + assertStatsEntry(stats, 2, TEST_IFACE, 5005, TAG_NONE, 256L, 256L); + } + public void testSubtractIdenticalData() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024); + .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L) + .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L); final NetworkStats after = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024); + .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L) + .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L); final NetworkStats result = after.subtract(before); @@ -85,12 +104,12 @@ public class NetworkStatsTest extends TestCase { public void testSubtractIdenticalRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024); + .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L) + .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L); final NetworkStats after = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, 1025, 2) - .addEntry(TEST_IFACE, 101, 3, 1028); + .addEntry(TEST_IFACE, 100, TAG_NONE, 1025L, 2L) + .addEntry(TEST_IFACE, 101, TAG_NONE, 3L, 1028L); final NetworkStats result = after.subtract(before); @@ -103,13 +122,13 @@ public class NetworkStatsTest extends TestCase { public void testSubtractNewRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024); + .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L) + .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L); final NetworkStats after = new NetworkStats(TEST_START, 3) - .addEntry(TEST_IFACE, 100, 1024, 0) - .addEntry(TEST_IFACE, 101, 0, 1024) - .addEntry(TEST_IFACE, 102, 1024, 1024); + .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L) + .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L) + .addEntry(TEST_IFACE, 102, TAG_NONE, 1024L, 1024L); final NetworkStats result = after.subtract(before); @@ -122,4 +141,13 @@ public class NetworkStatsTest extends TestCase { assertEquals(1024, result.tx[2]); } + private static void assertStatsEntry( + NetworkStats stats, int i, String iface, int uid, int tag, long rx, long tx) { + assertEquals(iface, stats.iface[i]); + assertEquals(uid, stats.uid[i]); + assertEquals(tag, stats.tag[i]); + assertEquals(rx, stats.rx[i]); + assertEquals(tx, stats.tx[i]); + } + } diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index bb0c6714b20d..d5bdd21dd733 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -16,6 +16,10 @@ package com.android.server; +import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStats.UID_ALL; + import android.content.Context; import android.content.pm.PackageManager; import android.net.INetworkManagementEventObserver; @@ -37,6 +41,7 @@ import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Inet4Address; @@ -59,8 +64,9 @@ class NetworkManagementService extends INetworkManagementService.Stub { private static final int ADD = 1; private static final int REMOVE = 2; - /** Base path to UID-granularity network statistics. */ - private static final File PATH_PROC_UID_STAT = new File("/proc/uid_stat"); + @Deprecated + private static final File STATS_UIDSTAT = new File("/proc/uid_stat"); + private static final File STATS_NETFILTER = new File("/proc/net/xt_qtaguid/stats"); class NetdResponseCode { public static final int InterfaceListResult = 110; @@ -899,7 +905,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { for (String iface : ifaces) { final long rx = getInterfaceCounter(iface, true); final long tx = getInterfaceCounter(iface, false); - stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx); + stats.addEntry(iface, UID_ALL, TAG_NONE, rx, tx); } return stats; @@ -910,16 +916,11 @@ class NetworkManagementService extends INetworkManagementService.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); - final String[] knownUids = PATH_PROC_UID_STAT.list(); - final NetworkStats stats = new NetworkStats( - SystemClock.elapsedRealtime(), knownUids.length); - - for (String uid : knownUids) { - final int uidInt = Integer.parseInt(uid); - collectNetworkStatsDetail(stats, uidInt); + if (STATS_NETFILTER.exists()) { + return getNetworkStatsDetailNetfilter(UID_ALL); + } else { + return getNetworkStatsDetailUidstat(UID_ALL); } - - return stats; } @Override @@ -929,19 +930,89 @@ class NetworkManagementService extends INetworkManagementService.Stub { android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); } - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); - collectNetworkStatsDetail(stats, uid); + if (STATS_NETFILTER.exists()) { + return getNetworkStatsDetailNetfilter(uid); + } else { + return getNetworkStatsDetailUidstat(uid); + } + } + + /** + * Build {@link NetworkStats} with detailed UID statistics. + */ + private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) { + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24); + + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(STATS_NETFILTER)); + + // assumes format from kernel: + // idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes + + // skip first line, which is legend + String line = reader.readLine(); + while ((line = reader.readLine()) != null) { + final StringTokenizer t = new StringTokenizer(line); + + final String idx = t.nextToken(); + final String iface = t.nextToken(); + + try { + // TODO: kernel currently emits tag in upper half of long; + // eventually switch to directly using int. + final int tag = (int) (Long.parseLong(t.nextToken().substring(2), 16) >> 32); + final int uid = Integer.parseInt(t.nextToken()); + final long rx = Long.parseLong(t.nextToken()); + final long tx = Long.parseLong(t.nextToken()); + + if (limitUid == UID_ALL || limitUid == uid) { + stats.addEntry(iface, uid, tag, rx, tx); + if (tag != TAG_NONE) { + // proc also counts tagged data in generic tag, so + // we subtract it here to avoid double-counting. + stats.combineEntry(iface, uid, TAG_NONE, -rx, -tx); + } + } + } catch (NumberFormatException e) { + Slog.w(TAG, "problem parsing stats for idx " + idx + ": " + e); + } + } + } catch (IOException e) { + Slog.w(TAG, "problem parsing stats: " + e); + } finally { + IoUtils.closeQuietly(reader); + } + return stats; } - private void collectNetworkStatsDetail(NetworkStats stats, int uid) { - // TODO: kernel module will provide interface-level stats in future - // TODO: migrate these stats to come across netd in bulk, instead of all - // these individual file reads. - final File uidPath = new File(PATH_PROC_UID_STAT, Integer.toString(uid)); - final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv")); - final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd")); - stats.addEntry(NetworkStats.IFACE_ALL, uid, rx, tx); + /** + * Build {@link NetworkStats} with detailed UID statistics. + * + * @deprecated since this uses older "uid_stat" data, and doesn't provide + * tag-level granularity or additional variables. + */ + @Deprecated + private NetworkStats getNetworkStatsDetailUidstat(int limitUid) { + final String[] knownUids; + if (limitUid == UID_ALL) { + knownUids = STATS_UIDSTAT.list(); + } else { + knownUids = new String[] { String.valueOf(limitUid) }; + } + + final NetworkStats stats = new NetworkStats( + SystemClock.elapsedRealtime(), knownUids.length); + for (String uid : knownUids) { + final int uidInt = Integer.parseInt(uid); + final File uidPath = new File(STATS_UIDSTAT, uid); + final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv")); + final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd")); + stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx); + } + + return stats; } public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) { diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java index 510ff62ed514..7266d7dd4f1d 100644 --- a/services/java/com/android/server/ThrottleService.java +++ b/services/java/com/android/server/ThrottleService.java @@ -533,7 +533,8 @@ public class ThrottleService extends IThrottleManager.Stub { long incWrite = 0; try { final NetworkStats stats = mNMService.getNetworkStatsSummary(); - final int index = stats.findIndex(mIface, NetworkStats.UID_ALL); + final int index = stats.findIndex( + mIface, NetworkStats.UID_ALL, NetworkStats.TAG_NONE); if (index != -1) { incRead = stats.rx[index] - mLastRead; diff --git a/services/java/com/android/server/net/InterfaceIdentity.java b/services/java/com/android/server/net/InterfaceIdentity.java deleted file mode 100644 index ff86581effc9..000000000000 --- a/services/java/com/android/server/net/InterfaceIdentity.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.ProtocolException; -import java.util.HashSet; - -/** - * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} - * active on that interface. - * - * @hide - */ -public class InterfaceIdentity extends HashSet { - private static final int VERSION_CURRENT = 1; - - public InterfaceIdentity() { - } - - public InterfaceIdentity(DataInputStream in) throws IOException { - final int version = in.readInt(); - switch (version) { - case VERSION_CURRENT: { - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - add(new NetworkIdentity(in)); - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } - - public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_CURRENT); - out.writeInt(size()); - for (NetworkIdentity ident : this) { - ident.writeToStream(out); - } - } - - /** - * Test if any {@link NetworkIdentity} on this interface matches the given - * template and IMEI. - */ - public boolean matchesTemplate(int networkTemplate, String subscriberId) { - for (NetworkIdentity ident : this) { - if (ident.matchesTemplate(networkTemplate, subscriberId)) { - return true; - } - } - return false; - } -} diff --git a/services/java/com/android/server/net/NetworkIdentity.java b/services/java/com/android/server/net/NetworkIdentity.java deleted file mode 100644 index 4a207f737aa9..000000000000 --- a/services/java/com/android/server/net/NetworkIdentity.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.ConnectivityManager.TYPE_WIMAX; -import static android.net.ConnectivityManager.isNetworkTypeMobile; -import static android.net.TrafficStats.TEMPLATE_MOBILE_3G_LOWER; -import static android.net.TrafficStats.TEMPLATE_MOBILE_4G; -import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL; -import static android.net.TrafficStats.TEMPLATE_WIFI; -import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; -import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; -import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; -import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; -import static android.telephony.TelephonyManager.getNetworkClass; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.NetworkState; -import android.telephony.TelephonyManager; - -import com.android.internal.util.Objects; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.ProtocolException; - -/** - * Identity of a {@link NetworkInfo}, defined by network type and billing - * relationship (such as IMSI). - * - * @hide - */ -public class NetworkIdentity { - private static final int VERSION_CURRENT = 1; - - public final int type; - public final int subType; - public final String subscriberId; - - public NetworkIdentity(int type, int subType, String subscriberId) { - this.type = type; - this.subType = subType; - this.subscriberId = subscriberId; - } - - public NetworkIdentity(DataInputStream in) throws IOException { - final int version = in.readInt(); - switch (version) { - case VERSION_CURRENT: { - type = in.readInt(); - subType = in.readInt(); - subscriberId = readOptionalString(in); - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } - - public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_CURRENT); - out.writeInt(type); - out.writeInt(subType); - writeOptionalString(out, subscriberId); - } - - @Override - public int hashCode() { - return Objects.hashCode(type, subType, subscriberId); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof NetworkIdentity) { - final NetworkIdentity ident = (NetworkIdentity) obj; - return type == ident.type && subType == ident.subType - && Objects.equal(subscriberId, ident.subscriberId); - } - return false; - } - - @Override - public String toString() { - final String typeName = ConnectivityManager.getNetworkTypeName(type); - final String subTypeName; - if (ConnectivityManager.isNetworkTypeMobile(type)) { - subTypeName = TelephonyManager.getNetworkTypeName(subType); - } else { - subTypeName = Integer.toString(subType); - } - - return "[type=" + typeName + ", subType=" + subTypeName + ", subId=" + subscriberId + "]"; - } - - /** - * Test if this network matches the given template and IMEI. - */ - public boolean matchesTemplate(int networkTemplate, String subscriberId) { - switch (networkTemplate) { - case TEMPLATE_MOBILE_ALL: - return matchesMobile(subscriberId); - case TEMPLATE_MOBILE_3G_LOWER: - return matchesMobile3gLower(subscriberId); - case TEMPLATE_MOBILE_4G: - return matchesMobile4g(subscriberId); - case TEMPLATE_WIFI: - return matchesWifi(); - default: - throw new IllegalArgumentException("unknown network template"); - } - } - - /** - * Check if mobile network with matching IMEI. Also matches - * {@link #TYPE_WIMAX}. - */ - private boolean matchesMobile(String subscriberId) { - if (isNetworkTypeMobile(type) && Objects.equal(this.subscriberId, subscriberId)) { - return true; - } else if (type == TYPE_WIMAX) { - return true; - } - return false; - } - - /** - * Check if mobile network classified 3G or lower with matching IMEI. - */ - private boolean matchesMobile3gLower(String subscriberId) { - if (isNetworkTypeMobile(type) - && Objects.equal(this.subscriberId, subscriberId)) { - switch (getNetworkClass(subType)) { - case NETWORK_CLASS_UNKNOWN: - case NETWORK_CLASS_2_G: - case NETWORK_CLASS_3_G: - return true; - } - } - return false; - } - - /** - * Check if mobile network classified 4G with matching IMEI. Also matches - * {@link #TYPE_WIMAX}. - */ - private boolean matchesMobile4g(String subscriberId) { - if (isNetworkTypeMobile(type) - && Objects.equal(this.subscriberId, subscriberId)) { - switch (getNetworkClass(subType)) { - case NETWORK_CLASS_4_G: - return true; - } - } else if (type == TYPE_WIMAX) { - return true; - } - return false; - } - - /** - * Check if matches Wi-Fi network template. - */ - private boolean matchesWifi() { - if (type == TYPE_WIFI) { - return true; - } - return false; - } - - /** - * Build a {@link NetworkIdentity} from the given {@link NetworkState}, - * assuming that any mobile networks are using the current IMSI. - */ - public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) { - final int type = state.networkInfo.getType(); - final int subType = state.networkInfo.getSubtype(); - - // TODO: consider moving subscriberId over to LinkCapabilities, so it - // comes from an authoritative source. - - final String subscriberId; - if (isNetworkTypeMobile(type)) { - final TelephonyManager telephony = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - subscriberId = telephony.getSubscriberId(); - } else { - subscriberId = null; - } - return new NetworkIdentity(type, subType, subscriberId); - } - - private static void writeOptionalString(DataOutputStream out, String value) throws IOException { - if (value != null) { - out.writeByte(1); - out.writeUTF(value); - } else { - out.writeByte(0); - } - } - - private static String readOptionalString(DataInputStream in) throws IOException { - if (in.readByte() != 0) { - return in.readUTF(); - } else { - return null; - } - } - -} diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/java/com/android/server/net/NetworkIdentitySet.java new file mode 100644 index 000000000000..757d3bc92f14 --- /dev/null +++ b/services/java/com/android/server/net/NetworkIdentitySet.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import android.net.NetworkIdentity; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.ProtocolException; +import java.util.HashSet; + +/** + * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} + * active on that interface. + * + * @hide + */ +public class NetworkIdentitySet extends HashSet { + private static final int VERSION_INIT = 1; + + public NetworkIdentitySet() { + } + + public NetworkIdentitySet(DataInputStream in) throws IOException { + final int version = in.readInt(); + switch (version) { + case VERSION_INIT: { + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + final int ignoredVersion = in.readInt(); + final int type = in.readInt(); + final int subType = in.readInt(); + final String subscriberId = readOptionalString(in); + add(new NetworkIdentity(type, subType, subscriberId)); + } + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } + } + + public void writeToStream(DataOutputStream out) throws IOException { + out.writeInt(VERSION_INIT); + out.writeInt(size()); + for (NetworkIdentity ident : this) { + out.writeInt(VERSION_INIT); + out.writeInt(ident.getType()); + out.writeInt(ident.getSubType()); + writeOptionalString(out, ident.getSubscriberId()); + } + } + + private static void writeOptionalString(DataOutputStream out, String value) throws IOException { + if (value != null) { + out.writeByte(1); + out.writeUTF(value); + } else { + out.writeByte(0); + } + } + + private static String readOptionalString(DataInputStream in) throws IOException { + if (in.readByte() != 0) { + return in.readUTF(); + } else { + return null; + } + } +} diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 43f3c63cdc07..ada9ba4202e0 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.READ_PHONE_STATE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicyManager.ACTION_DATA_USAGE_LIMIT; @@ -36,10 +37,9 @@ import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.dumpPolicy; import static android.net.NetworkPolicyManager.dumpRules; import static android.net.NetworkPolicyManager.isUidValidForPolicy; -import static android.net.TrafficStats.TEMPLATE_MOBILE_3G_LOWER; -import static android.net.TrafficStats.TEMPLATE_MOBILE_4G; -import static android.net.TrafficStats.TEMPLATE_MOBILE_ALL; -import static android.net.TrafficStats.isNetworkTemplateMobile; +import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; +import static android.net.NetworkTemplate.MATCH_MOBILE_4G; +import static android.net.NetworkTemplate.MATCH_MOBILE_ALL; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; @@ -61,9 +61,11 @@ import android.net.IConnectivityManager; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; +import android.net.NetworkIdentity; import android.net.NetworkPolicy; import android.net.NetworkState; import android.net.NetworkStats; +import android.net.NetworkTemplate; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -84,7 +86,6 @@ import android.util.Xml; import com.android.internal.R; import com.android.internal.os.AtomicFile; import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.Objects; import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -353,10 +354,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long total; try { final NetworkStats stats = mNetworkStats.getSummaryForNetwork( - start, end, policy.networkTemplate, policy.subscriberId); + policy.template, start, end); total = stats.rx[0] + stats.tx[0]; } catch (RemoteException e) { - Slog.w(TAG, "problem reading summary for template " + policy.networkTemplate); + Slog.w(TAG, "problem reading summary for template " + policy.template); continue; } @@ -380,8 +381,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * notification of a specific type, like {@link #TYPE_LIMIT}. */ private String buildNotificationTag(NetworkPolicy policy, int type) { - // TODO: consider splicing subscriberId hash into mix - return TAG + ":" + policy.networkTemplate + ":" + type; + return TAG + ":" + policy.template.hashCode() + ":" + type; } /** @@ -408,7 +408,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final Intent intent = new Intent(ACTION_DATA_USAGE_WARNING); intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.networkTemplate); + intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule()); builder.setContentIntent(PendingIntent.getActivity( mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); break; @@ -416,11 +416,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case TYPE_LIMIT: { final String title; final String body = res.getString(R.string.data_usage_limit_body); - switch (policy.networkTemplate) { - case TEMPLATE_MOBILE_3G_LOWER: + switch (policy.template.getMatchRule()) { + case MATCH_MOBILE_3G_LOWER: title = res.getString(R.string.data_usage_3g_limit_title); break; - case TEMPLATE_MOBILE_4G: + case MATCH_MOBILE_4G: title = res.getString(R.string.data_usage_4g_limit_title); break; default: @@ -435,7 +435,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final Intent intent = new Intent(ACTION_DATA_USAGE_LIMIT); intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.networkTemplate); + intent.putExtra(EXTRA_NETWORK_TEMPLATE, policy.template.getMatchRule()); builder.setContentIntent(PendingIntent.getActivity( mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); break; @@ -521,7 +521,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // collect all active ifaces that match this template ifaceList.clear(); for (NetworkIdentity ident : networks.keySet()) { - if (ident.matchesTemplate(policy.networkTemplate, policy.subscriberId)) { + if (policy.template.matches(ident)) { final String iface = networks.get(ident); ifaceList.add(iface); } @@ -554,11 +554,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final NetworkStats stats; final long total; try { - stats = mNetworkStats.getSummaryForNetwork( - start, end, policy.networkTemplate, policy.subscriberId); + stats = mNetworkStats.getSummaryForNetwork(policy.template, start, end); total = stats.rx[0] + stats.tx[0]; } catch (RemoteException e) { - Slog.w(TAG, "problem reading summary for template " + policy.networkTemplate); + Slog.w(TAG, "problem reading summary for template " + policy.template); continue; } @@ -603,12 +602,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void ensureActiveMobilePolicyLocked() { if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()"); final String subscriberId = getActiveSubscriberId(); + final NetworkIdentity probeIdent = new NetworkIdentity( + TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId); // examine to see if any policy is defined for active mobile boolean mobileDefined = false; for (NetworkPolicy policy : mNetworkPolicy) { - if (isNetworkTemplateMobile(policy.networkTemplate) - && Objects.equal(subscriberId, policy.subscriberId)) { + if (policy.template.matches(probeIdent)) { mobileDefined = true; } } @@ -624,8 +624,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { time.setToNow(); final int cycleDay = time.monthDay; - mNetworkPolicy.add(new NetworkPolicy( - TEMPLATE_MOBILE_ALL, subscriberId, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED)); + final NetworkTemplate template = new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId); + mNetworkPolicy.add( + new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED)); writePolicyLocked(); } } @@ -658,8 +659,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES); final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES); - mNetworkPolicy.add(new NetworkPolicy( - networkTemplate, subscriberId, cycleDay, warningBytes, limitBytes)); + final NetworkTemplate template = new NetworkTemplate( + networkTemplate, subscriberId); + mNetworkPolicy.add( + new NetworkPolicy(template, cycleDay, warningBytes, limitBytes)); } else if (TAG_UID_POLICY.equals(tag)) { final int uid = readIntAttribute(in, ATTR_UID); @@ -701,10 +704,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // write all known network policies for (NetworkPolicy policy : mNetworkPolicy) { + final NetworkTemplate template = policy.template; + out.startTag(null, TAG_NETWORK_POLICY); - writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, policy.networkTemplate); - if (policy.subscriberId != null) { - out.attribute(null, ATTR_SUBSCRIBER_ID, policy.subscriberId); + writeIntAttribute(out, ATTR_NETWORK_TEMPLATE, template.getMatchRule()); + final String subscriberId = template.getSubscriberId(); + if (subscriberId != null) { + out.attribute(null, ATTR_SUBSCRIBER_ID, subscriberId); } writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay); writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 0a84bc73729b..54a806a02df2 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.SHUTDOWN; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; @@ -45,10 +46,12 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.net.IConnectivityManager; import android.net.INetworkStatsService; +import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -63,8 +66,8 @@ import android.util.SparseArray; import android.util.TrustedTime; import com.android.internal.os.AtomicFile; -import com.google.android.collect.Lists; import com.google.android.collect.Maps; +import com.google.android.collect.Sets; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -76,9 +79,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.ProtocolException; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import libcore.io.IoUtils; @@ -93,7 +96,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** File header magic number: "ANET" */ private static final int FILE_MAGIC = 0x414E4554; - private static final int VERSION_CURRENT = 1; + private static final int VERSION_NETWORK_INIT = 1; + private static final int VERSION_UID_INIT = 1; + private static final int VERSION_UID_WITH_IDENT = 2; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -112,6 +117,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; // TODO: listen for kernel push events through netd instead of polling + // TODO: watch for UID uninstall, and transfer stats into single bucket private static final long KB_IN_BYTES = 1024; private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; @@ -132,13 +138,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Object mStatsLock = new Object(); - /** Set of active ifaces during this boot. */ - private HashMap mActiveIface = Maps.newHashMap(); - - /** Set of historical stats for known ifaces. */ - private HashMap mNetworkStats = Maps.newHashMap(); + /** Set of currently active ifaces. */ + private HashMap mActiveIfaces = Maps.newHashMap(); + /** Set of historical stats for known networks. */ + private HashMap mNetworkStats = Maps.newHashMap(); /** Set of historical stats for known UIDs. */ - private SparseArray mUidStats = new SparseArray(); + private HashMap> mUidStats = + Maps.newHashMap(); /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; @@ -251,17 +257,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForNetwork(int networkTemplate) { + public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { // combine all interfaces that match template - final String subscriberId = getActiveSubscriberId(); final NetworkStatsHistory combined = new NetworkStatsHistory( mSettings.getNetworkBucketDuration(), estimateNetworkBuckets()); - for (InterfaceIdentity ident : mNetworkStats.keySet()) { - final NetworkStatsHistory history = mNetworkStats.get(ident); - if (ident.matchesTemplate(networkTemplate, subscriberId)) { + for (NetworkIdentitySet ident : mNetworkStats.keySet()) { + if (templateMatches(template, ident)) { + final NetworkStatsHistory history = mNetworkStats.get(ident); combined.recordEntireHistory(history); } } @@ -270,19 +275,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) { + public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { - // TODO: combine based on template, if we store that granularity ensureUidStatsLoadedLocked(); - return mUidStats.get(uid); + + // combine all interfaces that match template + final NetworkStatsHistory combined = new NetworkStatsHistory( + mSettings.getUidBucketDuration(), estimateUidBuckets()); + for (NetworkIdentitySet ident : mUidStats.keySet()) { + if (templateMatches(template, ident)) { + final NetworkStatsHistory history = mUidStats.get(ident).get(uid); + if (history != null) { + combined.recordEntireHistory(history); + } + } + } + return combined; } } @Override - public NetworkStats getSummaryForNetwork( - long start, long end, int networkTemplate, String subscriberId) { + public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { @@ -291,9 +306,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { long[] networkTotal = new long[2]; // combine total from all interfaces that match template - for (InterfaceIdentity ident : mNetworkStats.keySet()) { - final NetworkStatsHistory history = mNetworkStats.get(ident); - if (ident.matchesTemplate(networkTemplate, subscriberId)) { + for (NetworkIdentitySet ident : mNetworkStats.keySet()) { + if (templateMatches(template, ident)) { + final NetworkStatsHistory history = mNetworkStats.get(ident); networkTotal = history.getTotalData(start, end, networkTotal); rx += networkTotal[0]; tx += networkTotal[1]; @@ -301,30 +316,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addEntry(IFACE_ALL, UID_ALL, rx, tx); + stats.addEntry(IFACE_ALL, UID_ALL, TAG_NONE, rx, tx); return stats; } } @Override - public NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate) { + public NetworkStats getSummaryForAllUid(NetworkTemplate template, long start, long end) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - // TODO: apply networktemplate once granular uid stats are stored. - synchronized (mStatsLock) { ensureUidStatsLoadedLocked(); - final int size = mUidStats.size(); - final NetworkStats stats = new NetworkStats(end - start, size); - + final NetworkStats stats = new NetworkStats(end - start, 24); long[] total = new long[2]; - for (int i = 0; i < size; i++) { - final int uid = mUidStats.keyAt(i); - final NetworkStatsHistory history = mUidStats.valueAt(i); - total = history.getTotalData(start, end, total); - stats.addEntry(IFACE_ALL, uid, total[0], total[1]); + + for (NetworkIdentitySet ident : mUidStats.keySet()) { + if (templateMatches(template, ident)) { + final SparseArray uidStats = mUidStats.get(ident); + for (int i = 0; i < uidStats.size(); i++) { + final int uid = uidStats.keyAt(i); + final NetworkStatsHistory history = uidStats.valueAt(i); + total = history.getTotalData(start, end, total); + stats.combineEntry(IFACE_ALL, uid, TAG_NONE, total[0], total[1]); + } + } } + return stats; } } @@ -352,7 +370,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // permission above. synchronized (mStatsLock) { // TODO: acquire wakelock while performing poll - performPollLocked(true); + performPollLocked(true, false); } } }; @@ -371,7 +389,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Inspect all current {@link NetworkState} to derive mapping from {@code * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} * are active on a single {@code iface}, they are combined under a single - * {@link InterfaceIdentity}. + * {@link NetworkIdentitySet}. */ private void updateIfacesLocked() { if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -379,7 +397,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // take one last stats snapshot before updating iface mapping. this // isn't perfect, since the kernel may already be counting traffic from // the updated network. - performPollLocked(false); + performPollLocked(false, false); final NetworkState[] states; try { @@ -390,13 +408,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // rebuild active interfaces based on connected networks - mActiveIface.clear(); + mActiveIfaces.clear(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { // collect networks under their parent interfaces final String iface = state.linkProperties.getInterfaceName(); - final InterfaceIdentity ident = findOrCreateInterfaceLocked(iface); + + NetworkIdentitySet ident = mActiveIfaces.get(iface); + if (ident == null) { + ident = new NetworkIdentitySet(); + mActiveIfaces.put(iface, ident); + } + ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state)); } } @@ -409,7 +433,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * @param detailedPoll Indicate if detailed UID stats should be collected * during this poll operation. */ - private void performPollLocked(boolean detailedPoll) { + private void performPollLocked(boolean detailedPoll, boolean forcePersist) { if (LOGV) Slog.v(TAG, "performPollLocked()"); // try refreshing time source when stale @@ -421,33 +445,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final NetworkStats networkStats; + final NetworkStats ifaceStats; final NetworkStats uidStats; try { - networkStats = mNetworkManager.getNetworkStatsSummary(); + ifaceStats = mNetworkManager.getNetworkStatsSummary(); uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; } catch (RemoteException e) { Slog.w(TAG, "problem reading network stats"); return; } - performNetworkPollLocked(networkStats, currentTime); + performNetworkPollLocked(ifaceStats, currentTime); if (detailedPoll) { performUidPollLocked(uidStats, currentTime); } // decide if enough has changed to trigger persist - final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, networkStats); + final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, ifaceStats); final long persistThreshold = mSettings.getPersistThreshold(); for (String iface : persistDelta.getUniqueIfaces()) { - final int index = persistDelta.findIndex(iface, UID_ALL); - if (persistDelta.rx[index] > persistThreshold + final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE); + if (forcePersist || persistDelta.rx[index] > persistThreshold || persistDelta.tx[index] > persistThreshold) { writeNetworkStatsLocked(); if (mUidStatsLoaded) { writeUidStatsLocked(); } - mLastNetworkPersist = networkStats; + mLastNetworkPersist = ifaceStats; break; } } @@ -462,23 +486,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Update {@link #mNetworkStats} historical usage. */ private void performNetworkPollLocked(NetworkStats networkStats, long currentTime) { - final ArrayList unknownIface = Lists.newArrayList(); + final HashSet unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta(mLastNetworkPoll, networkStats); final long timeStart = currentTime - delta.elapsedRealtime; final long maxHistory = mSettings.getNetworkMaxHistory(); - for (String iface : delta.getUniqueIfaces()) { - final InterfaceIdentity ident = mActiveIface.get(iface); + for (int i = 0; i < delta.size; i++) { + final String iface = delta.iface[i]; + final NetworkIdentitySet ident = mActiveIfaces.get(iface); if (ident == null) { unknownIface.add(iface); continue; } - final int index = delta.findIndex(iface, UID_ALL); - final long rx = delta.rx[index]; - final long tx = delta.tx[index]; + final long rx = delta.rx[i]; + final long tx = delta.tx[i]; - final NetworkStatsHistory history = findOrCreateNetworkLocked(ident); + final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident); history.recordData(timeStart, currentTime, rx, tx); history.removeBucketsBefore(currentTime - maxHistory); } @@ -498,22 +522,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats); final long timeStart = currentTime - delta.elapsedRealtime; final long maxHistory = mSettings.getUidMaxHistory(); - for (int uid : delta.getUniqueUids()) { - // TODO: traverse all ifaces once surfaced in stats - final int index = delta.findIndex(IFACE_ALL, uid); - if (index != -1) { - final long rx = delta.rx[index]; - final long tx = delta.tx[index]; - - final NetworkStatsHistory history = findOrCreateUidLocked(uid); - history.recordData(timeStart, currentTime, rx, tx); - history.removeBucketsBefore(currentTime - maxHistory); + + // NOTE: historical UID stats ignore tags, and simply records all stats + // entries into a single UID bucket. + + for (int i = 0; i < delta.size; i++) { + final String iface = delta.iface[i]; + final NetworkIdentitySet ident = mActiveIfaces.get(iface); + if (ident == null) { + continue; } + + final int uid = delta.uid[i]; + final long rx = delta.rx[i]; + final long tx = delta.tx[i]; + + final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid); + history.recordData(timeStart, currentTime, rx, tx); + history.removeBucketsBefore(currentTime - maxHistory); } + mLastUidPoll = uidStats; } - private NetworkStatsHistory findOrCreateNetworkLocked(InterfaceIdentity ident) { + private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) { final long bucketDuration = mSettings.getNetworkBucketDuration(); final NetworkStatsHistory existing = mNetworkStats.get(ident); @@ -535,9 +567,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private NetworkStatsHistory findOrCreateUidLocked(int uid) { + private NetworkStatsHistory findOrCreateUidStatsLocked(NetworkIdentitySet ident, int uid) { + // find bucket for identity first, then find uid + SparseArray uidStats = mUidStats.get(ident); + if (uidStats == null) { + uidStats = new SparseArray(); + mUidStats.put(ident, uidStats); + } + final long bucketDuration = mSettings.getUidBucketDuration(); - final NetworkStatsHistory existing = mUidStats.get(uid); + final NetworkStatsHistory existing = uidStats.get(uid); // update when no existing, or when bucket duration changed NetworkStatsHistory updated = null; @@ -550,22 +589,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (updated != null) { - mUidStats.put(uid, updated); + uidStats.put(uid, updated); return updated; } else { return existing; } } - private InterfaceIdentity findOrCreateInterfaceLocked(String iface) { - InterfaceIdentity ident = mActiveIface.get(iface); - if (ident == null) { - ident = new InterfaceIdentity(); - mActiveIface.put(iface, ident); - } - return ident; - } - private void readNetworkStatsLocked() { if (LOGV) Slog.v(TAG, "readNetworkStatsLocked()"); @@ -585,15 +615,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int version = in.readInt(); switch (version) { - case VERSION_CURRENT: { - // file format is pairs of interfaces and stats: - // network := size *(InterfaceIdentity NetworkStatsHistory) - + case VERSION_NETWORK_INIT: { + // network := size *(NetworkIdentitySet NetworkStatsHistory) final int size = in.readInt(); for (int i = 0; i < size; i++) { - final InterfaceIdentity ident = new InterfaceIdentity(in); + final NetworkIdentitySet ident = new NetworkIdentitySet(in); final NetworkStatsHistory history = new NetworkStatsHistory(in); - mNetworkStats.put(ident, history); } break; @@ -637,16 +664,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int version = in.readInt(); switch (version) { - case VERSION_CURRENT: { - // file format is pairs of UIDs and stats: + case VERSION_UID_INIT: { // uid := size *(UID NetworkStatsHistory) - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final int uid = in.readInt(); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - - mUidStats.put(uid, history); + // drop this data version, since we don't have a good + // mapping into NetworkIdentitySet. + break; + } + case VERSION_UID_WITH_IDENT: { + // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) + final int ifaceSize = in.readInt(); + for (int i = 0; i < ifaceSize; i++) { + final NetworkIdentitySet ident = new NetworkIdentitySet(in); + + final int uidSize = in.readInt(); + final SparseArray uidStats = new SparseArray< + NetworkStatsHistory>(uidSize); + for (int j = 0; j < uidSize; j++) { + final int uid = in.readInt(); + final NetworkStatsHistory history = new NetworkStatsHistory(in); + uidStats.put(uid, history); + } + + mUidStats.put(ident, uidStats); } break; } @@ -674,10 +714,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final DataOutputStream out = new DataOutputStream(fos); out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_CURRENT); + out.writeInt(VERSION_NETWORK_INIT); out.writeInt(mNetworkStats.size()); - for (InterfaceIdentity ident : mNetworkStats.keySet()) { + for (NetworkIdentitySet ident : mNetworkStats.keySet()) { final NetworkStatsHistory history = mNetworkStats.get(ident); ident.writeToStream(out); history.writeToStream(out); @@ -702,16 +742,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final DataOutputStream out = new DataOutputStream(fos); out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_CURRENT); + out.writeInt(VERSION_UID_WITH_IDENT); - final int size = mUidStats.size(); + out.writeInt(mUidStats.size()); + for (NetworkIdentitySet ident : mUidStats.keySet()) { + final SparseArray uidStats = mUidStats.get(ident); + ident.writeToStream(out); - out.writeInt(size); - for (int i = 0; i < size; i++) { - final int uid = mUidStats.keyAt(i); - final NetworkStatsHistory history = mUidStats.valueAt(i); - out.writeInt(uid); - history.writeToStream(out); + final int size = uidStats.size(); + out.writeInt(size); + for (int i = 0; i < size; i++) { + final int uid = uidStats.keyAt(i); + final NetworkStatsHistory history = uidStats.valueAt(i); + out.writeInt(uid); + history.writeToStream(out); + } } mUidFile.finishWrite(fos); @@ -740,35 +785,41 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (argSet.contains("poll")) { - performPollLocked(true); + performPollLocked(true, true); pw.println("Forced poll"); return; } pw.println("Active interfaces:"); - for (String iface : mActiveIface.keySet()) { - final InterfaceIdentity ident = mActiveIface.get(iface); + for (String iface : mActiveIfaces.keySet()) { + final NetworkIdentitySet ident = mActiveIfaces.get(iface); pw.print(" iface="); pw.print(iface); pw.print(" ident="); pw.println(ident.toString()); } pw.println("Known historical stats:"); - for (InterfaceIdentity ident : mNetworkStats.keySet()) { - final NetworkStatsHistory stats = mNetworkStats.get(ident); + for (NetworkIdentitySet ident : mNetworkStats.keySet()) { + final NetworkStatsHistory history = mNetworkStats.get(ident); pw.print(" ident="); pw.println(ident.toString()); - stats.dump(" ", pw); + history.dump(" ", pw); } if (argSet.contains("detail")) { // since explicitly requested with argument, we're okay to load // from disk if not already in memory. ensureUidStatsLoadedLocked(); - pw.println("Known UID stats:"); - for (int i = 0; i < mUidStats.size(); i++) { - final int uid = mUidStats.keyAt(i); - final NetworkStatsHistory stats = mUidStats.valueAt(i); - pw.print(" UID="); pw.println(uid); - stats.dump(" ", pw); + + pw.println("Detailed UID stats:"); + for (NetworkIdentitySet ident : mUidStats.keySet()) { + pw.print(" ident="); pw.println(ident.toString()); + + final SparseArray uidStats = mUidStats.get(ident); + for (int i = 0; i < uidStats.size(); i++) { + final int uid = uidStats.keyAt(i); + final NetworkStatsHistory history = uidStats.valueAt(i); + pw.print(" UID="); pw.println(uid); + history.dump(" ", pw); + } } } } @@ -779,27 +830,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @Deprecated private void generateRandomLocked() { - long end = System.currentTimeMillis(); - long start = end - mSettings.getNetworkMaxHistory(); - long rx = 3 * GB_IN_BYTES; - long tx = 2 * GB_IN_BYTES; + long networkEnd = System.currentTimeMillis(); + long networkStart = networkEnd - mSettings.getNetworkMaxHistory(); + long networkRx = 3 * GB_IN_BYTES; + long networkTx = 2 * GB_IN_BYTES; - mNetworkStats.clear(); - for (InterfaceIdentity ident : mActiveIface.values()) { - final NetworkStatsHistory stats = findOrCreateNetworkLocked(ident); - stats.generateRandom(start, end, rx, tx); - } + long uidEnd = System.currentTimeMillis(); + long uidStart = uidEnd - mSettings.getUidMaxHistory(); + long uidRx = 500 * MB_IN_BYTES; + long uidTx = 100 * MB_IN_BYTES; - end = System.currentTimeMillis(); - start = end - mSettings.getUidMaxHistory(); - rx = 500 * MB_IN_BYTES; - tx = 100 * MB_IN_BYTES; + final List installedApps = mContext + .getPackageManager().getInstalledApplications(0); + mNetworkStats.clear(); mUidStats.clear(); - for (ApplicationInfo info : mContext.getPackageManager().getInstalledApplications(0)) { - final int uid = info.uid; - final NetworkStatsHistory stats = findOrCreateUidLocked(uid); - stats.generateRandom(start, end, rx, tx); + for (NetworkIdentitySet ident : mActiveIfaces.values()) { + findOrCreateNetworkStatsLocked(ident).generateRandom( + networkStart, networkEnd, networkRx, networkTx); + + for (ApplicationInfo info : installedApps) { + final int uid = info.uid; + findOrCreateUidStatsLocked(ident, uid).generateRandom( + uidStart, uidEnd, uidRx, uidTx); + } } } @@ -815,12 +869,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private String getActiveSubscriberId() { - final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService( - Context.TELEPHONY_SERVICE); - return telephony.getSubscriberId(); - } - private int estimateNetworkBuckets() { return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration()); } @@ -833,6 +881,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration); } + /** + * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} + * in the given {@link NetworkIdentitySet}. + */ + private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) { + for (NetworkIdentity ident : identSet) { + if (template.matches(ident)) { + return true; + } + } + return false; + } + /** * Default external settings that read from {@link Settings.Secure}. */ diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 5cb1763f21f4..b62687a6176b 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -23,8 +23,9 @@ import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; +import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.TEMPLATE_WIFI; +import static android.net.NetworkTemplate.MATCH_WIFI; import static org.easymock.EasyMock.anyInt; import static org.easymock.EasyMock.aryEq; import static org.easymock.EasyMock.capture; @@ -49,6 +50,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkPolicy; import android.net.NetworkState; import android.net.NetworkStats; +import android.net.NetworkTemplate; import android.os.Binder; import android.os.IPowerManager; import android.test.AndroidTestCase; @@ -76,6 +78,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { private static final long TEST_START = 1194220800000L; private static final String TEST_IFACE = "test0"; + private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null); + private BroadcastInterceptingContext mServiceContext; private File mPolicyDir; @@ -305,7 +309,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final long currentTime = parseTime("2007-11-14T00:00:00.000Z"); final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z"); - final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 5, 1024L, 1024L); + final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 5, 1024L, 1024L); final long actualCycle = computeLastCycleBoundary(currentTime, policy); assertEquals(expectedCycle, actualCycle); } @@ -315,7 +319,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final long currentTime = parseTime("2007-11-14T00:00:00.000Z"); final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z"); - final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 20, 1024L, 1024L); + final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 20, 1024L, 1024L); final long actualCycle = computeLastCycleBoundary(currentTime, policy); assertEquals(expectedCycle, actualCycle); } @@ -325,7 +329,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final long currentTime = parseTime("2007-02-14T00:00:00.000Z"); final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z"); - final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 30, 1024L, 1024L); + final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 30, 1024L, 1024L); final long actualCycle = computeLastCycleBoundary(currentTime, policy); assertEquals(expectedCycle, actualCycle); } @@ -335,7 +339,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final long currentTime = parseTime("2007-03-14T00:00:00.000Z"); final long expectedCycle = parseTime("2007-03-01T00:00:00.000Z"); - final NetworkPolicy policy = new NetworkPolicy(TEMPLATE_WIFI, null, 30, 1024L, 1024L); + final NetworkPolicy policy = new NetworkPolicy(sTemplateWifi, 30, 1024L, 1024L); final long actualCycle = computeLastCycleBoundary(currentTime, policy); assertEquals(expectedCycle, actualCycle); } @@ -367,8 +371,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { // pretend that 512 bytes total have happened stats = new NetworkStats(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 256L, 256L); - expect(mStatsService.getSummaryForNetwork(TIME_FEB_15, TIME_MAR_10, TEMPLATE_WIFI, null)) + .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 256L, 256L); + expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10)) .andReturn(stats).atLeastOnce(); // expect that quota remaining should be 1536 bytes @@ -378,7 +382,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { expectMeteredIfacesChanged(TEST_IFACE); replay(); - setNetworkPolicies(new NetworkPolicy(TEMPLATE_WIFI, null, CYCLE_DAY, 1024L, 2048L)); + setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1024L, 2048L)); verifyAndReset(); } diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 2457ff3eb0da..1d2634c1f870 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -18,9 +18,9 @@ package com.android.server; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.TEMPLATE_WIFI; +import static android.net.NetworkTemplate.MATCH_WIFI; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -44,6 +44,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; import android.os.INetworkManagementService; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; @@ -66,6 +67,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { private static final String TEST_IFACE = "test0"; private static final long TEST_START = 1194220800000L; + private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null); + private static final int TEST_UID_1 = 1001; private static final int TEST_UID_2 = 1002; @@ -138,7 +141,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); // verify service has empty history for wifi - assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); + assertNetworkTotal(sTemplateWifi, 0L, 0L); verifyAndReset(); // modify some number on wifi, and trigger poll event @@ -146,14 +149,14 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectTime(TEST_START + elapsedRealtime); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L)); + .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 2048L)); expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); // verify service recorded history - assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); + assertNetworkTotal(sTemplateWifi, 1024L, 2048L); verifyAndReset(); // and bump forward again, with counters going higher. this is @@ -162,14 +165,14 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectTime(TEST_START + elapsedRealtime); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 4096L, 8192L)); + .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 4096L, 8192L)); expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); // verify service recorded history - assertNetworkTotal(TEMPLATE_WIFI, 4096L, 8192L); + assertNetworkTotal(sTemplateWifi, 4096L, 8192L); verifyAndReset(); } @@ -189,7 +192,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); // verify service has empty history for wifi - assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); + assertNetworkTotal(sTemplateWifi, 0L, 0L); verifyAndReset(); // modify some number on wifi, and trigger poll event @@ -197,19 +200,18 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectTime(TEST_START + elapsedRealtime); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 1024L, 2048L)); - // TODO: switch these stats to specific iface + .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 2048L)); expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 2) - .addEntry(IFACE_ALL, TEST_UID_1, 512L, 256L) - .addEntry(IFACE_ALL, TEST_UID_2, 128L, 128L)); + .addEntry(TEST_IFACE, TEST_UID_1, TAG_NONE, 512L, 256L) + .addEntry(TEST_IFACE, TEST_UID_2, TAG_NONE, 128L, 128L)); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); // verify service recorded history - assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); - assertUidTotal(TEST_UID_1, TEMPLATE_WIFI, 512L, 256L); - assertUidTotal(TEST_UID_2, TEMPLATE_WIFI, 128L, 128L); + assertNetworkTotal(sTemplateWifi, 1024L, 2048L); + assertUidTotal(sTemplateWifi, TEST_UID_1, 512L, 256L); + assertUidTotal(sTemplateWifi, TEST_UID_2, 128L, 128L); verifyAndReset(); // graceful shutdown system, which should trigger persist of stats, and @@ -220,7 +222,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { // we persisted them to file. expectDefaultSettings(); replay(); - assertNetworkTotal(TEMPLATE_WIFI, 0L, 0L); + assertNetworkTotal(sTemplateWifi, 0L, 0L); verifyAndReset(); assertStatsFilesExist(true); @@ -233,9 +235,9 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mService.systemReady(); // after systemReady(), we should have historical stats loaded again - assertNetworkTotal(TEMPLATE_WIFI, 1024L, 2048L); - assertUidTotal(TEST_UID_1, TEMPLATE_WIFI, 512L, 256L); - assertUidTotal(TEST_UID_2, TEMPLATE_WIFI, 128L, 128L); + assertNetworkTotal(sTemplateWifi, 1024L, 2048L); + assertUidTotal(sTemplateWifi, TEST_UID_1, 512L, 256L); + assertUidTotal(sTemplateWifi, TEST_UID_2, 128L, 128L); verifyAndReset(); } @@ -263,14 +265,14 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectTime(TEST_START + elapsedRealtime); expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1) - .addEntry(TEST_IFACE, UID_ALL, 512L, 512L)); + .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 512L, 512L)); expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime)); replay(); mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); // verify service recorded history - history = mService.getHistoryForNetwork(TEMPLATE_WIFI); + history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null)); total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(512L, total[0]); assertEquals(512L, total[1]); @@ -289,7 +291,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); // verify identical stats, but spread across 4 buckets now - history = mService.getHistoryForNetwork(TEMPLATE_WIFI); + history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null)); total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(512L, total[0]); assertEquals(512L, total[1]); @@ -299,15 +301,15 @@ public class NetworkStatsServiceTest extends AndroidTestCase { } - private void assertNetworkTotal(int template, long rx, long tx) { + private void assertNetworkTotal(NetworkTemplate template, long rx, long tx) { final NetworkStatsHistory history = mService.getHistoryForNetwork(template); final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(rx, total[0]); assertEquals(tx, total[1]); } - private void assertUidTotal(int uid, int template, long rx, long tx) { - final NetworkStatsHistory history = mService.getHistoryForUid(uid, template); + private void assertUidTotal(NetworkTemplate template, int uid, long rx, long tx) { + final NetworkStatsHistory history = mService.getHistoryForUid(template, uid); final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null); assertEquals(rx, total[0]); assertEquals(tx, total[1]); diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java index 30afdd81fa56..2f275c373f4b 100644 --- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java @@ -289,7 +289,7 @@ public class ThrottleServiceTest extends AndroidTestCase { public void expectGetInterfaceCounter(long rx, long tx) throws Exception { // TODO: provide elapsedRealtime mock to match TimeAuthority final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); - stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx); + stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, NetworkStats.TAG_NONE, rx, tx); expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats).atLeastOnce(); } -- cgit v1.2.3-59-g8ed1b