Data usage notifs, newly installed apps, defaults.

Only show warning/limit notifications for active networks, since they
aren't actionable for inactive IMSI.  Include IMSI in debug output on
engineering builds.

Move default policy warning to be configured through overlay.  Watch
for newly installed packages to enforce global policy.

Bug: 5038729, 5038541, 4979026, 5023634
Change-Id: I8fc8ab4c23c440a3091504ea16133ed6ababf58e
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index ccef122..aa6400b 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -19,6 +19,7 @@
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
 
 import android.content.Context;
+import android.os.Build;
 import android.telephony.TelephonyManager;
 
 import com.android.internal.util.Objects;
@@ -68,7 +69,7 @@
             subTypeName = Integer.toString(mSubType);
         }
 
-        final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+        final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
         final String roaming = mRoaming ? ", ROAMING" : "";
         return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId="
                 + scrubSubscriberId + roaming + "]";
@@ -91,6 +92,17 @@
     }
 
     /**
+     * Scrub given IMSI on production builds.
+     */
+    public static String scrubSubscriberId(String subscriberId) {
+        if ("eng".equals(Build.TYPE)) {
+            return subscriberId;
+        } else {
+            return subscriberId != null ? "valid" : "null";
+        }
+    }
+
+    /**
      * Build a {@link NetworkIdentity} from the given {@link NetworkState},
      * assuming that any mobile networks are using the current IMSI.
      */
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 1ef0d9d..cd49023 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -16,10 +16,11 @@
 
 package android.net;
 
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.NetworkIdentity.scrubSubscriberId;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
@@ -119,7 +120,7 @@
 
     @Override
     public String toString() {
-        final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+        final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
         return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId="
                 + scrubSubscriberId;
     }
@@ -150,7 +151,7 @@
     }
 
     /**
-     * Test if this network matches the given template and IMEI.
+     * Test if this network matches the given template and IMSI.
      */
     public boolean matches(NetworkIdentity ident) {
         switch (mMatchRule) {
@@ -170,7 +171,7 @@
     }
 
     /**
-     * Check if mobile network with matching IMEI. Also matches
+     * Check if mobile network with matching IMSI. Also matches
      * {@link #TYPE_WIMAX}.
      */
     private boolean matchesMobile(NetworkIdentity ident) {
@@ -183,7 +184,7 @@
     }
 
     /**
-     * Check if mobile network classified 3G or lower with matching IMEI.
+     * Check if mobile network classified 3G or lower with matching IMSI.
      */
     private boolean matchesMobile3gLower(NetworkIdentity ident) {
         if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) {
@@ -198,7 +199,7 @@
     }
 
     /**
-     * Check if mobile network classified 4G with matching IMEI. Also matches
+     * Check if mobile network classified 4G with matching IMSI. Also matches
      * {@link #TYPE_WIMAX}.
      */
     private boolean matchesMobile4g(NetworkIdentity ident) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1f2b7fb..215700c 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -665,4 +665,7 @@
     <!-- Timeout to wait for NTP server response. -->
     <integer name="config_ntpTimeout">20000</integer>
 
+    <!-- Default network policy warning threshold, in megabytes. -->
+    <integer name="config_networkPolicyDefaultWarning">2048</integer>
+
 </resources>
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 0c78fe7..435c394 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -22,6 +22,7 @@
 import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
 import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
 import static android.Manifest.permission.READ_PHONE_STATE;
+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.ACTION_BACKGROUND_DATA_SETTING_CHANGED;
@@ -174,10 +175,12 @@
 
     /** Current policy for network templates. */
     private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
+    /** Current derived network rules for ifaces. */
+    private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
 
     /** Current policy for each UID. */
     private SparseIntArray mUidPolicy = new SparseIntArray();
-    /** Current derived network rules for each UID. */
+    /** Current derived rules for each UID. */
     private SparseIntArray mUidRules = new SparseIntArray();
 
     /** Set of ifaces that are metered. */
@@ -199,8 +202,6 @@
     // TODO: keep whitelist of system-critical services that should never have
     // rules enforced, such as system, phone, and radio UIDs.
 
-    // TODO: watch for package added broadcast to catch new UIDs.
-
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             IPowerManager powerManager, INetworkStatsService networkStats,
             INetworkManagementService networkManagement) {
@@ -242,7 +243,6 @@
         synchronized (mRulesLock) {
             // read policy from disk
             readPolicyLocked();
-            updateNotificationsLocked();
         }
 
         updateScreenOn();
@@ -268,9 +268,12 @@
         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
 
-        // listen for uid removal to clean policy
-        final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
-        mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
+        // listen for package/uid changes to update policy
+        final IntentFilter packageFilter = new IntentFilter();
+        packageFilter.addAction(ACTION_PACKAGE_ADDED);
+        packageFilter.addAction(ACTION_UID_REMOVED);
+        packageFilter.addDataScheme("package");
+        mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
 
         // listen for stats update events
         final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
@@ -331,17 +334,28 @@
         }
     };
 
-    private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
+    private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            // on background handler thread, and UID_REMOVED is protected
-            // broadcast.
+            // on background handler thread, and PACKAGE_ADDED and UID_REMOVED
+            // are protected broadcasts.
+
+            final String action = intent.getAction();
             final int uid = intent.getIntExtra(EXTRA_UID, 0);
             synchronized (mRulesLock) {
-                // remove any policy and update rules to clean up
-                mUidPolicy.delete(uid);
-                updateRulesForUidLocked(uid);
-                writePolicyLocked();
+                if (ACTION_PACKAGE_ADDED.equals(action)) {
+                    // update rules for UID, since it might be subject to
+                    // global background data policy.
+                    if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
+                    updateRulesForUidLocked(uid);
+
+                } else if (ACTION_UID_REMOVED.equals(action)) {
+                    // remove any policy and update rules to clean up.
+                    if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
+                    mUidPolicy.delete(uid);
+                    updateRulesForUidLocked(uid);
+                    writePolicyLocked();
+                }
             }
         }
     };
@@ -396,8 +410,8 @@
         // TODO: when switching to kernel notifications, compute next future
         // cycle boundary to recompute notifications.
 
-        // examine stats for each policy defined
-        for (NetworkPolicy policy : mNetworkPolicy) {
+        // examine stats for each active policy
+        for (NetworkPolicy policy : mNetworkRules.keySet()) {
             final long start = computeLastCycleBoundary(currentTime, policy);
             final long end = currentTime;
 
@@ -424,6 +438,15 @@
                     cancelNotification(policy, TYPE_WARNING);
                 }
             }
+
+        }
+
+        // clear notifications for non-active policies
+        for (NetworkPolicy policy : mNetworkPolicy) {
+            if (!mNetworkRules.containsKey(policy)) {
+                cancelNotification(policy, TYPE_WARNING);
+                cancelNotification(policy, TYPE_LIMIT);
+            }
         }
     }
 
@@ -531,7 +554,8 @@
             // permission above.
             synchronized (mRulesLock) {
                 ensureActiveMobilePolicyLocked();
-                updateIfacesLocked();
+                updateNetworkRulesLocked();
+                updateNotificationsLocked();
             }
         }
     };
@@ -541,7 +565,7 @@
      * {@link NetworkPolicy} that need to be enforced. When matches found, set
      * remaining quota based on usage cycle and historical stats.
      */
-    private void updateIfacesLocked() {
+    private void updateNetworkRulesLocked() {
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
 
         final NetworkState[] states;
@@ -565,7 +589,7 @@
         }
 
         // build list of rules and ifaces to enforce them against
-        final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
+        mNetworkRules.clear();
         final ArrayList<String> ifaceList = Lists.newArrayList();
         for (NetworkPolicy policy : mNetworkPolicy) {
 
@@ -580,7 +604,7 @@
 
             if (ifaceList.size() > 0) {
                 final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
-                rules.put(policy, ifaces);
+                mNetworkRules.put(policy, ifaces);
             }
         }
 
@@ -596,8 +620,8 @@
 
         // apply each policy that we found ifaces for; compute remaining data
         // based on current cycle and historical stats, and push to kernel.
-        for (NetworkPolicy policy : rules.keySet()) {
-            final String[] ifaces = rules.get(policy);
+        for (NetworkPolicy policy : mNetworkRules.keySet()) {
+            final String[] ifaces = mNetworkRules.get(policy);
 
             final long start = computeLastCycleBoundary(currentTime, policy);
             final long end = currentTime;
@@ -670,17 +694,17 @@
         if (!mobileDefined) {
             Slog.i(TAG, "no policy for active mobile network; generating default policy");
 
-            // default mobile policy has combined 4GB warning, and assume usage
-            // cycle starts today today.
+            // 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;
 
-            // TODO: move this policy definition to overlay or secure setting
             final Time time = new Time(Time.TIMEZONE_UTC);
             time.setToNow();
             final int cycleDay = time.monthDay;
 
             final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
-            mNetworkPolicy.add(
-                    new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
+            mNetworkPolicy.add(new NetworkPolicy(template, cycleDay, warningBytes, LIMIT_DISABLED));
             writePolicyLocked();
         }
     }
@@ -859,7 +883,7 @@
                 mNetworkPolicy.add(policy);
             }
 
-            updateIfacesLocked();
+            updateNetworkRulesLocked();
             updateNotificationsLocked();
             writePolicyLocked();
         }