diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d36707e4cb..6864749875 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.telephony.TelephonyManager; +import android.util.Slog; import java.util.Objects; @@ -35,6 +36,8 @@ import java.util.Objects; * @hide */ public class NetworkIdentity implements Comparable { + private static final String TAG = "NetworkIdentity"; + /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. @@ -132,6 +135,18 @@ public class NetworkIdentity implements Comparable { } } + /** + * Scrub given IMSI on production builds. + */ + public static String[] scrubSubscriberId(String[] subscriberId) { + if (subscriberId == null) return null; + final String[] res = new String[subscriberId.length]; + for (int i = 0; i < res.length; i++) { + res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]); + } + return res; + } + /** * Build a {@link NetworkIdentity} from the given {@link NetworkState}, * assuming that any mobile networks are using the current IMSI. @@ -140,23 +155,18 @@ public class NetworkIdentity implements Comparable { 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. - String subscriberId = null; String networkId = null; boolean roaming = false; if (isNetworkTypeMobile(type)) { - final TelephonyManager telephony = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - roaming = telephony.isNetworkRoaming(); - if (state.subscriberId != null) { - subscriberId = state.subscriberId; - } else { - subscriberId = telephony.getSubscriberId(); + if (state.subscriberId == null) { + Slog.w(TAG, "Active mobile network without subscriber!"); } + subscriberId = state.subscriberId; + roaming = state.networkInfo.isRoaming(); + } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b839e0ac69..6cfab92360 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -22,7 +22,6 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; -import static android.net.NetworkIdentity.scrubSubscriberId; import static android.net.wifi.WifiInfo.removeDoubleQuotes; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; @@ -36,7 +35,9 @@ import android.os.Parcel; import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import java.util.Arrays; import java.util.Objects; /** @@ -146,17 +147,35 @@ public class NetworkTemplate implements Parcelable { private final int mMatchRule; private final String mSubscriberId; + + /** + * Ugh, templates are designed to target a single subscriber, but we might + * need to match several "merged" subscribers. These are the subscribers + * that should be considered to match this template. + *

+ * Since the merge set is dynamic, it should not be persisted or + * used for determining equality. + */ + private final String[] mMatchSubscriberIds; + private final String mNetworkId; public NetworkTemplate(int matchRule, String subscriberId, String networkId) { + this(matchRule, subscriberId, new String[] { subscriberId }, networkId); + } + + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId) { mMatchRule = matchRule; mSubscriberId = subscriberId; + mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; } private NetworkTemplate(Parcel in) { mMatchRule = in.readInt(); mSubscriberId = in.readString(); + mMatchSubscriberIds = in.createStringArray(); mNetworkId = in.readString(); } @@ -164,6 +183,7 @@ public class NetworkTemplate implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mMatchRule); dest.writeString(mSubscriberId); + dest.writeStringArray(mMatchSubscriberIds); dest.writeString(mNetworkId); } @@ -177,7 +197,12 @@ public class NetworkTemplate implements Parcelable { final StringBuilder builder = new StringBuilder("NetworkTemplate: "); builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); if (mSubscriberId != null) { - builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId)); + builder.append(", subscriberId=").append( + NetworkIdentity.scrubSubscriberId(mSubscriberId)); + } + if (mMatchSubscriberIds != null) { + builder.append(", matchSubscriberIds=").append( + Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds))); } if (mNetworkId != null) { builder.append(", networkId=").append(mNetworkId); @@ -201,6 +226,18 @@ public class NetworkTemplate implements Parcelable { return false; } + public boolean isMatchRuleMobile() { + switch (mMatchRule) { + case MATCH_MOBILE_3G_LOWER: + case MATCH_MOBILE_4G: + case MATCH_MOBILE_ALL: + case MATCH_MOBILE_WILDCARD: + return true; + default: + return false; + } + } + public int getMatchRule() { return mMatchRule; } @@ -247,8 +284,9 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)) - && Objects.equals(mSubscriberId, ident.mSubscriberId)); + final boolean matchesType = (sForceAllNetworkTypes + || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)); + return matchesType && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); } } @@ -368,6 +406,27 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Examine the given template and normalize if it refers to a "merged" + * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * for key purposes, and expand the template to match all other merged + * subscribers. + *

+ * For example, given an incoming template matching B, and the currently + * active merge set [A,B], we'd return a new template that primarily matches + * A, but also matches B. + */ + public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { + if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) { + // Requested template subscriber is part of the merge group; return + // a template that matches all merged subscribers. + return new NetworkTemplate(template.mMatchRule, merged[0], merged, + template.mNetworkId); + } else { + return template; + } + } + public static final Creator CREATOR = new Creator() { @Override public NetworkTemplate createFromParcel(Parcel in) {