More Data Saver / Battery Saver modes cleanup

When Battery Saver mode was first implemented, there were no firewall rules
on netd, so the solution was to make all network interface metered and
re-use the bw_penalty_box chain.

Recently, a fw_powersave chain was created with the purpose of
separating these 2 concerns, but some scenarios were no properly
handled.

This change further cleans up the code by:

- Creating a updateRestrictionRulesForUidLocked() to be used when both
  Battery Saver and Power Save rules need to be re-evaluated.
- Renaming some methods to be more consistent with others.
- Disabling rules for apps that do not have internet permissions.
- Updating network stats only when process status changes.
- Only updating Battery Saver rules when they changed.

BUG: 27127112
BUG: 26685616

Change-Id: I75fbc9733b8989fadcb10ebc154e214e3d256fe9
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 9b92e4f..c75e287 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -687,7 +687,7 @@
                 // global background data policy
                 if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
                 synchronized (mRulesLock) {
-                    updateRestrictDataRulesForUidLocked(uid);
+                    updateRestrictionRulesForUidLocked(uid);
                 }
             }
         }
@@ -705,7 +705,7 @@
             if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
             synchronized (mRulesLock) {
                 mUidPolicy.delete(uid);
-                updateRestrictDataRulesForUidLocked(uid);
+                updateRuleForRestrictBackgroundLocked(uid);
                 writePolicyLocked();
             }
         }
@@ -1678,7 +1678,7 @@
         mUidPolicy.put(uid, policy);
 
         // uid policy changed, recompute rules and persist policy.
-        updateRestrictDataRulesForUidLocked(uid);
+        updateRuleForRestrictBackgroundLocked(uid);
         if (persist) {
             writePolicyLocked();
         }
@@ -1897,7 +1897,7 @@
             maybeRefreshTrustedTime();
             synchronized (mRulesLock) {
                 mRestrictBackground = restrictBackground;
-                updateRulesForRestrictDataLocked();
+                updateRulesForRestrictBackgroundLocked();
                 updateNotificationsLocked();
                 writePolicyLocked();
             }
@@ -2272,7 +2272,7 @@
 
                 final int rule = mUidRules.get(uid, RULE_UNKNOWN);
                 fout.print(" rule=");
-                fout.print(DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule));
+                fout.print(ruleToString(rule));
 
                 fout.println();
             }
@@ -2280,6 +2280,10 @@
         }
     }
 
+    private String ruleToString(int rule) {
+        return DebugUtils.valueToString(NetworkPolicyManager.class, "RULE_", rule);
+    }
+
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ResultReceiver resultReceiver) throws RemoteException {
@@ -2296,57 +2300,73 @@
         }
     }
 
-    boolean isUidForegroundLocked(int uid) {
+    private boolean isUidForegroundLocked(int uid) {
+        return isUidStateForegroundLocked(
+                mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY));
+    }
+
+    private boolean isUidStateForegroundLocked(int state) {
         // only really in foreground when screen is also on
-        return mScreenOn && mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY)
-                <= ActivityManager.PROCESS_STATE_TOP;
+        return mScreenOn && state <= ActivityManager.PROCESS_STATE_TOP;
     }
 
     /**
      * Process state of UID changed; if needed, will trigger
      * {@link #updateRestrictDataRulesForUidLocked(int)}.
      */
-    void updateUidStateLocked(int uid, int uidState) {
+    private void updateUidStateLocked(int uid, int uidState) {
         final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         if (oldUidState != uidState) {
             // state changed, push updated rules
             mUidState.put(uid, uidState);
-            updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
+            updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState, uidState);
             if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
                     != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
                 if (mDeviceIdleMode) {
                     updateRuleForDeviceIdleLocked(uid);
                 }
                 if (mRestrictPower) {
-                    updateRulesForRestrictPowerLocked(uid);
+                    updateRuleForRestrictPowerLocked(uid);
                 }
             }
+            updateNetworkStats(uid, isUidStateForegroundLocked(uidState));
         }
     }
 
-    void removeUidStateLocked(int uid) {
+    private void removeUidStateLocked(int uid) {
         final int index = mUidState.indexOfKey(uid);
         if (index >= 0) {
             final int oldUidState = mUidState.valueAt(index);
             mUidState.removeAt(index);
             if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
-                updateRulesForUidStateChangeLocked(uid, oldUidState,
+                updateRestrictBackgroundRulesOnUidStatusChangedLocked(uid, oldUidState,
                         ActivityManager.PROCESS_STATE_CACHED_EMPTY);
                 if (mDeviceIdleMode) {
                     updateRuleForDeviceIdleLocked(uid);
                 }
                 if (mRestrictPower) {
-                    updateRulesForRestrictPowerLocked(uid);
+                    updateRuleForRestrictPowerLocked(uid);
                 }
+                updateNetworkStats(uid, false);
             }
         }
     }
 
-    void updateRulesForUidStateChangeLocked(int uid, int oldUidState, int newUidState) {
+    // adjust stats accounting based on foreground status
+    private void updateNetworkStats(int uid, boolean uidForeground) {
+        try {
+            mNetworkStats.setUidForeground(uid, uidForeground);
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+    }
+
+    private void updateRestrictBackgroundRulesOnUidStatusChangedLocked(int uid, int oldUidState,
+            int newUidState) {
         final boolean oldForeground = oldUidState <= ActivityManager.PROCESS_STATE_TOP;
         final boolean newForeground = newUidState <= ActivityManager.PROCESS_STATE_TOP;
         if (oldForeground != newForeground) {
-            updateRestrictDataRulesForUidLocked(uid);
+            updateRuleForRestrictBackgroundLocked(uid);
         }
     }
 
@@ -2370,7 +2390,7 @@
         for (int i = 0; i < size; i++) {
             if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_TOP) {
                 final int uid = mUidState.keyAt(i);
-                updateRestrictDataRulesForUidLocked(uid);
+                updateRestrictionRulesForUidLocked(uid);
             }
         }
     }
@@ -2384,7 +2404,7 @@
                 mUidFirewallPowerSaveRules);
     }
 
-    void updateRulesForRestrictPowerLocked(int uid) {
+    void updateRuleForRestrictPowerLocked(int uid) {
         updateRulesForWhitelistedPowerSaveLocked(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
     }
 
@@ -2397,8 +2417,8 @@
         updateRulesForWhitelistedPowerSaveLocked(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
     }
 
-    // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
-    // for whitelisting, we can reuse their logic in this method.
+    // NOTE: since both fw_dozable and fw_powersave uses the same map
+    // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
     private void updateRulesForWhitelistedPowerSaveLocked(boolean enabled, int chain,
             SparseIntArray rules) {
         if (enabled) {
@@ -2433,8 +2453,8 @@
         enableFirewallChainLocked(chain, enabled);
     }
 
-    // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
-    // for whitelisting, we can reuse their logic in this method.
+    // NOTE: since both fw_dozable and fw_powersave uses the same map
+    // (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
     private void updateRulesForWhitelistedPowerSaveLocked(int uid, boolean enabled, int chain) {
         if (enabled) {
             int appId = UserHandle.getAppId(uid);
@@ -2452,7 +2472,6 @@
         uidRules.clear();
 
         // Fully update the app idle firewall chain.
-        final IPackageManager ipm = AppGlobals.getPackageManager();
         final List<UserInfo> users = mUserManager.getUsers();
         for (int ui = users.size() - 1; ui >= 0; ui--) {
             UserInfo user = users.get(ui);
@@ -2499,7 +2518,7 @@
         updateRulesForDeviceIdleLocked();
         updateRulesForAppIdleLocked();
         updateRulesForRestrictPowerLocked();
-        updateRulesForRestrictDataLocked();
+        updateRulesForRestrictBackgroundLocked();
 
         // If the set of restricted networks may have changed, re-evaluate those.
         if (restrictedNetworksChanged) {
@@ -2513,7 +2532,7 @@
         }
     }
 
-    private void updateRulesForRestrictDataLocked() {
+    private void updateRulesForRestrictBackgroundLocked() {
         final PackageManager pm = mContext.getPackageManager();
 
         // update rules for all installed applications
@@ -2530,13 +2549,13 @@
             for (int j = 0; j < appsSize; j++) {
                 final ApplicationInfo app = apps.get(j);
                 final int uid = UserHandle.getUid(user.id, app.uid);
-                updateRestrictDataRulesForUidLocked(uid);
+                updateRuleForRestrictBackgroundLocked(uid);
             }
         }
 
         // limit data usage for some internal system services
-        updateRestrictDataRulesForUidLocked(android.os.Process.MEDIA_UID);
-        updateRestrictDataRulesForUidLocked(android.os.Process.DRM_UID);
+        updateRuleForRestrictBackgroundLocked(android.os.Process.MEDIA_UID);
+        updateRuleForRestrictBackgroundLocked(android.os.Process.DRM_UID);
     }
 
     private void updateRulesForTempWhitelistChangeLocked() {
@@ -2548,15 +2567,15 @@
                 int uid = UserHandle.getUid(user.id, appId);
                 updateRuleForAppIdleLocked(uid);
                 updateRuleForDeviceIdleLocked(uid);
-                updateRulesForRestrictPowerLocked(uid);
+                updateRuleForRestrictPowerLocked(uid);
             }
         }
     }
 
-    private static boolean isUidValidForRules(int uid) {
-        // allow rules on specific system services, and any apps
+    private boolean isUidValidForRules(int uid) {
+        // allow rules on specific system services, and any apps (that have network access)
         if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
-                || UserHandle.isApp(uid)) {
+                || (UserHandle.isApp(uid) && hasInternetPermissions(uid))) {
             return true;
         }
 
@@ -2594,12 +2613,21 @@
     }
 
     /**
-     * Applies network rules to bandwidth controllers based on uid policy.
+     * Applies network rules to bandwidth and firewall controllers based on uid policy.
      *
-     * @param uid The uid for which to apply the latest policy
+     * <p>There are currently 2 types of restriction rules:
+     * <ul>
+     * <li>Battery Saver Mode (also referred as power save).
+     * <li>Data Saver Mode (formerly known as restrict background data).
+     * </ul>
      */
-    private void updateRestrictDataRulesForUidLocked(int uid) {
-        if (!isUidValidForRules(uid) || !hasInternetPermissions(uid)) return;
+    private void updateRestrictionRulesForUidLocked(int uid) {
+        updateRuleForRestrictPowerLocked(uid);
+        updateRuleForRestrictBackgroundLocked(uid);
+    }
+
+    private void updateRuleForRestrictBackgroundLocked(int uid) {
+        if (!isUidValidForRules(uid)) return;
 
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
         final boolean uidForeground = isUidForegroundLocked(uid);
@@ -2618,8 +2646,10 @@
         }
 
         final int oldRule = mUidRules.get(uid);
-        if (LOGV) Log.v(TAG, "updateBandwithControllerRulesForUidLocked(" + uid + "): oldRule = "
-                + oldRule + ", newRule = " + newRule);
+        if (LOGV) {
+            Log.v(TAG, "updateRulesForRestrictBackgroundLocked(" + uid + "): oldRule = "
+                + ruleToString(oldRule) + ", newRule = " + ruleToString(newRule));
+        }
 
         if (newRule == RULE_ALLOW_ALL) {
             mUidRules.delete(uid);
@@ -2627,20 +2657,14 @@
             mUidRules.put(uid, newRule);
         }
 
-        final boolean rejectMetered = (newRule == RULE_REJECT_METERED);
-        setUidNetworkRules(uid, rejectMetered);
-
-        // dispatch changed rule to existing listeners
         if (oldRule != newRule) {
+            final boolean rejectMetered = (newRule == RULE_REJECT_METERED);
+            setUidNetworkRules(uid, rejectMetered);
+
+            // dispatch changed rule to existing listeners
             mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newRule).sendToTarget();
         }
 
-        try {
-            // adjust stats accounting based on foreground status
-            mNetworkStats.setUidForeground(uid, uidForeground);
-        } catch (RemoteException e) {
-            // ignored; service lives in system_server
-        }
     }
 
     private class AppIdleStateChangeListener