From b2cd0b9e578086e13758f2d3a2f778206b836bd3 Mon Sep 17 00:00:00 2001 From: lesl Date: Thu, 31 Dec 2020 17:26:28 +0800 Subject: [PATCH] wifi data usage: support to get carrier merged wifi network. Carrier merged wifi network is a specific cerrier wifi network which provides the same user experience as mobile. To support data usage accounting for carrier merged wifi, the change provide several APIs in NetworkTemplate: 1. extend buildTemplateWifi so it could be used for matching wifi networks with subscriber Id (IMSI). 2. add buildTemplateCarrier to let NetworkPolicyManagerService creates a single policy for a given carrier regardless of network type. Bug: 176396812 Test: atest -c NetworkTemplateTest Test: atest -c NetworkStatsServiceTest Test: Manual Test with test code on mobile and wifi network. 1. buildTemplateCarrier includes the carrier wifi and mobile usage 2. buildTemplateWifi can get carrier wifi usage and support the filter via subscriberId Change-Id: I667b4adf3eec0bdd3a7385109dd8c1fae8e7be32 --- core/java/android/net/NetworkTemplate.java | 160 +++++++++++++++++++-- 1 file changed, 147 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index c83dd99c2a..d3c8957494 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -82,6 +82,24 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_WIFI_WILDCARD = 7; public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + public static final int MATCH_CARRIER = 10; + + /** + * Value of the match rule of the subscriberId to match networks with specific subscriberId. + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; + /** + * Value of the match rule of the subscriberId to match networks with any subscriberId which + * includes null and non-null. + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; + + /** + * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that + * should be fixed), so it's not possible to want to match null vs + * non-null. Therefore it's fine to use null as a sentinel for Network ID. + */ + public static final String WIFI_NETWORKID_ALL = null; /** * Include all network types when filtering. This is meant to merge in with the @@ -125,6 +143,7 @@ public class NetworkTemplate implements Parcelable { case MATCH_WIFI_WILDCARD: case MATCH_BLUETOOTH: case MATCH_PROXY: + case MATCH_CARRIER: return true; default: @@ -168,10 +187,12 @@ public class NetworkTemplate implements Parcelable { @NetworkType int ratType) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -189,6 +210,8 @@ public class NetworkTemplate implements Parcelable { */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifiWildcard() { + // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL + // and SUBSCRIBER_ID_MATCH_RULE_ALL. return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } @@ -202,8 +225,27 @@ public class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the * given SSID. */ - public static NetworkTemplate buildTemplateWifi(String networkId) { - return new NetworkTemplate(MATCH_WIFI, null, networkId); + public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) { + Objects.requireNonNull(networkId); + return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */, + new String[] { null } /* matchSubscriberIds */, + networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_ALL); + } + + /** + * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID, + * and IMSI. + * + * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID. + */ + public static NetworkTemplate buildTemplateWifi(@Nullable String networkId, + @Nullable String subscriberId) { + return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, + networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -231,6 +273,14 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_PROXY, null, null); } + /** + * Template to match all carrier networks with the given IMSI. + */ + public static NetworkTemplate buildTemplateCarrier(@NonNull String subscriberId) { + Objects.requireNonNull(subscriberId); + return new NetworkTemplate(MATCH_CARRIER, subscriberId, null); + } + private final int mMatchRule; private final String mSubscriberId; @@ -251,10 +301,26 @@ public class NetworkTemplate implements Parcelable { private final int mRoaming; private final int mDefaultNetwork; private final int mSubType; + private final int mSubscriberIdMatchRule; // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. private final int mOemManaged; + private void checkValidSubscriberIdMatchRule() { + switch (mMatchRule) { + case MATCH_MOBILE: + case MATCH_CARRIER: + // MOBILE and CARRIER templates must always specify a subscriber ID. + if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + throw new IllegalArgumentException("Invalid SubscriberIdMatchRule" + + "on match rule: " + getMatchRuleName(mMatchRule)); + } + return; + default: + return; + } + } + @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -263,14 +329,25 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); + } + + // TODO: Remove it after updating all of the caller. + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId, int metered, int roaming, int defaultNetwork, int subType, + int oemManaged) { + this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming, + defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, - int oemManaged) { + int oemManaged, int subscriberIdMatchRule) { mMatchRule = matchRule; mSubscriberId = subscriberId; + // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when + // mSubscriberId is null mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; mMetered = metered; @@ -278,7 +355,8 @@ public class NetworkTemplate implements Parcelable { mDefaultNetwork = defaultNetwork; mSubType = subType; mOemManaged = oemManaged; - + mSubscriberIdMatchRule = subscriberIdMatchRule; + checkValidSubscriberIdMatchRule(); if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule + " will not match any identity."); @@ -295,6 +373,7 @@ public class NetworkTemplate implements Parcelable { mDefaultNetwork = in.readInt(); mSubType = in.readInt(); mOemManaged = in.readInt(); + mSubscriberIdMatchRule = in.readInt(); } @Override @@ -308,6 +387,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mDefaultNetwork); dest.writeInt(mSubType); dest.writeInt(mOemManaged); + dest.writeInt(mSubscriberIdMatchRule); } @Override @@ -346,13 +426,15 @@ public class NetworkTemplate implements Parcelable { if (mOemManaged != OEM_MANAGED_ALL) { builder.append(", oemManaged=").append(mOemManaged); } + builder.append(", subscriberIdMatchRule=") + .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule)); return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork, mSubType, mOemManaged); + mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule); } @Override @@ -366,11 +448,23 @@ public class NetworkTemplate implements Parcelable { && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork && mSubType == other.mSubType - && mOemManaged == other.mOemManaged; + && mOemManaged == other.mOemManaged + && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule; } return false; } + private String subscriberIdMatchRuleToString(int rule) { + switch (rule) { + case SUBSCRIBER_ID_MATCH_RULE_EXACT: + return "EXACT_MATCH"; + case SUBSCRIBER_ID_MATCH_RULE_ALL: + return "ALL"; + default: + return "Unknown rule " + rule; + } + } + public boolean isMatchRuleMobile() { switch (mMatchRule) { case MATCH_MOBILE: @@ -386,6 +480,14 @@ public class NetworkTemplate implements Parcelable { case MATCH_MOBILE_WILDCARD: case MATCH_WIFI_WILDCARD: return false; + case MATCH_CARRIER: + return mSubscriberId != null; + case MATCH_WIFI: + if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + return false; + } + return true; default: return true; } @@ -405,6 +507,10 @@ public class NetworkTemplate implements Parcelable { return mNetworkId; } + public int getSubscriberIdMatchRule() { + return mSubscriberIdMatchRule; + } + /** * Test if given {@link NetworkIdentity} matches this template. */ @@ -429,6 +535,8 @@ public class NetworkTemplate implements Parcelable { return matchesBluetooth(ident); case MATCH_PROXY: return matchesProxy(ident); + case MATCH_CARRIER: + return matchesCarrier(ident); default: // We have no idea what kind of network template we are, so we // just claim not to match anything. @@ -466,8 +574,23 @@ public class NetworkTemplate implements Parcelable { || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); } - public boolean matchesSubscriberId(String subscriberId) { - return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + /** + * Check if this template matches {@code subscriberId}. Returns true if this + * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a + * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. + */ + public boolean matchesSubscriberId(@Nullable String subscriberId) { + return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL + || ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + } + + /** + * Check if network with matching SSID. Returns true when the SSID matches, or when + * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}. + */ + private boolean matchesWifiNetworkId(@Nullable String networkId) { + return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId)); } /** @@ -566,8 +689,8 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: - return Objects.equals( - sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); + return matchesSubscriberId(ident.mSubscriberId) + && matchesWifiNetworkId(ident.mNetworkId); default: return false; } @@ -583,6 +706,15 @@ public class NetworkTemplate implements Parcelable { return false; } + /** + * Check if matches carrier network. The carrier networks means it includes the subscriberId. + */ + private boolean matchesCarrier(NetworkIdentity ident) { + return ident.mSubscriberId != null + && !ArrayUtils.isEmpty(mMatchSubscriberIds) + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + } + private boolean matchesMobileWildcard(NetworkIdentity ident) { if (ident.mType == TYPE_WIMAX) { return true; @@ -635,6 +767,8 @@ public class NetworkTemplate implements Parcelable { return "BLUETOOTH"; case MATCH_PROXY: return "PROXY"; + case MATCH_CARRIER: + return "CARRIER"; default: return "UNKNOWN(" + matchRule + ")"; }