Implement user-settable power save whitelist.

The whitelist is now maintained by DeviceIdleController,
which is moving out into its own independent system service.
Network stats now queries it for the whitelist, instead of
collecting that itself.

Also did a few improvements in alarm manager -- made the
code for moving alarms out of the pending list more robust,
and fixed the debug output to always print the contents of
the pending list even if we aren't in a pending state.  (That
would have helped me identify the problem much earlier.)

Change-Id: I0f7119d4c553c3af4d77b2f71246fa6e2c13c561
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 818f0aa..e45092c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -110,13 +110,16 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IDeviceIdleController;
 import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
+import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -138,6 +141,7 @@
 import android.util.Xml;
 
 import com.android.server.AppOpsService;
+import com.android.server.DeviceIdleController;
 import libcore.io.IoUtils;
 
 import com.android.internal.R;
@@ -245,6 +249,7 @@
     private IConnectivityManager mConnManager;
     private INotificationManager mNotifManager;
     private PowerManagerInternal mPowerManagerInternal;
+    private IDeviceIdleController mDeviceIdleController;
 
     final Object mRulesLock = new Object();
 
@@ -321,6 +326,8 @@
         mPowerManager = checkNotNull(powerManager, "missing powerManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
         mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
+        mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
+                DeviceIdleController.SERVICE_NAME));
         mTime = checkNotNull(time, "missing TrustedTime");
 
         HandlerThread thread = new HandlerThread(TAG);
@@ -342,28 +349,27 @@
         mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
     }
 
+    void updatePowerSaveWhitelistLocked() {
+        try {
+            final int[] whitelist = mDeviceIdleController.getAppIdWhitelist();
+            mPowerSaveWhitelistAppIds.clear();
+            if (whitelist != null) {
+                for (int uid : whitelist) {
+                    mPowerSaveWhitelistAppIds.put(uid, true);
+                }
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
     public void systemReady() {
         if (!isBandwidthControlEnabled()) {
             Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
             return;
         }
 
-        final PackageManager pm = mContext.getPackageManager();
-
         synchronized (mRulesLock) {
-            SystemConfig sysConfig = SystemConfig.getInstance();
-            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
-            for (int i=0; i<allowPower.size(); i++) {
-                String pkg = allowPower.valueAt(i);
-                try {
-                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
-                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
-                        mPowerSaveWhitelistAppIds.put(UserHandle.getAppId(ai.uid), true);
-                    }
-                } catch (PackageManager.NameNotFoundException e) {
-                }
-            }
-
+            updatePowerSaveWhitelistLocked();
             mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
             mPowerManagerInternal.registerLowPowerModeObserver(
                     new PowerManagerInternal.LowPowerModeListener() {
@@ -406,6 +412,11 @@
         screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
         mContext.registerReceiver(mScreenReceiver, screenFilter);
 
+        // listen for changes to power save whitelist
+        final IntentFilter whitelistFilter = new IntentFilter(
+                PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+        mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
+
         // watch for network interfaces to be claimed
         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
@@ -489,6 +500,17 @@
         }
     };
 
+    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) {
+                updatePowerSaveWhitelistLocked();
+                updateRulesForGlobalChangeLocked(false);
+            }
+        }
+    };
+
     private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -1528,20 +1550,6 @@
         return uids;
     }
 
-    @Override
-    public int[] getPowerSaveAppIdWhitelist() {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-
-        synchronized (mRulesLock) {
-            int size = mPowerSaveWhitelistAppIds.size();
-            int[] appids = new int[size];
-            for (int i = 0; i < size; i++) {
-                appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
-            }
-            return appids;
-        }
-    }
-
     /**
      * Remove any policies associated with given {@link UserHandle}, persisting
      * if any changes are made.