summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/bluetooth/BluetoothTetheringDataTracker.java15
-rw-r--r--core/java/android/net/DummyDataStateTracker.java12
-rw-r--r--core/java/android/net/EthernetDataTracker.java22
-rw-r--r--core/java/android/net/IConnectivityManager.aidl4
-rw-r--r--core/java/android/net/MobileDataStateTracker.java49
-rw-r--r--core/java/android/net/NetworkStateTracker.java12
-rwxr-xr-xcore/res/res/values/strings.xml4
-rw-r--r--services/java/com/android/server/ConnectivityService.java33
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java297
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java115
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnectionTracker.java110
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java9
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java50
-rw-r--r--wifi/java/android/net/wifi/WifiStateTracker.java22
14 files changed, 482 insertions, 272 deletions
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index a7b0037..83d1bda 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -19,7 +19,6 @@ package android.bluetooth;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfoInternal;
-import android.net.LinkAddress;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
import android.net.NetworkInfo;
@@ -30,7 +29,6 @@ import android.os.Handler;
import android.os.Message;
import android.util.Log;
-import java.net.InetAddress;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -184,11 +182,14 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker {
return -1;
}
- /**
- * @param enabled
- */
- public void setDataEnable(boolean enabled) {
- android.util.Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled);
+ @Override
+ public void setUserDataEnable(boolean enabled) {
+ Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
+ }
+
+ @Override
+ public void setPolicyDataEnable(boolean enabled) {
+ Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
}
/**
diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java
index e39725a..9f0f9cd 100644
--- a/core/java/android/net/DummyDataStateTracker.java
+++ b/core/java/android/net/DummyDataStateTracker.java
@@ -19,9 +19,6 @@ package android.net;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo;
-import android.net.LinkProperties;
import android.util.Slog;
/**
@@ -168,7 +165,14 @@ public class DummyDataStateTracker implements NetworkStateTracker {
return true;
}
- public void setDataEnable(boolean enabled) {
+ @Override
+ public void setUserDataEnable(boolean enabled) {
+ // ignored
+ }
+
+ @Override
+ public void setPolicyDataEnable(boolean enabled) {
+ // ignored
}
@Override
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index b035c51..21ecc22 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -17,15 +17,7 @@
package android.net;
import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.DhcpInfoInternal;
-import android.net.LinkAddress;
-import android.net.LinkCapabilities;
-import android.net.LinkProperties;
-import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkStateTracker;
-import android.net.NetworkUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkManagementService;
@@ -34,7 +26,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
-import java.net.InetAddress;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -302,11 +293,14 @@ public class EthernetDataTracker implements NetworkStateTracker {
return -1;
}
- /**
- * @param enabled
- */
- public void setDataEnable(boolean enabled) {
- Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled);
+ @Override
+ public void setUserDataEnable(boolean enabled) {
+ Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
+ }
+
+ @Override
+ public void setPolicyDataEnable(boolean enabled) {
+ Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
}
/**
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 1b95b60..c9553c0 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -64,9 +64,11 @@ interface IConnectivityManager
boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
boolean getMobileDataEnabled();
-
void setMobileDataEnabled(boolean enabled);
+ /** 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/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 5501f38..5929cfb 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -16,19 +16,26 @@
package android.net;
+import static com.android.internal.telephony.DataConnectionTracker.CMD_SET_POLICY_DATA_ENABLE;
+import static com.android.internal.telephony.DataConnectionTracker.CMD_SET_USER_DATA_ENABLE;
+import static com.android.internal.telephony.DataConnectionTracker.DISABLED;
+import static com.android.internal.telephony.DataConnectionTracker.ENABLED;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.NetworkInfo.DetailedState;
import android.os.Bundle;
-import android.os.HandlerThread;
+import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Slog;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.ITelephony;
@@ -36,13 +43,6 @@ import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.AsyncChannel;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo;
-import android.net.LinkProperties;
-import android.telephony.TelephonyManager;
-import android.util.Slog;
-import android.text.TextUtils;
-
/**
* Track the state of mobile data connectivity. This is done by
* receiving broadcast intents from the Phone process whenever
@@ -452,17 +452,22 @@ public class MobileDataStateTracker implements NetworkStateTracker {
return false;
}
- /**
- * @param enabled
- */
- public void setDataEnable(boolean enabled) {
- try {
- if (DBG) log("setDataEnable: E enabled=" + enabled);
- mDataConnectionTrackerAc.sendMessage(DataConnectionTracker.CMD_SET_DATA_ENABLE,
- enabled ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED);
- if (VDBG) log("setDataEnable: X enabled=" + enabled);
- } catch (Exception e) {
- loge("setDataEnable: X mAc was null" + e);
+ @Override
+ public void setUserDataEnable(boolean enabled) {
+ if (DBG) log("setUserDataEnable: E enabled=" + enabled);
+ final AsyncChannel channel = mDataConnectionTrackerAc;
+ if (channel != null) {
+ channel.sendMessage(CMD_SET_USER_DATA_ENABLE, enabled ? ENABLED : DISABLED);
+ }
+ if (VDBG) log("setUserDataEnable: X enabled=" + enabled);
+ }
+
+ @Override
+ public void setPolicyDataEnable(boolean enabled) {
+ if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")");
+ final AsyncChannel channel = mDataConnectionTrackerAc;
+ if (channel != null) {
+ channel.sendMessage(CMD_SET_POLICY_DATA_ENABLE, enabled ? ENABLED : DISABLED);
}
}
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index f53063d..1735592 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -136,9 +136,17 @@ public interface NetworkStateTracker {
public boolean isAvailable();
/**
- * @param enabled
+ * User control of data connection through this network, typically persisted
+ * internally.
*/
- public void setDataEnable(boolean enabled);
+ public void setUserDataEnable(boolean enabled);
+
+ /**
+ * Policy control of data connection through this network, typically not
+ * persisted internally. Usually used when {@link NetworkPolicy#limitBytes}
+ * is passed.
+ */
+ public void setPolicyDataEnable(boolean enabled);
/**
* -------------------------------------------------------------
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6aff54e..ade2865 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3098,6 +3098,8 @@
<string name="data_usage_4g_limit_title">4G data disabled</string>
<!-- Notification title when mobile data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
<string name="data_usage_mobile_limit_title">Mobile data disabled</string>
+ <!-- Notification title when Wi-Fi data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
+ <string name="data_usage_wifi_limit_title">Wi-Fi data disabled</string>
<!-- Notification body when data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
<string name="data_usage_limit_body">Touch to enable</string>
@@ -3107,6 +3109,8 @@
<string name="data_usage_4g_limit_snoozed_title">4G data limit exceeded</string>
<!-- Notification title when mobile data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
<string name="data_usage_mobile_limit_snoozed_title">Mobile data limit exceeded</string>
+ <!-- Notification title when Wi-Fi data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
+ <string name="data_usage_wifi_limit_snoozed_title">Wi-Fi data limit exceeded</string>
<!-- Notification body when data usage has exceeded limit threshold. [CHAR LIMIT=32] -->
<string name="data_usage_limit_snoozed_body"><xliff:g id="size" example="3.8GB">%s</xliff:g> over specified limit</string>
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 1341dd4..bfca851 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -72,7 +72,6 @@ import com.android.internal.net.VpnConfig;
import com.android.internal.telephony.Phone;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
-
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
@@ -89,7 +88,6 @@ import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* @hide
@@ -251,6 +249,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final int EVENT_SEND_STICKY_BROADCAST_INTENT =
MAX_NETWORK_STATE_TRACKER_EVENT + 12;
+ /**
+ * Used internally to
+ * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}.
+ */
+ private static final int EVENT_SET_POLICY_DATA_ENABLE = MAX_NETWORK_STATE_TRACKER_EVENT + 13;
+
private Handler mHandler;
// list of DeathRecipients used to make sure features are turned off when
@@ -1282,7 +1286,25 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (VDBG) {
log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
}
- mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled);
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled);
+ }
+ }
+
+ @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) {
+ if (isNetworkTypeValid(networkType)) {
+ final NetworkStateTracker tracker = mNetTrackers[networkType];
+ if (tracker != null) {
+ tracker.setPolicyDataEnable(enabled);
+ }
}
}
@@ -2263,6 +2285,11 @@ 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);
+ }
}
}
}
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 14d9665..84880f9 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -27,7 +27,10 @@ import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -40,8 +43,11 @@ import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
import static android.net.NetworkPolicyManager.dumpPolicy;
import static android.net.NetworkPolicyManager.dumpRules;
import static android.net.NetworkPolicyManager.isUidValidForPolicy;
+import static android.net.NetworkTemplate.MATCH_ETHERNET;
import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
+import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
+import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -104,6 +110,7 @@ import android.util.Xml;
import com.android.internal.R;
import com.android.internal.os.AtomicFile;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Objects;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -129,8 +136,8 @@ import java.util.List;
import libcore.io.IoUtils;
/**
- * Service that maintains low-level network policy rules and collects usage
- * statistics to drive those rules.
+ * Service that maintains low-level network policy rules, using
+ * {@link NetworkStatsService} statistics to drive those rules.
* <p>
* Derives active rules by combining a given policy with other system status,
* and delivers to listeners, such as {@link ConnectivityManager}, for
@@ -195,6 +202,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private volatile boolean mScreenOn;
private volatile boolean mRestrictBackground;
+ private final boolean mSuppressDefaultPolicy;
+
/** Defined network policies. */
private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap();
/** Currently active network rules for ifaces. */
@@ -210,6 +219,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Set of over-limit templates that have been notified. */
private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
+ /** Set of currently active {@link Notification} tags. */
+ private HashSet<String> mActiveNotifs = Sets.newHashSet();
+ /** Current values from {@link #setPolicyDataEnable(int, boolean)}. */
+ private SparseBooleanArray mActiveNetworkEnabled = new SparseBooleanArray();
+
/** Foreground at both UID and PID granularity. */
private SparseBooleanArray mUidForeground = new SparseBooleanArray();
private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
@@ -232,7 +246,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
IPowerManager powerManager, INetworkStatsService networkStats,
INetworkManagementService networkManagement) {
this(context, activityManager, powerManager, networkStats, networkManagement,
- NtpTrustedTime.getInstance(context), getSystemDir());
+ NtpTrustedTime.getInstance(context), getSystemDir(), false);
}
private static File getSystemDir() {
@@ -241,8 +255,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
IPowerManager powerManager, INetworkStatsService networkStats,
- INetworkManagementService networkManagement,
- TrustedTime time, File systemDir) {
+ INetworkManagementService networkManagement, TrustedTime time, File systemDir,
+ boolean suppressDefaultPolicy) {
mContext = checkNotNull(context, "missing context");
mActivityManager = checkNotNull(activityManager, "missing activityManager");
mPowerManager = checkNotNull(powerManager, "missing powerManager");
@@ -254,6 +268,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
+ mSuppressDefaultPolicy = suppressDefaultPolicy;
+
mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
}
@@ -408,6 +424,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// READ_NETWORK_USAGE_HISTORY permission above.
synchronized (mRulesLock) {
+ updateNetworkEnabledLocked();
updateNotificationsLocked();
}
}
@@ -446,6 +463,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
Slog.w(TAG, "problem updating network stats");
}
+ updateNetworkEnabledLocked();
updateNotificationsLocked();
}
}
@@ -459,74 +477,70 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void updateNotificationsLocked() {
if (LOGV) Slog.v(TAG, "updateNotificationsLocked()");
- // try refreshing time source when stale
- if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
- mTime.forceRefresh();
- }
-
- final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
- : System.currentTimeMillis();
+ // keep track of previously active notifications
+ final HashSet<String> beforeNotifs = Sets.newHashSet();
+ beforeNotifs.addAll(mActiveNotifs);
+ mActiveNotifs.clear();
// TODO: when switching to kernel notifications, compute next future
// cycle boundary to recompute notifications.
// examine stats for each active policy
- for (NetworkPolicy policy : mNetworkRules.keySet()) {
+ final long currentTime = currentTimeMillis(true);
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ // ignore policies that aren't relevant to user
+ if (!isTemplateRelevant(policy.template)) continue;
+
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
- final long totalBytes;
- try {
- final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
- policy.template, start, end);
- final NetworkStats.Entry entry = stats.getValues(0, null);
- totalBytes = entry.rxBytes + entry.txBytes;
- } catch (RemoteException e) {
- Slog.w(TAG, "problem reading summary for template " + policy.template);
- continue;
- }
+ final long totalBytes = getTotalBytes(policy.template, start, end);
+ if (totalBytes == UNKNOWN_BYTES) continue;
if (policy.limitBytes != LIMIT_DISABLED && totalBytes >= policy.limitBytes) {
- cancelNotification(policy, TYPE_WARNING);
-
if (policy.lastSnooze >= start) {
- cancelNotification(policy, TYPE_LIMIT);
enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
} else {
- cancelNotification(policy, TYPE_LIMIT_SNOOZED);
enqueueNotification(policy, TYPE_LIMIT, totalBytes);
notifyOverLimitLocked(policy.template);
}
} else {
- cancelNotification(policy, TYPE_LIMIT);
- cancelNotification(policy, TYPE_LIMIT_SNOOZED);
notifyUnderLimitLocked(policy.template);
if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) {
enqueueNotification(policy, TYPE_WARNING, totalBytes);
- } else {
- cancelNotification(policy, TYPE_WARNING);
}
}
}
- // clear notifications for non-active policies
- for (NetworkPolicy policy : mNetworkPolicy.values()) {
- if (!mNetworkRules.containsKey(policy)) {
- cancelNotification(policy, TYPE_WARNING);
- cancelNotification(policy, TYPE_LIMIT);
- cancelNotification(policy, TYPE_LIMIT_SNOOZED);
- notifyUnderLimitLocked(policy.template);
- }
- }
-
// ongoing notification when restricting background data
if (mRestrictBackground) {
enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND);
- } else {
- cancelNotification(TAG_ALLOW_BACKGROUND);
}
+
+ // cancel stale notifications that we didn't renew above
+ for (String tag : beforeNotifs) {
+ if (!mActiveNotifs.contains(tag)) {
+ cancelNotification(tag);
+ }
+ }
+ }
+
+ /**
+ * Test if given {@link NetworkTemplate} is relevant to user based on
+ * current device state, such as when {@link #getActiveSubscriberId()}
+ * matches. This is regardless of data connection status.
+ */
+ private boolean isTemplateRelevant(NetworkTemplate template) {
+ switch (template.getMatchRule()) {
+ case MATCH_MOBILE_3G_LOWER:
+ case MATCH_MOBILE_4G:
+ case MATCH_MOBILE_ALL:
+ // mobile templates are relevant when subscriberid is active
+ return Objects.equal(getActiveSubscriberId(), template.getSubscriberId());
+ }
+ return true;
}
/**
@@ -590,9 +604,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
case MATCH_MOBILE_4G:
title = res.getText(R.string.data_usage_4g_limit_title);
break;
- default:
+ case MATCH_MOBILE_ALL:
title = res.getText(R.string.data_usage_mobile_limit_title);
break;
+ case MATCH_WIFI:
+ title = res.getText(R.string.data_usage_wifi_limit_title);
+ break;
+ default:
+ title = null;
+ break;
}
builder.setSmallIcon(com.android.internal.R.drawable.ic_menu_block);
@@ -618,9 +638,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
case MATCH_MOBILE_4G:
title = res.getText(R.string.data_usage_4g_limit_snoozed_title);
break;
- default:
+ case MATCH_MOBILE_ALL:
title = res.getText(R.string.data_usage_mobile_limit_snoozed_title);
break;
+ case MATCH_WIFI:
+ title = res.getText(R.string.data_usage_wifi_limit_snoozed_title);
+ break;
+ default:
+ title = null;
+ break;
}
builder.setSmallIcon(R.drawable.ic_menu_info_details);
@@ -641,6 +667,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final int[] idReceived = new int[1];
mNotifManager.enqueueNotificationWithTag(
packageName, tag, 0x0, builder.getNotification(), idReceived);
+ mActiveNotifs.add(tag);
} catch (RemoteException e) {
Slog.w(TAG, "problem during enqueueNotification: " + e);
}
@@ -674,19 +701,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final int[] idReceived = new int[1];
mNotifManager.enqueueNotificationWithTag(packageName, tag,
0x0, builder.getNotification(), idReceived);
+ mActiveNotifs.add(tag);
} catch (RemoteException e) {
Slog.w(TAG, "problem during enqueueNotification: " + e);
}
}
- /**
- * Cancel any notification for combined {@link NetworkPolicy} and specific
- * type, like {@link #TYPE_LIMIT}.
- */
- private void cancelNotification(NetworkPolicy policy, int type) {
- cancelNotification(buildNotificationTag(policy, type));
- }
-
private void cancelNotification(String tag) {
// TODO: move to NotificationManager once we can mock it
try {
@@ -709,6 +729,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// permission above.
synchronized (mRulesLock) {
ensureActiveMobilePolicyLocked();
+ updateNetworkEnabledLocked();
updateNetworkRulesLocked();
updateNotificationsLocked();
}
@@ -716,6 +737,65 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
};
/**
+ * Proactively control network data connections when they exceed
+ * {@link NetworkPolicy#limitBytes}.
+ */
+ private void updateNetworkEnabledLocked() {
+ if (LOGV) Slog.v(TAG, "updateNetworkEnabledLocked()");
+
+ // TODO: reset any policy-disabled networks when any policy is removed
+ // completely, which is currently rare case.
+
+ final long currentTime = currentTimeMillis(true);
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ // shortcut when policy has no limit
+ if (policy.limitBytes == LIMIT_DISABLED) {
+ setNetworkTemplateEnabled(policy.template, true);
+ continue;
+ }
+
+ final long start = computeLastCycleBoundary(currentTime, policy);
+ final long end = currentTime;
+
+ final long totalBytes = getTotalBytes(policy.template, start, end);
+ if (totalBytes == UNKNOWN_BYTES) continue;
+
+ // disable data connection when over limit and not snoozed
+ final boolean overLimit = policy.limitBytes != LIMIT_DISABLED
+ && totalBytes > policy.limitBytes && policy.lastSnooze < start;
+ setNetworkTemplateEnabled(policy.template, !overLimit);
+ }
+ }
+
+ /**
+ * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}
+ * for the given {@link NetworkTemplate}.
+ */
+ private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) {
+ if (LOGD) Slog.d(TAG, "setting template=" + template + " enabled=" + enabled);
+ 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 (Objects.equal(getActiveSubscriberId(), 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");
+ }
+ }
+
+ /**
* Examine all connected {@link NetworkState}, looking for
* {@link NetworkPolicy} that need to be enforced. When matches found, set
* remaining quota based on usage cycle and historical stats.
@@ -763,34 +843,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- // try refreshing time source when stale
- if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
- mTime.forceRefresh();
- }
-
- final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
- : System.currentTimeMillis();
-
final HashSet<String> newMeteredIfaces = Sets.newHashSet();
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
+ final long currentTime = currentTimeMillis(true);
for (NetworkPolicy policy : mNetworkRules.keySet()) {
final String[] ifaces = mNetworkRules.get(policy);
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
- final NetworkStats stats;
- final long total;
- try {
- stats = mNetworkStats.getSummaryForNetwork(policy.template, start, end);
- final NetworkStats.Entry entry = stats.getValues(0, null);
- total = entry.rxBytes + entry.txBytes;
- } catch (RemoteException e) {
- Slog.w(TAG, "problem reading summary for template " + policy.template);
- continue;
- }
+ final long totalBytes = getTotalBytes(policy.template, start, end);
+ if (totalBytes == UNKNOWN_BYTES) continue;
if (LOGD) {
Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
@@ -798,11 +863,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
- final boolean hasWarning = policy.warningBytes != WARNING_DISABLED;
-
if (hasLimit) {
- // remaining "quota" is based on usage in current cycle
- final long quotaBytes = Math.max(0, policy.limitBytes - total);
+ final long quotaBytes;
+ if (policy.lastSnooze >= start) {
+ // snoozing past quota, but we still need to restrict apps,
+ // so push really high quota.
+ quotaBytes = Long.MAX_VALUE;
+ } else {
+ // remaining "quota" bytes are based on total usage in
+ // current cycle. kernel doesn't like 0-byte rules, so we
+ // set 1-byte quota and disable the radio later.
+ quotaBytes = Math.max(1, policy.limitBytes - totalBytes);
+ }
if (ifaces.length > 1) {
// TODO: switch to shared quota once NMS supports
@@ -811,10 +883,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (String iface : ifaces) {
removeInterfaceQuota(iface);
- if (quotaBytes > 0) {
- setInterfaceQuota(iface, quotaBytes);
- newMeteredIfaces.add(iface);
- }
+ setInterfaceQuota(iface, quotaBytes);
+ newMeteredIfaces.add(iface);
}
}
}
@@ -837,6 +907,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private void ensureActiveMobilePolicyLocked() {
if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()");
+ if (mSuppressDefaultPolicy) return;
+
final String subscriberId = getActiveSubscriberId();
final NetworkIdentity probeIdent = new NetworkIdentity(
TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, false);
@@ -1073,6 +1145,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mNetworkPolicy.put(policy.template, policy);
}
+ updateNetworkEnabledLocked();
updateNetworkRulesLocked();
updateNotificationsLocked();
writePolicyLocked();
@@ -1093,14 +1166,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public void snoozePolicy(NetworkTemplate template) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- // try refreshing time source when stale
- if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
- mTime.forceRefresh();
- }
-
- final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
- : System.currentTimeMillis();
-
+ final long currentTime = currentTimeMillis(true);
synchronized (mRulesLock) {
// find and snooze local policy that matches
final NetworkPolicy policy = mNetworkPolicy.get(template);
@@ -1110,6 +1176,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
policy.lastSnooze = currentTime;
+ updateNetworkEnabledLocked();
updateNetworkRulesLocked();
updateNotificationsLocked();
writePolicyLocked();
@@ -1173,22 +1240,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return null;
}
- final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
- : System.currentTimeMillis();
+ final long currentTime = currentTimeMillis(false);
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
// find total bytes used under policy
- long totalBytes = 0;
- try {
- final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
- policy.template, start, end);
- final NetworkStats.Entry entry = stats.getValues(0, null);
- totalBytes = entry.rxBytes + entry.txBytes;
- } catch (RemoteException e) {
- Slog.w(TAG, "problem reading summary for template " + policy.template);
- }
+ final long totalBytes = getTotalBytes(policy.template, start, end);
+ if (totalBytes == UNKNOWN_BYTES) return null;
// report soft and hard limits under policy
final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
@@ -1481,12 +1540,54 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ /**
+ * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)},
+ * dispatching only when actually changed.
+ */
+ private void setPolicyDataEnable(int networkType, boolean enabled) {
+ synchronized (mActiveNetworkEnabled) {
+ final boolean prevEnabled = mActiveNetworkEnabled.get(networkType, true);
+ if (prevEnabled == enabled) return;
+
+ try {
+ mConnManager.setPolicyDataEnable(networkType, enabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem setting network enabled", e);
+ }
+
+ mActiveNetworkEnabled.put(networkType, enabled);
+ }
+ }
+
private String getActiveSubscriberId() {
final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
return telephony.getSubscriberId();
}
+ private static final long UNKNOWN_BYTES = -1;
+
+ private long getTotalBytes(NetworkTemplate template, long start, long end) {
+ try {
+ final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
+ template, start, end);
+ final NetworkStats.Entry entry = stats.getValues(0, null);
+ return entry.rxBytes + entry.txBytes;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "problem reading summary for template " + template);
+ return UNKNOWN_BYTES;
+ }
+ }
+
+ private long currentTimeMillis(boolean allowRefresh) {
+ // try refreshing time source when stale
+ if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE && allowRefresh) {
+ mTime.forceRefresh();
+ }
+
+ return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
+ }
+
private static Intent buildAllowBackgroundDataIntent() {
return new Intent(ACTION_ALLOW_BACKGROUND);
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 845aa3f..f67d251 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -79,6 +79,7 @@ import com.google.common.util.concurrent.AbstractFuture;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
+import org.easymock.IExpectationSetters;
import java.io.File;
import java.util.LinkedHashSet;
@@ -87,6 +88,8 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import libcore.io.IoUtils;
+
/**
* Tests for {@link NetworkPolicyManagerService}.
*/
@@ -117,6 +120,9 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
private Binder mStubBinder = new Binder();
+ private long mStartTime;
+ private long mElapsedRealtime;
+
private static final int UID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
private static final int UID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
@@ -128,6 +134,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public void setUp() throws Exception {
super.setUp();
+ setCurrentTimeMillis(TEST_START);
+
// intercept various broadcasts, and pretend that uids have packages
mServiceContext = new BroadcastInterceptingContext(getContext()) {
@Override
@@ -160,8 +168,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
};
mPolicyDir = getContext().getFilesDir();
- for (File file : mPolicyDir.listFiles()) {
- file.delete();
+ if (mPolicyDir.exists()) {
+ IoUtils.deleteContents(mPolicyDir);
}
mActivityManager = createMock(IActivityManager.class);
@@ -173,9 +181,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
mConnManager = createMock(IConnectivityManager.class);
mNotifManager = createMock(INotificationManager.class);
- mService = new NetworkPolicyManagerService(
- mServiceContext, mActivityManager, mPowerManager, mStatsService,
- mNetworkManager, mTime, mPolicyDir);
+ mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mPowerManager,
+ mStatsService, mNetworkManager, mTime, mPolicyDir, true);
mService.bindConnectivityManager(mConnManager);
mService.bindNotificationManager(mNotifManager);
@@ -198,7 +205,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// expect to answer screen status during systemReady()
expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
- expectTime(System.currentTimeMillis());
+ expectCurrentTime();
replay();
mService.systemReady();
@@ -485,7 +492,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
public void testNetworkPolicyAppliedCycleLastMonth() throws Exception {
- long elapsedRealtime = 0;
NetworkState[] state = null;
NetworkStats stats = null;
Future<Void> future;
@@ -494,11 +500,13 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final long TIME_MAR_10 = 1173484800000L;
final int CYCLE_DAY = 15;
+ setCurrentTimeMillis(TIME_MAR_10);
+
// first, pretend that wifi network comes online. no policy active,
// which means we shouldn't push limit to interface.
state = new NetworkState[] { buildWifi() };
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
- expectTime(TIME_MAR_10 + elapsedRealtime);
+ expectCurrentTime();
expectClearNotifications();
future = expectMeteredIfacesChanged();
@@ -510,10 +518,10 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// now change cycle to be on 15th, and test in early march, to verify we
// pick cycle day in previous month.
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
- expectTime(TIME_MAR_10 + elapsedRealtime);
+ expectCurrentTime();
// pretend that 512 bytes total have happened
- stats = new NetworkStats(elapsedRealtime, 1)
+ stats = new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L);
expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
.andReturn(stats).atLeastOnce();
@@ -521,8 +529,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// TODO: consider making strongly ordered mock
expectRemoveInterfaceQuota(TEST_IFACE);
expectSetInterfaceQuota(TEST_IFACE, 1536L);
- expectRemoveInterfaceAlert(TEST_IFACE);
- expectSetInterfaceAlert(TEST_IFACE, 512L);
expectClearNotifications();
future = expectMeteredIfacesChanged(TEST_IFACE);
@@ -558,8 +564,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
public void testOverWarningLimitNotification() throws Exception {
- long elapsedRealtime = 0;
- long currentTime = 0;
NetworkState[] state = null;
NetworkStats stats = null;
Future<Void> future;
@@ -569,14 +573,18 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
final long TIME_MAR_10 = 1173484800000L;
final int CYCLE_DAY = 15;
+ setCurrentTimeMillis(TIME_MAR_10);
+
// assign wifi policy
- elapsedRealtime = 0;
- currentTime = TIME_MAR_10 + elapsedRealtime;
state = new NetworkState[] {};
+ stats = new NetworkStats(getElapsedRealtime(), 1)
+ .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
{
- expectTime(currentTime);
+ expectCurrentTime();
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+ .andReturn(stats).atLeastOnce();
expectClearNotifications();
future = expectMeteredIfacesChanged();
@@ -589,22 +597,19 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
// bring up wifi network
- elapsedRealtime += MINUTE_IN_MILLIS;
- currentTime = TIME_MAR_10 + elapsedRealtime;
- stats = new NetworkStats(elapsedRealtime, 1)
- .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
+ incrementCurrentTime(MINUTE_IN_MILLIS);
state = new NetworkState[] { buildWifi() };
+ stats = new NetworkStats(getElapsedRealtime(), 1)
+ .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
{
- expectTime(currentTime);
+ expectCurrentTime();
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
.andReturn(stats).atLeastOnce();
expectRemoveInterfaceQuota(TEST_IFACE);
expectSetInterfaceQuota(TEST_IFACE, 2048L);
- expectRemoveInterfaceAlert(TEST_IFACE);
- expectSetInterfaceAlert(TEST_IFACE, 1024L);
expectClearNotifications();
future = expectMeteredIfacesChanged(TEST_IFACE);
@@ -616,14 +621,13 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
// go over warning, which should kick notification
- elapsedRealtime += MINUTE_IN_MILLIS;
- currentTime = TIME_MAR_10 + elapsedRealtime;
- stats = new NetworkStats(elapsedRealtime, 1)
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ stats = new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1536L, 15L, 0L, 0L);
{
- expectTime(currentTime);
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
+ expectCurrentTime();
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
.andReturn(stats).atLeastOnce();
expectForceUpdate();
@@ -637,15 +641,15 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
// go over limit, which should kick notification and dialog
- elapsedRealtime += MINUTE_IN_MILLIS;
- currentTime = TIME_MAR_10 + elapsedRealtime;
- stats = new NetworkStats(elapsedRealtime, 1)
+ incrementCurrentTime(MINUTE_IN_MILLIS);
+ stats = new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 5120L, 512L, 0L, 0L);
{
- expectTime(currentTime);
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
+ expectCurrentTime();
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
.andReturn(stats).atLeastOnce();
+ expectPolicyDataEnable(TYPE_WIFI, false).atLeastOnce();
expectForceUpdate();
expectClearNotifications();
@@ -658,21 +662,23 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
// now snooze policy, which should remove quota
- elapsedRealtime += MINUTE_IN_MILLIS;
- currentTime = TIME_MAR_10 + elapsedRealtime;
+ incrementCurrentTime(MINUTE_IN_MILLIS);
{
- expectTime(currentTime);
+ expectCurrentTime();
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
- expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime))
+ expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
.andReturn(stats).atLeastOnce();
+ expectPolicyDataEnable(TYPE_WIFI, true).atLeastOnce();
+ // snoozed interface still has high quota so background data is
+ // still restricted.
expectRemoveInterfaceQuota(TEST_IFACE);
- expectRemoveInterfaceAlert(TEST_IFACE);
+ expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE);
expectClearNotifications();
tag = expectEnqueueNotification();
- future = expectMeteredIfacesChanged();
+ future = expectMeteredIfacesChanged(TEST_IFACE);
replay();
mService.snoozePolicy(sTemplateWifi);
@@ -700,10 +706,10 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
return new NetworkState(info, prop, null);
}
- private void expectTime(long currentTime) throws Exception {
+ private void expectCurrentTime() throws Exception {
expect(mTime.forceRefresh()).andReturn(false).anyTimes();
expect(mTime.hasCache()).andReturn(true).anyTimes();
- expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes();
+ expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes();
expect(mTime.getCacheAge()).andReturn(0L).anyTimes();
expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes();
}
@@ -770,6 +776,12 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
return future;
}
+ private <T> IExpectationSetters<T> expectPolicyDataEnable(int type, boolean enabled)
+ throws Exception {
+ mConnManager.setPolicyDataEnable(type, enabled);
+ return expectLastCall();
+ }
+
private static class FutureAnswer extends AbstractFuture<Void> implements IAnswer<Void> {
@Override
public Void get() throws InterruptedException, ExecutionException {
@@ -818,6 +830,23 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1));
}
+ private long getElapsedRealtime() {
+ return mElapsedRealtime;
+ }
+
+ private void setCurrentTimeMillis(long currentTimeMillis) {
+ mStartTime = currentTimeMillis;
+ mElapsedRealtime = 0L;
+ }
+
+ private long currentTimeMillis() {
+ return mStartTime + mElapsedRealtime;
+ }
+
+ private void incrementCurrentTime(long duration) {
+ mElapsedRealtime += duration;
+ }
+
private void replay() {
EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
mNetworkManager, mTime, mConnManager, mNotifManager);
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 3bd78e0..42ea4f2 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -36,8 +36,8 @@ import android.os.Messenger;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.Settings;
-import android.telephony.ServiceState;
import android.provider.Settings.SettingNotFoundException;
+import android.telephony.ServiceState;
import android.text.TextUtils;
import android.util.Log;
@@ -126,9 +126,10 @@ public abstract class DataConnectionTracker extends Handler {
protected static final int EVENT_RESTART_RADIO = BASE + 26;
protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
protected static final int EVENT_RESET_DONE = BASE + 28;
- public static final int CMD_SET_DATA_ENABLE = BASE + 29;
+ public static final int CMD_SET_USER_DATA_ENABLE = BASE + 29;
public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
+ public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
/***** Constants *****/
@@ -153,6 +154,8 @@ public abstract class DataConnectionTracker extends Handler {
protected static final int APN_DELAY_MILLIS =
SystemProperties.getInt("persist.radio.apn_delay", 5000);
+ protected Object mDataEnabledLock = new Object();
+
// responds to the setInternalDataEnabled call - used internally to turn off data
// for example during emergency calls
protected boolean mInternalDataEnabled = true;
@@ -160,11 +163,12 @@ public abstract class DataConnectionTracker extends Handler {
// responds to public (user) API to enable/disable data use
// independent of mInternalDataEnabled and requests for APN access
// persisted
- protected boolean mDataEnabled = true;
+ protected boolean mUserDataEnabled = true;
+ protected boolean mPolicyDataEnabled = true;
- protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
+ private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
- protected int enabledCount = 0;
+ private int enabledCount = 0;
/* Currently requested APN type (TODO: This should probably be a parameter not a member) */
protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
@@ -408,8 +412,8 @@ public abstract class DataConnectionTracker extends Handler {
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
- mDataEnabled = Settings.Secure.getInt(mPhone.getContext().getContentResolver(),
- Settings.Secure.MOBILE_DATA, 1) == 1;
+ mUserDataEnabled = Settings.Secure.getInt(
+ mPhone.getContext().getContentResolver(), Settings.Secure.MOBILE_DATA, 1) == 1;
// TODO: Why is this registering the phone as the receiver of the intent
// and not its own handler?
@@ -630,13 +634,12 @@ public abstract class DataConnectionTracker extends Handler {
onResetDone((AsyncResult) msg.obj);
break;
}
- case CMD_SET_DATA_ENABLE: {
- boolean enabled = (msg.arg1 == ENABLED) ? true : false;
- if (DBG) log("CMD_SET_DATA_ENABLE enabled=" + enabled);
- onSetDataEnabled(enabled);
+ case CMD_SET_USER_DATA_ENABLE: {
+ final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
+ if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
+ onSetUserDataEnabled(enabled);
break;
}
-
case CMD_SET_DEPENDENCY_MET: {
boolean met = (msg.arg1 == ENABLED) ? true : false;
if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
@@ -649,7 +652,11 @@ public abstract class DataConnectionTracker extends Handler {
}
break;
}
-
+ case CMD_SET_POLICY_DATA_ENABLE: {
+ final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
+ onSetPolicyDataEnabled(enabled);
+ break;
+ }
default:
Log.e("DATA", "Unidentified event msg=" + msg);
break;
@@ -662,8 +669,12 @@ public abstract class DataConnectionTracker extends Handler {
* @return {@code false} if data connectivity has been explicitly disabled,
* {@code true} otherwise.
*/
- public synchronized boolean getAnyDataEnabled() {
- boolean result = (mInternalDataEnabled && mDataEnabled && (enabledCount != 0));
+ public boolean getAnyDataEnabled() {
+ final boolean result;
+ synchronized (mDataEnabledLock) {
+ result = (mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled
+ && (enabledCount != 0));
+ }
if (!result && DBG) log("getAnyDataEnabled " + result);
return result;
}
@@ -985,18 +996,18 @@ public abstract class DataConnectionTracker extends Handler {
return true;
}
- protected void onSetInternalDataEnabled(boolean enable) {
- boolean prevEnabled = getAnyDataEnabled();
- if (mInternalDataEnabled != enable) {
- synchronized (this) {
- mInternalDataEnabled = enable;
- }
- if (prevEnabled != getAnyDataEnabled()) {
- if (!prevEnabled) {
- resetAllRetryCounts();
- onTrySetupData(Phone.REASON_DATA_ENABLED);
- } else {
- cleanUpAllConnections(null);
+ protected void onSetInternalDataEnabled(boolean enabled) {
+ synchronized (mDataEnabledLock) {
+ final boolean prevEnabled = getAnyDataEnabled();
+ if (mInternalDataEnabled != enabled) {
+ mInternalDataEnabled = enabled;
+ if (prevEnabled != getAnyDataEnabled()) {
+ if (!prevEnabled) {
+ resetAllRetryCounts();
+ onTrySetupData(Phone.REASON_DATA_ENABLED);
+ } else {
+ cleanUpAllConnections(null);
+ }
}
}
}
@@ -1010,20 +1021,20 @@ public abstract class DataConnectionTracker extends Handler {
public abstract boolean isAnyActiveDataConnections();
- protected void onSetDataEnabled(boolean enable) {
- boolean prevEnabled = getAnyDataEnabled();
- if (mDataEnabled != enable) {
- synchronized (this) {
- mDataEnabled = enable;
- }
- Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
- Settings.Secure.MOBILE_DATA, enable ? 1 : 0);
- if (prevEnabled != getAnyDataEnabled()) {
- if (!prevEnabled) {
- resetAllRetryCounts();
- onTrySetupData(Phone.REASON_DATA_ENABLED);
- } else {
- onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
+ protected void onSetUserDataEnabled(boolean enabled) {
+ synchronized (mDataEnabledLock) {
+ final boolean prevEnabled = getAnyDataEnabled();
+ if (mUserDataEnabled != enabled) {
+ mUserDataEnabled = enabled;
+ Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
+ Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
+ if (prevEnabled != getAnyDataEnabled()) {
+ if (!prevEnabled) {
+ resetAllRetryCounts();
+ onTrySetupData(Phone.REASON_DATA_ENABLED);
+ } else {
+ onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
+ }
}
}
}
@@ -1032,6 +1043,23 @@ public abstract class DataConnectionTracker extends Handler {
protected void onSetDependencyMet(String apnType, boolean met) {
}
+ protected void onSetPolicyDataEnabled(boolean enabled) {
+ synchronized (mDataEnabledLock) {
+ final boolean prevEnabled = getAnyDataEnabled();
+ if (mPolicyDataEnabled != enabled) {
+ mPolicyDataEnabled = enabled;
+ if (prevEnabled != getAnyDataEnabled()) {
+ if (!prevEnabled) {
+ resetAllRetryCounts();
+ onTrySetupData(Phone.REASON_DATA_ENABLED);
+ } else {
+ onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
+ }
+ }
+ }
+ }
+ }
+
protected String getReryConfig(boolean forDefault) {
int rt = mPhone.getServiceState().getRadioTechnology();
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 800615c..1a077d0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -175,6 +175,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
@Override
protected boolean isDataAllowed() {
+ final boolean internalDataEnabled;
+ synchronized (mDataEnabledLock) {
+ internalDataEnabled = mInternalDataEnabled;
+ }
+
int psState = mCdmaPhone.mSST.getCurrentDataConnectionState();
boolean roaming = (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled());
boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState();
@@ -187,7 +192,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
(mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
mPhone.getState() == Phone.State.IDLE) &&
!roaming &&
- mInternalDataEnabled &&
+ internalDataEnabled &&
desiredPowerState &&
!mPendingRestartRadio &&
!mCdmaPhone.needsOtaServiceProvisioning();
@@ -205,7 +210,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
reason += " - concurrentVoiceAndData not allowed and state= " + mPhone.getState();
}
if (roaming) reason += " - Roaming";
- if (!mInternalDataEnabled) reason += " - mInternalDataEnabled= false";
+ if (!internalDataEnabled) reason += " - mInternalDataEnabled= false";
if (!desiredPowerState) reason += " - desiredPowerState= false";
if (mPendingRestartRadio) reason += " - mPendingRestartRadio= true";
if (mCdmaPhone.needsOtaServiceProvisioning()) reason += " - needs Provisioning";
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 3236901..c8671c1 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -27,14 +27,14 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
+import android.net.LinkCapabilities;
+import android.net.LinkProperties;
import android.net.LinkProperties.CompareResult;
+import android.net.NetworkConfig;
import android.net.NetworkUtils;
import android.net.ProxyProperties;
import android.net.TrafficStats;
import android.net.Uri;
-import android.net.LinkCapabilities;
-import android.net.LinkProperties;
-import android.net.NetworkConfig;
import android.os.AsyncResult;
import android.os.Message;
import android.os.SystemClock;
@@ -49,34 +49,27 @@ import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
-import android.preference.PreferenceManager;
-import com.android.internal.R;
import com.android.internal.telephony.ApnContext;
import com.android.internal.telephony.ApnSetting;
import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
+import com.android.internal.telephony.EventLogTags;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneBase;
-import com.android.internal.telephony.RetryManager;
-import com.android.internal.telephony.EventLogTags;
-import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.RetryManager;
import com.android.internal.util.AsyncChannel;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.List;
-import java.util.Map;
import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
/**
* {@hide}
@@ -523,16 +516,18 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* {@code true} otherwise.
*/
@Override
- public synchronized boolean getAnyDataEnabled() {
- if (!(mInternalDataEnabled && mDataEnabled)) return false;
- for (ApnContext apnContext : mApnContexts.values()) {
- // Make sure we dont have a context that going down
- // and is explicitly disabled.
- if (isDataAllowed(apnContext)) {
- return true;
+ public boolean getAnyDataEnabled() {
+ synchronized (mDataEnabledLock) {
+ if (!(mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled)) return false;
+ for (ApnContext apnContext : mApnContexts.values()) {
+ // Make sure we dont have a context that going down
+ // and is explicitly disabled.
+ if (isDataAllowed(apnContext)) {
+ return true;
+ }
}
+ return false;
}
- return false;
}
private boolean isDataAllowed(ApnContext apnContext) {
@@ -570,6 +565,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
protected boolean isDataAllowed() {
+ final boolean internalDataEnabled;
+ synchronized (mDataEnabledLock) {
+ internalDataEnabled = mInternalDataEnabled;
+ }
+
int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState();
boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
@@ -577,7 +577,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
(gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
mPhone.mIccRecords.getRecordsLoaded() &&
mPhone.getState() == Phone.State.IDLE &&
- mInternalDataEnabled &&
+ internalDataEnabled &&
(!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
!mIsPsRestricted &&
desiredPowerState;
@@ -590,7 +590,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (mPhone.getState() != Phone.State.IDLE) {
reason += " - PhoneState= " + mPhone.getState();
}
- if (!mInternalDataEnabled) reason += " - mInternalDataEnabled= false";
+ if (!internalDataEnabled) reason += " - mInternalDataEnabled= false";
if (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()) {
reason += " - Roaming and data roaming not enabled";
}
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index c20c716..956c3f2 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -16,23 +16,20 @@
package android.net.wifi;
-
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.net.ConnectivityManager;
import android.net.LinkCapabilities;
-import android.net.NetworkInfo;
import android.net.LinkProperties;
+import android.net.NetworkInfo;
import android.net.NetworkStateTracker;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Handler;
import android.os.Message;
+import android.util.Slog;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* Track the state of wifi for connectivity service.
@@ -44,6 +41,8 @@ public class WifiStateTracker implements NetworkStateTracker {
private static final String NETWORKTYPE = "WIFI";
private static final String TAG = "WifiStateTracker";
+ private static final boolean LOGV = true;
+
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
@@ -135,11 +134,14 @@ public class WifiStateTracker implements NetworkStateTracker {
return mNetworkInfo.isAvailable();
}
- /**
- * @param enabled
- */
- public void setDataEnable(boolean enabled) {
- android.util.Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled);
+ @Override
+ public void setUserDataEnable(boolean enabled) {
+ Slog.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
+ }
+
+ @Override
+ public void setPolicyDataEnable(boolean enabled) {
+ Slog.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
}
/**