diff options
14 files changed, 267 insertions, 223 deletions
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 802121093a64..d9921a6df0f9 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -68,9 +68,6 @@ interface IConnectivityManager boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); - /** Policy control over specific {@link NetworkStateTracker}. */ - void setPolicyDataEnable(int networkType, boolean enabled); - int tether(String iface); int untether(String iface); diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d36707e4cb35..68647498755f 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<NetworkIdentity> { + private static final String TAG = "NetworkIdentity"; + /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. @@ -133,6 +136,18 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { } /** + * 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<NetworkIdentity> { 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/NetworkMisc.java b/core/java/android/net/NetworkMisc.java index 5d2a43d0f3c9..b92c9e3c5d9f 100644 --- a/core/java/android/net/NetworkMisc.java +++ b/core/java/android/net/NetworkMisc.java @@ -20,15 +20,18 @@ import android.os.Parcel; import android.os.Parcelable; /** - * A grab-bag of information (metadata, policies, properties, etc) about a {@link Network}. + * A grab-bag of information (metadata, policies, properties, etc) about a + * {@link Network}. Since this contains PII, it should not be sent outside the + * system. * * @hide */ public class NetworkMisc implements Parcelable { /** - * If the {@link Network} is a VPN, whether apps are allowed to bypass the VPN. This is set by - * a {@link VpnService} and used by {@link ConnectivityService} when creating a VPN. + * If the {@link Network} is a VPN, whether apps are allowed to bypass the + * VPN. This is set by a {@link VpnService} and used by + * {@link ConnectivityManager} when creating a VPN. */ public boolean allowBypass; @@ -41,6 +44,11 @@ public class NetworkMisc implements Parcelable { */ public boolean explicitlySelected; + /** + * For mobile networks, this is the subscriber ID (such as IMSI). + */ + public String subscriberId; + public NetworkMisc() { } @@ -48,6 +56,7 @@ public class NetworkMisc implements Parcelable { if (nm != null) { allowBypass = nm.allowBypass; explicitlySelected = nm.explicitlySelected; + subscriberId = nm.subscriberId; } } @@ -60,6 +69,7 @@ public class NetworkMisc implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(allowBypass ? 1 : 0); out.writeInt(explicitlySelected ? 1 : 0); + out.writeString(subscriberId); } public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() { @@ -68,6 +78,7 @@ public class NetworkMisc implements Parcelable { NetworkMisc networkMisc = new NetworkMisc(); networkMisc.allowBypass = in.readInt() != 0; networkMisc.explicitlySelected = in.readInt() != 0; + networkMisc.subscriberId = in.readString(); return networkMisc; } diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 10c686b9e211..e88bc26851e7 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -35,7 +35,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { public static final long LIMIT_DISABLED = -1; public static final long SNOOZE_NEVER = -1; - public final NetworkTemplate template; + public NetworkTemplate template; public int cycleDay; public String cycleTimezone; public long warningBytes; diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index d26c70d5569f..933287f6341f 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -30,16 +30,10 @@ public class NetworkState implements Parcelable { public final LinkProperties linkProperties; public final NetworkCapabilities networkCapabilities; public final Network network; - /** Currently only used by testing. */ public final String subscriberId; public final String networkId; public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - NetworkCapabilities networkCapabilities, Network network) { - this(networkInfo, linkProperties, networkCapabilities, network, null, null); - } - - public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, Network network, String subscriberId, String networkId) { this.networkInfo = networkInfo; @@ -85,5 +79,4 @@ public class NetworkState implements Parcelable { return new NetworkState[size]; } }; - } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b839e0ac69a2..6cfab92360f6 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. + * <p> + * Since the merge set is dynamic, it should <em>not</em> 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. + * <p> + * 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<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() { @Override public NetworkTemplate createFromParcel(Parcel in) { diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 8e786da7cf7e..f908fcbd99eb 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -128,6 +128,20 @@ public class ArrayUtils } /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(int[] array) { + return array == null || array.length == 0; + } + + /** + * Checks if given array is null or has zero elements. + */ + public static boolean isEmpty(long[] array) { + return array == null || array.length == 0; + } + + /** * Checks that value is present as at least one of the elements of the array. * @param array the array to check in * @param value the value to check for @@ -157,6 +171,7 @@ public class ArrayUtils * Test if all {@code check} items are contained in {@code array}. */ public static <T> boolean containsAll(T[] array, T[] check) { + if (check == null) return true; for (T checkItem : check) { if (!contains(array, checkItem)) { return false; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 9c0e486af7f6..dde158cdddd9 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -20,22 +20,8 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; -import static android.net.ConnectivityManager.TYPE_BLUETOOTH; -import static android.net.ConnectivityManager.TYPE_DUMMY; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_MOBILE_CBS; -import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; -import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; -import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; -import static android.net.ConnectivityManager.TYPE_MOBILE_IA; -import static android.net.ConnectivityManager.TYPE_MOBILE_IMS; -import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; -import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; import static android.net.ConnectivityManager.TYPE_NONE; -import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_VPN; -import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; @@ -45,11 +31,9 @@ import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; -import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; @@ -62,7 +46,6 @@ import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; -import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; @@ -72,7 +55,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkFactory; import android.net.NetworkMisc; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; @@ -80,16 +62,12 @@ import android.net.NetworkState; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; -import android.net.ProxyDataTracker; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.SamplingDataTracker; import android.net.UidRange; import android.net.Uri; -import android.net.wimax.WimaxManagerConstants; -import android.os.AsyncTask; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.FileUtils; import android.os.Handler; @@ -103,7 +81,6 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; @@ -126,9 +103,6 @@ import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; @@ -146,8 +120,6 @@ import com.android.server.net.LockdownVpnTracker; import com.google.android.collect.Lists; import com.google.android.collect.Sets; -import dalvik.system.DexClassLoader; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -157,31 +129,20 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; -import java.lang.reflect.Constructor; -import java.net.HttpURLConnection; import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; -import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Random; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSession; - /** * @hide */ @@ -328,12 +289,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11; /** - * Used internally to - * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}. - */ - private static final int EVENT_SET_POLICY_DATA_ENABLE = 12; - - /** * Used internally to disable fail fast of mobile data */ private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14; @@ -850,6 +805,7 @@ public class ConnectivityService extends IConnectivityManager.Stub LinkProperties lp = null; NetworkCapabilities nc = null; Network network = null; + String subscriberId = null; if (mLegacyTypeTracker.isTypeSupported(networkType)) { NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); @@ -859,6 +815,7 @@ public class ConnectivityService extends IConnectivityManager.Stub lp = new LinkProperties(nai.linkProperties); nc = new NetworkCapabilities(nai.networkCapabilities); network = new Network(nai.network); + subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null; } info.setType(networkType); } else { @@ -872,7 +829,7 @@ public class ConnectivityService extends IConnectivityManager.Stub info = getFilteredNetworkInfo(info, lp, uid); } - return new NetworkState(info, lp, nc, network); + return new NetworkState(info, lp, nc, network, subscriberId, null); } private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) { @@ -889,6 +846,7 @@ public class ConnectivityService extends IConnectivityManager.Stub LinkProperties lp = null; NetworkCapabilities nc = null; Network network = null; + String subscriberId = null; NetworkAgentInfo nai = mNetworkForRequestId.get(mDefaultRequest.requestId); @@ -920,10 +878,11 @@ public class ConnectivityService extends IConnectivityManager.Stub lp = new LinkProperties(nai.linkProperties); nc = new NetworkCapabilities(nai.networkCapabilities); network = new Network(nai.network); + subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null; } } - return new NetworkState(info, lp, nc, network); + return new NetworkState(info, lp, nc, network, subscriberId, null); } /** @@ -1220,14 +1179,19 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkState[] getAllNetworkState() { - enforceAccessPermission(); - final int uid = Binder.getCallingUid(); + // Require internal since we're handing out IMSI details + enforceConnectivityInternalPermission(); + final ArrayList<NetworkState> result = Lists.newArrayList(); - for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE; - networkType++) { - NetworkState state = getFilteredNetworkState(networkType, uid); - if (state.networkInfo != null) { - result.add(state); + for (Network network : getAllNetworks()) { + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai != null) { + synchronized (nai) { + final String subscriberId = (nai.networkMisc != null) + ? nai.networkMisc.subscriberId : null; + result.add(new NetworkState(nai.networkInfo, nai.linkProperties, + nai.networkCapabilities, network, subscriberId, null)); + } } } return result.toArray(new NetworkState[result.size()]); @@ -1452,25 +1416,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } }; - @Override - public void setPolicyDataEnable(int networkType, boolean enabled) { - // only someone like NPMS should only be calling us - mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - - mHandler.sendMessage(mHandler.obtainMessage( - EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED))); - } - - private void handleSetPolicyDataEnable(int networkType, boolean enabled) { - // TODO - handle this passing to factories -// if (isNetworkTypeValid(networkType)) { -// final NetworkStateTracker tracker = mNetTrackers[networkType]; -// if (tracker != null) { -// tracker.setPolicyDataEnable(enabled); -// } -// } - } - private void enforceInternetPermission() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERNET, @@ -2457,12 +2402,6 @@ public class ConnectivityService extends IConnectivityManager.Stub sendStickyBroadcast(intent); break; } - case EVENT_SET_POLICY_DATA_ENABLE: { - final int networkType = msg.arg1; - final boolean enabled = msg.arg2 == ENABLED; - handleSetPolicyDataEnable(networkType, enabled); - break; - } case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: { int tag = mEnableFailFastMobileDataTag.get(); if (msg.arg1 == tag) { @@ -3858,7 +3797,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mNumDnsEntries = last; } - private void updateCapabilities(NetworkAgentInfo networkAgent, NetworkCapabilities networkCapabilities) { if (!Objects.equals(networkAgent.networkCapabilities, networkCapabilities)) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index cf194165b0af..2be591b39002 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -120,7 +120,9 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.text.format.Formatter; import android.text.format.Time; import android.util.ArrayMap; @@ -136,16 +138,17 @@ import android.util.SparseIntArray; import android.util.TrustedTime; import android.util.Xml; +import libcore.io.IoUtils; + import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.google.android.collect.Lists; -import libcore.io.IoUtils; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -160,7 +163,6 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; /** * Service that maintains low-level network policy rules, using @@ -253,38 +255,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private final boolean mSuppressDefaultPolicy; /** Defined network policies. */ - final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap< - NetworkTemplate, NetworkPolicy>(); + final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>(); /** Currently active network rules for ifaces. */ - private final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap< - NetworkPolicy, String[]>(); + final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<>(); /** Defined UID policies. */ final SparseIntArray mUidPolicy = new SparseIntArray(); /** Currently derived rules for each UID. */ - private final SparseIntArray mUidRules = new SparseIntArray(); + final SparseIntArray mUidRules = new SparseIntArray(); - /** UIDs that have been white-listed to always be able to have network access in - * power save mode. */ + /** + * UIDs that have been white-listed to always be able to have network access + * in power save mode. + */ private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray(); /** Set of ifaces that are metered. */ - private ArraySet<String> mMeteredIfaces = new ArraySet<String>(); + private ArraySet<String> mMeteredIfaces = new ArraySet<>(); /** Set of over-limit templates that have been notified. */ - private final ArraySet<NetworkTemplate> mOverLimitNotified = new ArraySet<NetworkTemplate>(); + private final ArraySet<NetworkTemplate> mOverLimitNotified = new ArraySet<>(); /** Set of currently active {@link Notification} tags. */ private final ArraySet<String> mActiveNotifs = new ArraySet<String>(); /** Foreground at both UID and PID granularity. */ - private final SparseIntArray mUidState = new SparseIntArray(); - final SparseArray<SparseIntArray> mUidPidState = new SparseArray<SparseIntArray>(); + final SparseIntArray mUidState = new SparseIntArray(); + final SparseArray<SparseIntArray> mUidPidState = new SparseArray<>(); /** The current maximum process state that we are considering to be foreground. */ private int mCurForegroundState = ActivityManager.PROCESS_STATE_TOP; - private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList< - INetworkPolicyListener>(); + private final RemoteCallbackList<INetworkPolicyListener> + mListeners = new RemoteCallbackList<>(); final Handler mHandler; @@ -740,21 +742,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * data connection status. */ private boolean isTemplateRelevant(NetworkTemplate template) { - final TelephonyManager tele = TelephonyManager.from(mContext); - - switch (template.getMatchRule()) { - case MATCH_MOBILE_3G_LOWER: - case MATCH_MOBILE_4G: - case MATCH_MOBILE_ALL: - // mobile templates are relevant when SIM is ready and - // subscriberId matches. - if (tele.getSimState() == SIM_STATE_READY) { - return Objects.equals(tele.getSubscriberId(), template.getSubscriberId()); - } else { - return false; + if (template.isMatchRuleMobile()) { + final TelephonyManager tele = TelephonyManager.from(mContext); + final SubscriptionManager sub = SubscriptionManager.from(mContext); + + // Mobile template is relevant when any active subscriber matches + final int[] subIds = sub.getActiveSubscriptionIdList(); + for (int subId : subIds) { + final String subscriberId = tele.getSubscriberId(subId); + final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, + TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false); + if (template.matches(probeIdent)) { + return true; } + } + return false; + } else { + return true; } - return true; } /** @@ -961,6 +966,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { maybeRefreshTrustedTime(); synchronized (mRulesLock) { ensureActiveMobilePolicyLocked(); + normalizePoliciesLocked(); updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); @@ -1001,33 +1007,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)} - * for the given {@link NetworkTemplate}. + * Proactively disable networks that match the given + * {@link NetworkTemplate}. */ private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) { - final TelephonyManager tele = TelephonyManager.from(mContext); - - switch (template.getMatchRule()) { - case MATCH_MOBILE_3G_LOWER: - case MATCH_MOBILE_4G: - case MATCH_MOBILE_ALL: - // TODO: offer more granular control over radio states once - // 4965893 is available. - if (tele.getSimState() == SIM_STATE_READY - && Objects.equals(tele.getSubscriberId(), template.getSubscriberId())) { - setPolicyDataEnable(TYPE_MOBILE, enabled); - setPolicyDataEnable(TYPE_WIMAX, enabled); - } - break; - case MATCH_WIFI: - setPolicyDataEnable(TYPE_WIFI, enabled); - break; - case MATCH_ETHERNET: - setPolicyDataEnable(TYPE_ETHERNET, enabled); - break; - default: - throw new IllegalArgumentException("unexpected template"); - } + // TODO: reach into ConnectivityManager to proactively disable bringing + // up this network, since we know that traffic will be blocked. } /** @@ -1036,7 +1021,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * remaining quota based on usage cycle and historical stats. */ void updateNetworkRulesLocked() { - if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); + if (LOGV) Slog.v(TAG, "updateNetworkRulesLocked()"); final NetworkState[] states; try { @@ -1203,42 +1188,47 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (mSuppressDefaultPolicy) return; final TelephonyManager tele = TelephonyManager.from(mContext); + final SubscriptionManager sub = SubscriptionManager.from(mContext); - // avoid creating policy when SIM isn't ready - if (tele.getSimState() != SIM_STATE_READY) return; - - final String subscriberId = tele.getSubscriberId(); - final NetworkIdentity probeIdent = new NetworkIdentity( - TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false); + final int[] subIds = sub.getActiveSubscriptionIdList(); + for (int subId : subIds) { + final String subscriberId = tele.getSubscriberId(subId); + ensureActiveMobilePolicyLocked(subscriberId); + } + } - // examine to see if any policy is defined for active mobile - boolean mobileDefined = false; - for (int i = mNetworkPolicy.size()-1; i >= 0; i--) { - if (mNetworkPolicy.valueAt(i).template.matches(probeIdent)) { - mobileDefined = true; - break; + private void ensureActiveMobilePolicyLocked(String subscriberId) { + // Poke around to see if we already have a policy + final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, + TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false); + for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) { + final NetworkTemplate template = mNetworkPolicy.keyAt(i); + if (template.matches(probeIdent)) { + if (LOGD) { + Slog.d(TAG, "Found template " + template + " which matches subscriber " + + NetworkIdentity.scrubSubscriberId(subscriberId)); + } + return; } } - if (!mobileDefined) { - Slog.i(TAG, "no policy for active mobile network; generating default policy"); + Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId) + + "; generating default policy"); - // build default mobile policy, and assume usage cycle starts today - final long warningBytes = mContext.getResources().getInteger( - com.android.internal.R.integer.config_networkPolicyDefaultWarning) - * MB_IN_BYTES; + // Build default mobile policy, and assume usage cycle starts today + final long warningBytes = mContext.getResources().getInteger( + com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES; - final Time time = new Time(); - time.setToNow(); + final Time time = new Time(); + time.setToNow(); - final int cycleDay = time.monthDay; - final String cycleTimezone = time.timezone; + final int cycleDay = time.monthDay; + final String cycleTimezone = time.timezone; - final NetworkTemplate template = buildTemplateMobileAll(subscriberId); - final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone, - warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true); - addNetworkPolicyLocked(policy); - } + final NetworkTemplate template = buildTemplateMobileAll(subscriberId); + final NetworkPolicy policy = new NetworkPolicy(template, cycleDay, cycleTimezone, + warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true); + addNetworkPolicyLocked(policy); } private void readPolicyLocked() { @@ -1321,8 +1311,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { inferred = false; } - final NetworkTemplate template = new NetworkTemplate( - networkTemplate, subscriberId, networkId); + final NetworkTemplate template = new NetworkTemplate(networkTemplate, + subscriberId, networkId); mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, cycleTimezone, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred)); @@ -1593,11 +1583,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { maybeRefreshTrustedTime(); synchronized (mRulesLock) { - mNetworkPolicy.clear(); - for (NetworkPolicy policy : policies) { - mNetworkPolicy.put(policy.template, policy); - } - + normalizePoliciesLocked(policies); updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); @@ -1606,12 +1592,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } void addNetworkPolicyLocked(NetworkPolicy policy) { - mNetworkPolicy.put(policy.template, policy); - - updateNetworkEnabledLocked(); - updateNetworkRulesLocked(); - updateNotificationsLocked(); - writePolicyLocked(); + NetworkPolicy[] policies = getNetworkPolicies(); + policies = ArrayUtils.appendElement(NetworkPolicy.class, policies, policy); + setNetworkPolicies(policies); } @Override @@ -1620,7 +1603,35 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG); synchronized (mRulesLock) { - return mNetworkPolicy.values().toArray(new NetworkPolicy[mNetworkPolicy.size()]); + final int size = mNetworkPolicy.size(); + final NetworkPolicy[] policies = new NetworkPolicy[size]; + for (int i = 0; i < size; i++) { + policies[i] = mNetworkPolicy.valueAt(i); + } + return policies; + } + } + + private void normalizePoliciesLocked() { + normalizePoliciesLocked(getNetworkPolicies()); + } + + private void normalizePoliciesLocked(NetworkPolicy[] policies) { + final TelephonyManager tele = TelephonyManager.from(mContext); + final String[] merged = tele.getMergedSubscriberIds(); + + mNetworkPolicy.clear(); + for (NetworkPolicy policy : policies) { + // When two normalized templates conflict, prefer the most + // restrictive policy + policy.template = NetworkTemplate.normalize(policy.template, merged); + final NetworkPolicy existing = mNetworkPolicy.get(policy.template); + if (existing == null || existing.compareTo(policy) > 0) { + if (existing != null) { + Slog.d(TAG, "Normalization replaced " + existing + " with " + policy); + } + mNetworkPolicy.put(policy.template, policy); + } } } @@ -1657,6 +1668,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { throw new IllegalArgumentException("unexpected type"); } + normalizePoliciesLocked(); updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); @@ -1784,6 +1796,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mNetworkPolicy.valueAt(i).clearSnooze(); } + normalizePoliciesLocked(); updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); @@ -1976,6 +1989,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // If the set of restricted networks may have changed, re-evaluate those. if (restrictedNetworksChanged) { + normalizePoliciesLocked(); updateNetworkRulesLocked(); } } @@ -2162,17 +2176,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - /** - * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}. - */ - private void setPolicyDataEnable(int networkType, boolean enabled) { - try { - mConnManager.setPolicyDataEnable(networkType, enabled); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - } - private long getTotalBytes(NetworkTemplate template, long start, long end) { try { return mNetworkStats.getNetworkTotalBytes(template, start, end); diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index b74716fdcdda..0b4d42e0a172 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -916,10 +916,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } private Future<Void> expectPolicyDataEnable(int type, boolean enabled) throws Exception { - final FutureAnswer future = new FutureAnswer(); - mConnManager.setPolicyDataEnable(type, enabled); - expectLastCall().andAnswer(future); - return future; + // TODO: bring back this test + return null; } private void expectAdvisePersistThreshold() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index f9a03fc36fab..7383478c44eb 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -1023,7 +1023,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { info.setDetailedState(DetailedState.CONNECTED, null, null); final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(iface); - return new NetworkState(info, prop, null, null); + return new NetworkState(info, prop, null, null, null, null); } private NetworkStats buildEmptyStats() { diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index abf1ead8eef6..20cd0373d81e 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; @@ -1064,7 +1065,7 @@ public class SubscriptionManager { * is never null but the length maybe 0. * @hide */ - public int[] getActiveSubscriptionIdList() { + public @NonNull int[] getActiveSubscriptionIdList() { int[] subId = null; try { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 751e11b74890..83bf04fec734 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -40,6 +41,7 @@ import com.android.internal.telephony.TelephonyProperties; import java.io.FileInputStream; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1879,6 +1881,23 @@ public class TelephonyManager { } /** + * Return the set of subscriber IDs that should be considered as "merged + * together" for data usage purposes. This is commonly {@code null} to + * indicate no merging is required. Any returned subscribers are sorted in a + * deterministic order. + * + * @hide + */ + public @Nullable String[] getMergedSubscriberIds() { + try { + return getITelephony().getMergedSubscriberIds(); + } catch (RemoteException ex) { + } catch (NullPointerException ex) { + } + return null; + } + + /** * Returns the MSISDN string. * for a GSM phone. Return null if it is unavailable. * <p> @@ -3593,5 +3612,3 @@ public class TelephonyManager { } } } - - diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index bf7f33273ffe..d19fa2ccf1a8 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -772,6 +772,8 @@ interface ITelephony { */ String getLine1AlphaTagForDisplay(int subId); + String[] getMergedSubscriberIds(); + /** * Override the operator branding for the current ICCID. * |