Proactively disable data when over policy limit.

Add policy controls to NetworkStateTracker which are combined with
other user preference and internal flags to decide if data connection
should be established.  Better locking around enabled flags.

When data network would be over limit, proactively disable data on
that network.  Enable when policy is snoozed or when cycle resets.

Track and dismiss notifications from now-stale policies.

Bug: 4587023, 5178147
Change-Id: Ibfcc9f73cda7c369209af701b46eddd3d1943f2d
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 @@
     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/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.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.GregorianCalendar;
 import java.util.HashSet;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * @hide
@@ -251,6 +249,12 @@
     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 @@
             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 @@
                     sendStickyBroadcast(intent);
                     break;
                 }
+                case EVENT_SET_POLICY_DATA_ENABLE: {
+                    final int networkType = msg.arg1;
+                    final boolean enabled = msg.arg2 == ENABLED;
+                    handleSetPolicyDataEnable(networkType, enabled);
+                }
             }
         }
     }