Fix issue #21626564: MMS should be receivied while Dozing

We now place whoever is receiving the MMS on the temporary
whitelist while doing so, so they can get network access to
download it.

There was also an issue that needed to be fixed where we
were no longer updating the list of allowed uids while
dozing based on their proc states...  we now do that.

Also did a bit of optimization of the temp white list update
path do the network policy manager, instead of going through
a broadcast we now directly call in to the network policy
manager.  This also allows us to have a synchronous version
of updating the list, so we can know the app has network access
before we tell it to do anything.

Finally added battery stats events for things going on and off
the whitelist so we can diagnose the behavior there.

Change-Id: Ic7fe010af680034d9f8cb014bb135b2addef7455
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f8f00ef..395aa27 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -147,6 +147,7 @@
 import android.util.TrustedTime;
 import android.util.Xml;
 
+import com.android.server.DeviceIdleController;
 import com.android.server.EventLogTags;
 import libcore.io.IoUtils;
 
@@ -462,9 +463,12 @@
         // listen for changes to power save whitelist
         final IntentFilter whitelistFilter = new IntentFilter(
                 PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
-        whitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
         mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
 
+        DeviceIdleController.LocalService deviceIdleService
+                = LocalServices.getService(DeviceIdleController.LocalService.class);
+        deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
+
         // watch for network interfaces to be claimed
         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
@@ -512,7 +516,7 @@
 
     }
 
-    private IUidObserver mUidObserver = new IUidObserver.Stub() {
+    final private IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
             synchronized (mRulesLock) {
                 updateUidStateLocked(uid, procState);
@@ -526,24 +530,29 @@
         }
     };
 
-    private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
             synchronized (mRulesLock) {
-                if (PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(intent.getAction())) {
-                    updatePowerSaveWhitelistLocked();
-                    updateRulesForGlobalChangeLocked(false);
-                } else {
-                    updatePowerSaveTempWhitelistLocked();
-                    updateRulesForTempWhitelistChangeLocked();
-                    purgePowerSaveTempWhitelistLocked();
-                }
+                updatePowerSaveWhitelistLocked();
+                updateRulesForGlobalChangeLocked(false);
             }
         }
     };
 
-    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
+    final private Runnable mTempPowerSaveChangedCallback = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mRulesLock) {
+                updatePowerSaveTempWhitelistLocked();
+                updateRulesForTempWhitelistChangeLocked();
+                purgePowerSaveTempWhitelistLocked();
+            }
+        }
+    };
+
+    final private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // screen-related broadcasts are protected by system, no need
@@ -552,7 +561,7 @@
         }
     };
 
-    private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and PACKAGE_ADDED is protected
@@ -572,7 +581,7 @@
         }
     };
 
-    private BroadcastReceiver mUidRemovedReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mUidRemovedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and UID_REMOVED is protected
@@ -590,7 +599,7 @@
         }
     };
 
-    private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and USER_ADDED and USER_REMOVED
@@ -619,7 +628,7 @@
      * Receiver that watches for {@link INetworkStatsService} updates, which we
      * use to check against {@link NetworkPolicy#warningBytes}.
      */
-    private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified
@@ -637,7 +646,7 @@
      * Receiver that watches for {@link Notification} control of
      * {@link #mRestrictBackground}.
      */
-    private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified MANAGE_NETWORK_POLICY
@@ -651,7 +660,7 @@
      * Receiver that watches for {@link Notification} control of
      * {@link NetworkPolicy#lastWarningSnooze}.
      */
-    private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified MANAGE_NETWORK_POLICY
@@ -665,7 +674,7 @@
     /**
      * Receiver that watches for {@link WifiConfiguration} to be changed.
      */
-    private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified CONNECTIVITY_INTERNAL
@@ -692,7 +701,7 @@
      * Receiver that watches {@link WifiInfo} state changes to infer metered
      * state. Ignores hints when policy is user-defined.
      */
-    private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified CONNECTIVITY_INTERNAL
@@ -732,7 +741,8 @@
     /**
      * Observer that watches for {@link INetworkManagementService} alerts.
      */
-    private INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() {
+    final private INetworkManagementEventObserver mAlertObserver
+            = new BaseNetworkObserver() {
         @Override
         public void limitReached(String limitName, String iface) {
             // only someone like NMS should be calling us
@@ -1985,6 +1995,10 @@
             // state changed, push updated rules
             mUidState.put(uid, uidState);
             updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
+            if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState)
+                    != isProcStateAllowedWhileIdle(uidState)) {
+                updateRulesForDeviceIdleLocked();
+            }
         }
     }
 
@@ -1996,6 +2010,9 @@
             if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
                 updateRulesForUidStateChangeLocked(uid, oldUidState,
                         ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+                if (mDeviceIdleMode) {
+                    updateRulesForDeviceIdleLocked();
+                }
             }
         }
     }
@@ -2033,13 +2050,18 @@
         }
     }
 
+    static boolean isProcStateAllowedWhileIdle(int procState) {
+        return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+    }
+
     void updateRulesForDeviceIdleLocked() {
         if (mDeviceIdleMode) {
             // sync the whitelists before enable dozable chain.  We don't care about the rules if
             // we are disabling the chain.
             SparseIntArray uidRules = new SparseIntArray();
             final List<UserInfo> users = mUserManager.getUsers();
-            for (UserInfo user : users) {
+            for (int ui = users.size() - 1; ui >= 0; ui--) {
+                UserInfo user = users.get(ui);
                 for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
                     int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
                     int uid = UserHandle.getUid(user.id, appId);
@@ -2051,6 +2073,11 @@
                     uidRules.put(uid, FIREWALL_RULE_ALLOW);
                 }
             }
+            for (int i = mUidState.size() - 1; i >= 0; i--) {
+                if (isProcStateAllowedWhileIdle(mUidState.valueAt(i))) {
+                    uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
+                }
+            }
             setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
         }
         enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);