summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2014-12-02 18:30:14 -0800
committerJeff Sharkey <jsharkey@android.com>2014-12-08 08:42:59 -0800
commit3256601f5e4d94713f59e97b9d4912875c1bdcaf (patch)
treef1419e55b5b45e0b8485845ad21b72eadeccd977
parent9eb2092ea146faa21b8c6e0e512c03fc67a09dda (diff)
downloadframeworks_base-3256601f5e4d94713f59e97b9d4912875c1bdcaf.zip
frameworks_base-3256601f5e4d94713f59e97b9d4912875c1bdcaf.tar.gz
frameworks_base-3256601f5e4d94713f59e97b9d4912875c1bdcaf.tar.bz2
Offer to "merge" subscribers for data usage.
There are some cases where multiple subscriber identities (IMSI) should be treated as "merged together" from a data usage perspective. This is done by extending the template used for matching purposes to support multiple subscribers. Then, when we query historical usage or set network policies, we normalize the matching template to merge to any other identities that should be included. When normalizing, the "lowest" identity is always used for equality and storage purposes, which allows identities to come and go over time. This change also fixes data usage recording for multi-SIM devices by passing along the concrete subscriber identity for each network interface. Also correctly create default policies for multi-SIM devices. This change also drops setPolicyDataEnable() until it can be wired up to the right underlying NetworkAgent. (This means we still bring up the network, and then rely on iptables rules to block traffic when over the limit, instead of proactively disabling the connection.) Bug: 18012787 Change-Id: If6acf32009fdfea2b836f5aff8e2f3e5e0248b4a
-rw-r--r--core/java/android/net/IConnectivityManager.aidl3
-rw-r--r--core/java/android/net/NetworkIdentity.java30
-rw-r--r--core/java/android/net/NetworkMisc.java17
-rw-r--r--core/java/android/net/NetworkPolicy.java2
-rw-r--r--core/java/android/net/NetworkState.java7
-rw-r--r--core/java/android/net/NetworkTemplate.java67
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java15
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java98
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java217
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java2
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java3
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java21
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl2
14 files changed, 267 insertions, 223 deletions
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 8021210..d9921a6 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 d36707e..6864749 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 5d2a43d..b92c9e3 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 10c686b..e88bc26 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 d26c70d..933287f 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 b839e0a..6cfab92 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 8e786da..f908fcb 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 9c0e486..dde158c 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 cf19416..2be591b 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 b74716f..0b4d42e 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 f9a03fc..7383478 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 abf1ead..20cd037 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 751e11b..83bf04f 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 bf7f332..d19fa2c 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.
*