From 7e3859251fca8d16b00af49dc5bec7a575936ea6 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 30 Mar 2016 11:14:39 -0700 Subject: [PATCH] Excluded certain APNs (e.g. IMS) from mobile data usage. Added not_metered capability to a mobile network if none of its associated APN types are metered. Also used not_metered capability to determine if a network should be accounted for data usage or not instead of using network type, which is always MOBILE after refactoring. Will add VT usage support in next phase. bug: 20888836 Change-Id: Id692cb856be9a47d0e918371112630128965b1bb --- core/java/android/net/NetworkIdentity.java | 24 +++++++++++++++---- core/java/android/net/NetworkTemplate.java | 21 ++++------------ .../server/net/NetworkIdentitySet.java | 18 ++++++++++++-- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index a9de23ef1b..9cd563e87c 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -55,19 +55,22 @@ public class NetworkIdentity implements Comparable { final String mSubscriberId; final String mNetworkId; final boolean mRoaming; + final boolean mMetered; public NetworkIdentity( - int type, int subType, String subscriberId, String networkId, boolean roaming) { + int type, int subType, String subscriberId, String networkId, boolean roaming, + boolean metered) { mType = type; mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; mSubscriberId = subscriberId; mNetworkId = networkId; mRoaming = roaming; + mMetered = metered; } @Override public int hashCode() { - return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming); + return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered); } @Override @@ -76,7 +79,8 @@ public class NetworkIdentity implements Comparable { final NetworkIdentity ident = (NetworkIdentity) obj; return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming && Objects.equals(mSubscriberId, ident.mSubscriberId) - && Objects.equals(mNetworkId, ident.mNetworkId); + && Objects.equals(mNetworkId, ident.mNetworkId) + && mMetered == ident.mMetered; } return false; } @@ -102,6 +106,7 @@ public class NetworkIdentity implements Comparable { if (mRoaming) { builder.append(", ROAMING"); } + builder.append(", metered=").append(mMetered); return builder.append("}").toString(); } @@ -125,6 +130,10 @@ public class NetworkIdentity implements Comparable { return mRoaming; } + public boolean getMetered() { + return mMetered; + } + /** * Scrub given IMSI on production builds. */ @@ -162,6 +171,7 @@ public class NetworkIdentity implements Comparable { String subscriberId = null; String networkId = null; boolean roaming = false; + boolean metered = false; if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { @@ -171,6 +181,9 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; roaming = state.networkInfo.isRoaming(); + metered = !state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; @@ -182,7 +195,7 @@ public class NetworkIdentity implements Comparable { } } - return new NetworkIdentity(type, subType, subscriberId, networkId, roaming); + return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered); } @Override @@ -200,6 +213,9 @@ public class NetworkIdentity implements Comparable { if (res == 0) { res = Boolean.compare(mRoaming, another.mRoaming); } + if (res == 0) { + res = Boolean.compare(mMetered, another.mMetered); + } return res; } } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b32b2ccd76..caf79829db 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -19,6 +19,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_PROXY; +import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; @@ -30,9 +31,6 @@ import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; import static android.telephony.TelephonyManager.getNetworkClass; -import static com.android.internal.util.ArrayUtils.contains; - -import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; @@ -71,16 +69,6 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; - /** - * Set of {@link NetworkInfo#getType()} that reflect data usage. - */ - private static final int[] DATA_USAGE_NETWORK_TYPES; - - static { - DATA_USAGE_NETWORK_TYPES = Resources.getSystem().getIntArray( - com.android.internal.R.array.config_data_usage_network_types); - } - private static boolean sForceAllNetworkTypes = false; @VisibleForTesting @@ -318,9 +306,8 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - final boolean matchesType = (sForceAllNetworkTypes - || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)); - return matchesType && !ArrayUtils.isEmpty(mMatchSubscriberIds) + return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); } } @@ -389,7 +376,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType); + return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered); } } diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 68dc715b08..959a823290 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -23,6 +23,8 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.HashSet; +import static android.net.ConnectivityManager.TYPE_MOBILE; + /** * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} * active on that interface. @@ -34,6 +36,7 @@ public class NetworkIdentitySet extends HashSet implements private static final int VERSION_INIT = 1; private static final int VERSION_ADD_ROAMING = 2; private static final int VERSION_ADD_NETWORK_ID = 3; + private static final int VERSION_ADD_METERED = 4; public NetworkIdentitySet() { } @@ -61,12 +64,22 @@ public class NetworkIdentitySet extends HashSet implements roaming = false; } - add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming)); + final boolean metered; + if (version >= VERSION_ADD_METERED) { + metered = in.readBoolean(); + } else { + // If this is the old data and the type is mobile, treat it as metered. (Note that + // if this is a mobile network, TYPE_MOBILE is the only possible type that could be + // used.) + metered = (type == TYPE_MOBILE); + } + + add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered)); } } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_ADD_NETWORK_ID); + out.writeInt(VERSION_ADD_METERED); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); @@ -74,6 +87,7 @@ public class NetworkIdentitySet extends HashSet implements writeOptionalString(out, ident.getSubscriberId()); writeOptionalString(out, ident.getNetworkId()); out.writeBoolean(ident.getRoaming()); + out.writeBoolean(ident.getMetered()); } }