Update power manager to track uid state like netstats.

To follow the correct semantics for when restricts due to
device idle can be applied, power manager need to know about
uid process states like net policy so that it can allow
wake locks from apps that are in the foreground.

Since this is being added to a second place, I reworked things
so that the activity manager now keeps track of per-uid process
states and allows apps to register to listen to those, rather
than having to track lower-level process states and transform
them into an overall uid state.  Both net policy and power
manager use this new facility.

Change-Id: I77359164c40d0f36fe1ef296dd9f9c3062431148
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1e9bc54..c83a45b 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1970,6 +1970,22 @@
             return true;
         }
 
+        case REGISTER_UID_OBSERVER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IUidObserver observer = IUidObserver.Stub.asInterface(
+                    data.readStrongBinder());
+            registerUidObserver(observer);
+            return true;
+        }
+
+        case UNREGISTER_UID_OBSERVER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IUidObserver observer = IUidObserver.Stub.asInterface(
+                    data.readStrongBinder());
+            unregisterUidObserver(observer);
+            return true;
+        }
+
         case GET_PACKAGE_ASK_SCREEN_COMPAT_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -5084,6 +5100,28 @@
         reply.recycle();
     }
 
+    public void registerUidObserver(IUidObserver observer) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+        mRemote.transact(REGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    public void unregisterUidObserver(IUidObserver observer) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(observer != null ? observer.asBinder() : null);
+        mRemote.transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 05a936c..a7c5cb9 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -387,6 +387,9 @@
     public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
     public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
 
+    public void registerUidObserver(IUidObserver observer) throws RemoteException;
+    public void unregisterUidObserver(IUidObserver observer) throws RemoteException;
+
     public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;
 
     public boolean isIntentSenderAnActivity(IIntentSender sender) throws RemoteException;
@@ -846,4 +849,6 @@
     int UPDATE_DEVICE_OWNER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+295;
     int UPDATE_PREFERRED_SETUP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+296;
     int KEYGUARD_GOING_AWAY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+297;
+    int REGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+298;
+    int UNREGISTER_UID_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+299;
 }
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
new file mode 100644
index 0000000..308cb94
--- /dev/null
+++ b/core/java/android/app/IUidObserver.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/** {@hide} */
+oneway interface IUidObserver {
+    void onUidStateChanged(int uid, int procState);
+    void onUidGone(int uid);
+}
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 9a0d0d0..e523285 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -136,4 +136,8 @@
     public abstract void setDeviceIdleMode(boolean enabled);
 
     public abstract void setDeviceIdleWhitelist(int[] appids);
+
+    public abstract void updateUidProcState(int uid, int procState);
+
+    public abstract void uidGone(int uid);
 }
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 92e874f..dc965ed 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -134,6 +134,24 @@
     }
 
     /**
+     * @hide
+     * Removes the mapping from the specified key, if there was any, returning the old value.
+     */
+    public E removeReturnOld(int key) {
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+
+        if (i >= 0) {
+            if (mValues[i] != DELETED) {
+                final E old = (E) mValues[i];
+                mValues[i] = DELETED;
+                mGarbage = true;
+                return old;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Alias for {@link #delete(int)}.
      */
     public void remove(int key) {
diff --git a/core/java/com/android/internal/app/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java
index 6ff0304..23a8bd7 100644
--- a/core/java/com/android/internal/app/ProcessMap.java
+++ b/core/java/com/android/internal/app/ProcessMap.java
@@ -39,14 +39,16 @@
         return value;
     }
     
-    public void remove(String name, int uid) {
+    public E remove(String name, int uid) {
         SparseArray<E> uids = mMap.get(name);
         if (uids != null) {
-            uids.remove(uid);
+            final E old = uids.removeReturnOld(uid);
             if (uids.size() == 0) {
                 mMap.remove(name);
             }
+            return old;
         }
+        return null;
     }
     
     public ArrayMap<String, SparseArray<E>> getMap() {