Merge "Read "qtaguid" network stats, refactor templates."
This commit is contained in:
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
107
core/java/android/net/NetworkIdentity.java
Normal file
107
core/java/android/net/NetworkIdentity.java
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<NetworkPolicy> {
|
||||
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<NetworkPolicy> {
|
||||
|
||||
/** {@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<NetworkPolicy> {
|
||||
|
||||
@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<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
19
core/java/android/net/NetworkTemplate.aidl
Normal file
19
core/java/android/net/NetworkTemplate.aidl
Normal file
@@ -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;
|
||||
217
core/java/android/net/NetworkTemplate.java
Normal file
217
core/java/android/net/NetworkTemplate.java
Normal file
@@ -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<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
|
||||
public NetworkTemplate createFromParcel(Parcel in) {
|
||||
return new NetworkTemplate(in);
|
||||
}
|
||||
|
||||
public NetworkTemplate[] newArray(int size) {
|
||||
return new NetworkTemplate[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
.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));
|
||||
assertEquals(2, stats.findIndex(TEST_IFACE, 102));
|
||||
assertEquals(0, stats.findIndex(TEST_IFACE, 100));
|
||||
assertEquals(-1, stats.findIndex(TEST_IFACE, 6));
|
||||
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]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.net;
|
||||
|
||||
import android.net.NetworkIdentity;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -28,19 +30,23 @@ import java.util.HashSet;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class InterfaceIdentity extends HashSet<NetworkIdentity> {
|
||||
private static final int VERSION_CURRENT = 1;
|
||||
public class NetworkIdentitySet extends HashSet<NetworkIdentity> {
|
||||
private static final int VERSION_INIT = 1;
|
||||
|
||||
public InterfaceIdentity() {
|
||||
public NetworkIdentitySet() {
|
||||
}
|
||||
|
||||
public InterfaceIdentity(DataInputStream in) throws IOException {
|
||||
public NetworkIdentitySet(DataInputStream in) throws IOException {
|
||||
final int version = in.readInt();
|
||||
switch (version) {
|
||||
case VERSION_CURRENT: {
|
||||
case VERSION_INIT: {
|
||||
final int size = in.readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
add(new NetworkIdentity(in));
|
||||
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;
|
||||
}
|
||||
@@ -51,23 +57,30 @@ public class InterfaceIdentity extends HashSet<NetworkIdentity> {
|
||||
}
|
||||
|
||||
public void writeToStream(DataOutputStream out) throws IOException {
|
||||
out.writeInt(VERSION_CURRENT);
|
||||
out.writeInt(VERSION_INIT);
|
||||
out.writeInt(size());
|
||||
for (NetworkIdentity ident : this) {
|
||||
ident.writeToStream(out);
|
||||
out.writeInt(VERSION_INIT);
|
||||
out.writeInt(ident.getType());
|
||||
out.writeInt(ident.getSubType());
|
||||
writeOptionalString(out, ident.getSubscriberId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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<String, InterfaceIdentity> mActiveIface = Maps.newHashMap();
|
||||
|
||||
/** Set of historical stats for known ifaces. */
|
||||
private HashMap<InterfaceIdentity, NetworkStatsHistory> mNetworkStats = Maps.newHashMap();
|
||||
/** Set of currently active ifaces. */
|
||||
private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
|
||||
/** Set of historical stats for known networks. */
|
||||
private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkStats = Maps.newHashMap();
|
||||
/** Set of historical stats for known UIDs. */
|
||||
private SparseArray<NetworkStatsHistory> mUidStats = new SparseArray<NetworkStatsHistory>();
|
||||
private HashMap<NetworkIdentitySet, SparseArray<NetworkStatsHistory>> 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<NetworkStatsHistory> 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<String> unknownIface = Lists.newArrayList();
|
||||
final HashSet<String> 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<NetworkStatsHistory> uidStats = mUidStats.get(ident);
|
||||
if (uidStats == null) {
|
||||
uidStats = new SparseArray<NetworkStatsHistory>();
|
||||
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);
|
||||
// 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);
|
||||
|
||||
mUidStats.put(uid, history);
|
||||
final int uidSize = in.readInt();
|
||||
final SparseArray<NetworkStatsHistory> 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<NetworkStatsHistory> 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<NetworkStatsHistory> 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;
|
||||
|
||||
long uidEnd = System.currentTimeMillis();
|
||||
long uidStart = uidEnd - mSettings.getUidMaxHistory();
|
||||
long uidRx = 500 * MB_IN_BYTES;
|
||||
long uidTx = 100 * MB_IN_BYTES;
|
||||
|
||||
final List<ApplicationInfo> installedApps = mContext
|
||||
.getPackageManager().getInstalledApplications(0);
|
||||
|
||||
mNetworkStats.clear();
|
||||
for (InterfaceIdentity ident : mActiveIface.values()) {
|
||||
final NetworkStatsHistory stats = findOrCreateNetworkLocked(ident);
|
||||
stats.generateRandom(start, end, rx, tx);
|
||||
}
|
||||
|
||||
end = System.currentTimeMillis();
|
||||
start = end - mSettings.getUidMaxHistory();
|
||||
rx = 500 * MB_IN_BYTES;
|
||||
tx = 100 * MB_IN_BYTES;
|
||||
|
||||
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}.
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user