Various infrastructure to support a running services UI.

Some of this is temporary (in particular the two approaches for getting
process memory, one working but horrible, the other not working but
preferred) until I figure out the best way to do it.

Change-Id: I8c8f25062d481fcea22a47d459b083d2fd8a5040
diff --git a/api/current.xml b/api/current.xml
index 7e6c2df..46dfd89 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -18039,6 +18039,50 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_FOREGROUND"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_PERSISTENT_PROCESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_STARTED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_SYSTEM_PROCESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="activeSince"
  type="long"
  transient="false"
@@ -18069,6 +18113,16 @@
  visibility="public"
 >
 </field>
+<field name="flags"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="foreground"
  type="boolean"
  transient="false"
@@ -18139,6 +18193,16 @@
  visibility="public"
 >
 </field>
+<field name="uid"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="ActivityManager.RunningTaskInfo"
  extends="java.lang.Object"
@@ -97544,6 +97608,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<implements name="android.os.Parcelable">
+</implements>
 <constructor name="Debug.MemoryInfo"
  type="android.os.Debug.MemoryInfo"
  static="false"
@@ -97552,6 +97618,55 @@
  visibility="public"
 >
 </constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="readFromParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.os.Parcel">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="dalvikPrivateDirty"
  type="int"
  transient="false"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 07520c9d..ad06fa9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -289,6 +289,11 @@
         public int pid;
         
         /**
+         * The UID that owns this service.
+         */
+        public int uid;
+        
+        /**
          * The name of the process this service runs in.
          */
         public String process;
@@ -299,7 +304,7 @@
         public boolean foreground;
         
         /**
-         * The time when the service was first made activity, either by someone
+         * The time when the service was first made active, either by someone
          * starting or binding to it.
          */
         public long activeSince;
@@ -332,6 +337,35 @@
          */
         public long restarting;
         
+        /**
+         * Bit for {@link #flags}: set if this service has been
+         * explicitly started.
+         */
+        public static final int FLAG_STARTED = 1<<0;
+        
+        /**
+         * Bit for {@link #flags}: set if the service has asked to
+         * run as a foreground process.
+         */
+        public static final int FLAG_FOREGROUND = 1<<1;
+        
+        /**
+         * Bit for {@link #flags): set if the service is running in a
+         * core system process.
+         */
+        public static final int FLAG_SYSTEM_PROCESS = 1<<2;
+        
+        /**
+         * Bit for {@link #flags): set if the service is running in a
+         * persistent process.
+         */
+        public static final int FLAG_PERSISTENT_PROCESS = 1<<3;
+        
+        /**
+         * Running flags.
+         */
+        public int flags;
+        
         public RunningServiceInfo() {
         }
 
@@ -342,6 +376,7 @@
         public void writeToParcel(Parcel dest, int flags) {
             ComponentName.writeToParcel(service, dest);
             dest.writeInt(pid);
+            dest.writeInt(uid);
             dest.writeString(process);
             dest.writeInt(foreground ? 1 : 0);
             dest.writeLong(activeSince);
@@ -350,11 +385,13 @@
             dest.writeInt(crashCount);
             dest.writeLong(lastActivityTime);
             dest.writeLong(restarting);
+            dest.writeInt(this.flags);
         }
 
         public void readFromParcel(Parcel source) {
             service = ComponentName.readFromParcel(source);
             pid = source.readInt();
+            uid = source.readInt();
             process = source.readString();
             foreground = source.readInt() != 0;
             activeSince = source.readLong();
@@ -363,6 +400,7 @@
             crashCount = source.readInt();
             lastActivityTime = source.readLong();
             restarting = source.readLong();
+            flags = source.readInt();
         }
         
         public static final Creator<RunningServiceInfo> CREATOR = new Creator<RunningServiceInfo>() {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index d14ec15..1bb21b9 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -29,6 +29,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -1107,6 +1108,16 @@
             reply.writeNoException();
             return true;
         }
+        
+        case GET_PROCESS_MEMORY_INFO_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int pid = data.readInt();
+            Debug.MemoryInfo mi = new Debug.MemoryInfo();
+            getProcessMemoryInfo(pid, mi);
+            reply.writeNoException();
+            mi.writeToParcel(reply, 0);
+            return true;
+        }
         }
         
         return super.onTransact(code, data, reply, flags);
@@ -2424,6 +2435,19 @@
         data.recycle();
         reply.recycle();
     }
-        
+    
+    public void getProcessMemoryInfo(int pid, Debug.MemoryInfo outInfo)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(pid);
+        mRemote.transact(GET_PROCESS_MEMORY_INFO_TRANSACTION, data, reply, 0);
+        reply.readException();
+        outInfo.readFromParcel(reply);
+        data.recycle();
+        reply.recycle();
+    }
+    
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1e915b4..b4e57e0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1546,6 +1546,10 @@
             }
         }
         
+        public void getMemoryInfo(Debug.MemoryInfo outInfo) {
+            Debug.getMemoryInfo(outInfo);
+        }
+        
         @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index ad64465..15bf9ed 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -26,6 +26,7 @@
 import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.IBinder;
@@ -370,6 +371,16 @@
             scheduleDestroyBackupAgent(appInfo);
             return true;
         }
+
+        case GET_MEMORY_INFO_TRANSACTION:
+        {
+            data.enforceInterface(IApplicationThread.descriptor);
+            Debug.MemoryInfo mi = new Debug.MemoryInfo();
+            getMemoryInfo(mi);
+            reply.writeNoException();
+            mi.writeToParcel(reply, 0);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -756,5 +767,16 @@
                 IBinder.FLAG_ONEWAY);
         data.recycle();
     }
+    
+    public void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IApplicationThread.descriptor);
+        mRemote.transact(GET_MEMORY_INFO_TRANSACTION, data, reply, 0);
+        reply.readException();
+        outInfo.readFromParcel(reply);
+        data.recycle();
+        reply.recycle();
+    }
 }
 
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index c3e7224..64daea9 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -30,6 +30,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.Debug;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IInterface;
@@ -272,6 +273,9 @@
     
     public void closeSystemDialogs(String reason) throws RemoteException;
     
+    public void getProcessMemoryInfo(int pid, Debug.MemoryInfo outInfo)
+            throws RemoteException;
+    
     /*
      * Private non-Binder interfaces
      */
@@ -428,4 +432,5 @@
     int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
     int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
     int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
+    int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
 }
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 6faaa34..da9a957 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -25,6 +25,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.IBinder;
@@ -97,6 +98,7 @@
     void profilerControl(boolean start, String path, ParcelFileDescriptor fd)
             throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
+    void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException;
     
     String descriptor = "android.app.IApplicationThread";
 
@@ -130,4 +132,5 @@
     int SET_SCHEDULING_GROUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
     int SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
     int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
+    int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
 }
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index b0fc78e..5352cf6 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -104,7 +104,7 @@
      * This class is used to retrieved various statistics about the memory mappings for this
      * process. The returns info broken down by dalvik, native, and other. All results are in kB.
      */
-    public static class MemoryInfo {
+    public static class MemoryInfo implements Parcelable {
         /** The proportional set size for dalvik. */
         public int dalvikPss;
         /** The private dirty pages used by dalvik. */
@@ -125,6 +125,50 @@
         public int otherPrivateDirty;
         /** The shared dirty pages used by everything else. */
         public int otherSharedDirty;
+        
+        public MemoryInfo() {
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(dalvikPss);
+            dest.writeInt(dalvikPrivateDirty);
+            dest.writeInt(dalvikSharedDirty);
+            dest.writeInt(nativePss);
+            dest.writeInt(nativePrivateDirty);
+            dest.writeInt(nativeSharedDirty);
+            dest.writeInt(otherPss);
+            dest.writeInt(otherPrivateDirty);
+            dest.writeInt(otherSharedDirty);
+        }
+
+        public void readFromParcel(Parcel source) {
+            dalvikPss = source.readInt();
+            dalvikPrivateDirty = source.readInt();
+            dalvikSharedDirty = source.readInt();
+            nativePss = source.readInt();
+            nativePrivateDirty = source.readInt();
+            nativeSharedDirty = source.readInt();
+            otherPss = source.readInt();
+            otherPrivateDirty = source.readInt();
+            otherSharedDirty = source.readInt();
+        }
+        
+        public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
+            public MemoryInfo createFromParcel(Parcel source) {
+                return new MemoryInfo(source);
+            }
+            public MemoryInfo[] newArray(int size) {
+                return new MemoryInfo[size];
+            }
+        };
+
+        private MemoryInfo(Parcel source) {
+            readFromParcel(source);
+        }
     }
 
 
@@ -556,6 +600,13 @@
     public static native void getMemoryInfo(MemoryInfo memoryInfo);
 
     /**
+     * Note: currently only works when the requested pid has the same UID
+     * as the caller.
+     * @hide
+     */
+    public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo);
+
+    /**
      * Establish an object allocation limit in the current thread.  Useful
      * for catching regressions in code that is expected to operate
      * without causing any allocations.
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index b4c60f1..3ee404ad 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -200,12 +200,13 @@
     fclose(fp);
 }
 
-static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
+static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
+        jint pid, jobject object)
 {
     stats_t stats;
     memset(&stats, 0, sizeof(stats_t));
     
-    load_maps(getpid(), &stats);
+    load_maps(pid, &stats);
 
     env->SetIntField(object, dalvikPss_field, stats.dalvikPss);
     env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty);
@@ -220,6 +221,11 @@
     env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty);
 }
 
+static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
+{
+    android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
+}
+
 static jint read_binder_stat(const char* stat)
 {
     FILE* fp = fopen(BINDER_STATS, "r");
@@ -281,6 +287,8 @@
             (void*) android_os_Debug_getNativeHeapFreeSize },
     { "getMemoryInfo",          "(Landroid/os/Debug$MemoryInfo;)V",
             (void*) android_os_Debug_getDirtyPages },
+    { "getMemoryInfo",          "(ILandroid/os/Debug$MemoryInfo;)V",
+            (void*) android_os_Debug_getDirtyPagesPid },
     { "getBinderSentTransactions", "()I",
             (void*) android_os_Debug_getBinderSentTransactions },
     { "getBinderReceivedTransactions", "()I",
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d4e69c0..867d8a6e 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -68,6 +68,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -4895,6 +4896,25 @@
         Binder.restoreCallingIdentity(origId);
     }
     
+    public void getProcessMemoryInfo(int pid, Debug.MemoryInfo mi)
+            throws RemoteException {
+        ProcessRecord proc;
+        synchronized (mPidsSelfLocked) {
+            proc = mPidsSelfLocked.get(pid);
+        }
+        
+        if (proc == null) {
+            throw new RemoteException();
+        }
+        
+        IApplicationThread thread = proc.thread;
+        if (thread == null) {
+            throw new RemoteException();
+        }
+        
+        thread.getMemoryInfo(mi);
+    }
+    
     private void restartPackageLocked(final String packageName, int uid) {
         uninstallPackageLocked(packageName, uid, false);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
@@ -9818,6 +9838,7 @@
         if (r.app != null) {
             info.pid = r.app.pid;
         }
+        info.uid = r.appInfo.uid;
         info.process = r.processName;
         info.foreground = r.isForeground;
         info.activeSince = r.createTime;
@@ -9825,6 +9846,18 @@
         info.clientCount = r.connections.size();
         info.crashCount = r.crashCount;
         info.lastActivityTime = r.lastActivity;
+        if (r.isForeground) {
+            info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
+        }
+        if (r.startRequested) {
+            info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
+        }
+        if (r.app != null && r.app.pid == Process.myPid()) {
+            info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
+        }
+        if (r.app != null && r.app.persistent) {
+            info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
+        }
         return info;
     }