Add 'App Summary' section to meminfo.

The 'App Summary' section is shown by default when other memory
details are shown. This adds a new meminfo flag '-s' to show only the
App Summary section.

Change-Id: I66913673cd3afca873a8b13e45abe071d4c57b82
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f16406a..f506d59 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -571,8 +571,6 @@
     private native void dumpGraphicsInfo(FileDescriptor fd);
 
     private class ApplicationThread extends ApplicationThreadNative {
-        private static final String ONE_COUNT_COLUMN = "%21s %8d";
-        private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
         private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
 
         private int mLastProcessState = -1;
@@ -972,18 +970,18 @@
 
         @Override
         public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
-                boolean dumpFullInfo, boolean dumpDalvik, String[] args) {
+                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) {
             FileOutputStream fout = new FileOutputStream(fd);
             PrintWriter pw = new FastPrintWriter(fout);
             try {
-                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik);
+                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly);
             } finally {
                 pw.flush();
             }
         }
 
         private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
-                boolean dumpFullInfo, boolean dumpDalvik) {
+                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
             long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
             long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -1007,7 +1005,8 @@
             long openSslSocketCount = Debug.countInstancesOfClass(OpenSSLSocketImpl.class);
             SQLiteDebug.PagerStats stats = SQLiteDebug.getDatabaseInfo();
 
-            dumpMemInfoTable(pw, memInfo, checkin, dumpFullInfo, dumpDalvik, Process.myPid(),
+            dumpMemInfoTable(pw, memInfo, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly,
+                    Process.myPid(),
                     (mBoundApplication != null) ? mBoundApplication.processName : "unknown",
                     nativeMax, nativeAllocated, nativeFree,
                     dalvikMax, dalvikAllocated, dalvikFree);
@@ -1935,6 +1934,9 @@
             = "%13s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s";
     private static final String HEAP_COLUMN
             = "%13s %8s %8s %8s %8s %8s %8s %8s";
+    private static final String ONE_COUNT_COLUMN = "%21s %8d";
+    private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
+    private static final String ONE_COUNT_COLUMN_HEADER = "%21s %8s";
 
     // Formatting for checkin service - update version if row format changes
     private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;
@@ -1944,7 +1946,8 @@
     }
 
     public static void dumpMemInfoTable(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
-            boolean dumpFullInfo, boolean dumpDalvik, int pid, String processName,
+            boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
+            int pid, String processName,
             long nativeMax, long nativeAllocated, long nativeFree,
             long dalvikMax, long dalvikAllocated, long dalvikFree) {
 
@@ -2025,106 +2028,50 @@
             return;
         }
 
-        // otherwise, show human-readable format
-        if (dumpFullInfo) {
-            printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
-                    "Shared", "Private", "Swapped", "Heap", "Heap", "Heap");
-            printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
-                    "Clean", "Clean", "Dirty", "Size", "Alloc", "Free");
-            printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
-                    "------", "------", "------", "------", "------", "------");
-            printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
-                    memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
-                    memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
-                    memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
-                    nativeMax, nativeAllocated, nativeFree);
-            printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
-                    memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
-                    memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
-                    memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
-                    dalvikMax, dalvikAllocated, dalvikFree);
-        } else {
-            printRow(pw, HEAP_COLUMN, "", "Pss", "Private",
-                    "Private", "Swapped", "Heap", "Heap", "Heap");
-            printRow(pw, HEAP_COLUMN, "", "Total", "Dirty",
-                    "Clean", "Dirty", "Size", "Alloc", "Free");
-            printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
-                    "------", "------", "------", "------", "------");
-            printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
-                    memInfo.nativePrivateDirty,
-                    memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
-                    nativeMax, nativeAllocated, nativeFree);
-            printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
-                    memInfo.dalvikPrivateDirty,
-                    memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
-                    dalvikMax, dalvikAllocated, dalvikFree);
-        }
-
-        int otherPss = memInfo.otherPss;
-        int otherSwappablePss = memInfo.otherSwappablePss;
-        int otherSharedDirty = memInfo.otherSharedDirty;
-        int otherPrivateDirty = memInfo.otherPrivateDirty;
-        int otherSharedClean = memInfo.otherSharedClean;
-        int otherPrivateClean = memInfo.otherPrivateClean;
-        int otherSwappedOut = memInfo.otherSwappedOut;
-
-        for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
-            final int myPss = memInfo.getOtherPss(i);
-            final int mySwappablePss = memInfo.getOtherSwappablePss(i);
-            final int mySharedDirty = memInfo.getOtherSharedDirty(i);
-            final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
-            final int mySharedClean = memInfo.getOtherSharedClean(i);
-            final int myPrivateClean = memInfo.getOtherPrivateClean(i);
-            final int mySwappedOut = memInfo.getOtherSwappedOut(i);
-            if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
-                    || mySharedClean != 0 || myPrivateClean != 0 || mySwappedOut != 0) {
-                if (dumpFullInfo) {
-                    printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
-                            myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
-                            mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
-                } else {
-                    printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
-                            myPss, myPrivateDirty,
-                            myPrivateClean, mySwappedOut, "", "", "");
-                }
-                otherPss -= myPss;
-                otherSwappablePss -= mySwappablePss;
-                otherSharedDirty -= mySharedDirty;
-                otherPrivateDirty -= myPrivateDirty;
-                otherSharedClean -= mySharedClean;
-                otherPrivateClean -= myPrivateClean;
-                otherSwappedOut -= mySwappedOut;
+        if (!dumpSummaryOnly) {
+            if (dumpFullInfo) {
+                printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
+                        "Shared", "Private", "Swapped", "Heap", "Heap", "Heap");
+                printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
+                        "Clean", "Clean", "Dirty", "Size", "Alloc", "Free");
+                printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------",
+                        "------", "------", "------", "------", "------", "------");
+                printRow(pw, HEAP_FULL_COLUMN, "Native Heap", memInfo.nativePss,
+                        memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
+                        memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
+                        memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
+                        nativeMax, nativeAllocated, nativeFree);
+                printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+                        memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
+                        memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
+                        memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
+                        dalvikMax, dalvikAllocated, dalvikFree);
+            } else {
+                printRow(pw, HEAP_COLUMN, "", "Pss", "Private",
+                        "Private", "Swapped", "Heap", "Heap", "Heap");
+                printRow(pw, HEAP_COLUMN, "", "Total", "Dirty",
+                        "Clean", "Dirty", "Size", "Alloc", "Free");
+                printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
+                        "------", "------", "------", "------", "------");
+                printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
+                        memInfo.nativePrivateDirty,
+                        memInfo.nativePrivateClean, memInfo.nativeSwappedOut,
+                        nativeMax, nativeAllocated, nativeFree);
+                printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+                        memInfo.dalvikPrivateDirty,
+                        memInfo.dalvikPrivateClean, memInfo.dalvikSwappedOut,
+                        dalvikMax, dalvikAllocated, dalvikFree);
             }
-        }
 
-        if (dumpFullInfo) {
-            printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
-                    otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
-                    otherSwappedOut, "", "", "");
-            printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
-                    memInfo.getTotalSwappablePss(),
-                    memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
-                    memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
-                    memInfo.getTotalSwappedOut(), nativeMax+dalvikMax,
-                    nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
-        } else {
-            printRow(pw, HEAP_COLUMN, "Unknown", otherPss,
-                    otherPrivateDirty, otherPrivateClean, otherSwappedOut,
-                    "", "", "");
-            printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
-                    memInfo.getTotalPrivateDirty(),
-                    memInfo.getTotalPrivateClean(),
-                    memInfo.getTotalSwappedOut(),
-                    nativeMax+dalvikMax,
-                    nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
-        }
+            int otherPss = memInfo.otherPss;
+            int otherSwappablePss = memInfo.otherSwappablePss;
+            int otherSharedDirty = memInfo.otherSharedDirty;
+            int otherPrivateDirty = memInfo.otherPrivateDirty;
+            int otherSharedClean = memInfo.otherSharedClean;
+            int otherPrivateClean = memInfo.otherPrivateClean;
+            int otherSwappedOut = memInfo.otherSwappedOut;
 
-        if (dumpDalvik) {
-            pw.println(" ");
-            pw.println(" Dalvik Details");
-
-            for (int i=Debug.MemoryInfo.NUM_OTHER_STATS;
-                 i<Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS; i++) {
+            for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
                 final int myPss = memInfo.getOtherPss(i);
                 final int mySwappablePss = memInfo.getOtherSwappablePss(i);
                 final int mySharedDirty = memInfo.getOtherSharedDirty(i);
@@ -2133,7 +2080,7 @@
                 final int myPrivateClean = memInfo.getOtherPrivateClean(i);
                 final int mySwappedOut = memInfo.getOtherSwappedOut(i);
                 if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
-                        || mySharedClean != 0 || myPrivateClean != 0) {
+                        || mySharedClean != 0 || myPrivateClean != 0 || mySwappedOut != 0) {
                     if (dumpFullInfo) {
                         printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
                                 myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
@@ -2143,9 +2090,89 @@
                                 myPss, myPrivateDirty,
                                 myPrivateClean, mySwappedOut, "", "", "");
                     }
+                    otherPss -= myPss;
+                    otherSwappablePss -= mySwappablePss;
+                    otherSharedDirty -= mySharedDirty;
+                    otherPrivateDirty -= myPrivateDirty;
+                    otherSharedClean -= mySharedClean;
+                    otherPrivateClean -= myPrivateClean;
+                    otherSwappedOut -= mySwappedOut;
+                }
+            }
+
+            if (dumpFullInfo) {
+                printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
+                        otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
+                        otherSwappedOut, "", "", "");
+                printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
+                        memInfo.getTotalSwappablePss(),
+                        memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+                        memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
+                        memInfo.getTotalSwappedOut(), nativeMax+dalvikMax,
+                        nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+            } else {
+                printRow(pw, HEAP_COLUMN, "Unknown", otherPss,
+                        otherPrivateDirty, otherPrivateClean, otherSwappedOut,
+                        "", "", "");
+                printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+                        memInfo.getTotalPrivateDirty(),
+                        memInfo.getTotalPrivateClean(),
+                        memInfo.getTotalSwappedOut(),
+                        nativeMax+dalvikMax,
+                        nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+            }
+
+            if (dumpDalvik) {
+                pw.println(" ");
+                pw.println(" Dalvik Details");
+
+                for (int i=Debug.MemoryInfo.NUM_OTHER_STATS;
+                     i<Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS; i++) {
+                    final int myPss = memInfo.getOtherPss(i);
+                    final int mySwappablePss = memInfo.getOtherSwappablePss(i);
+                    final int mySharedDirty = memInfo.getOtherSharedDirty(i);
+                    final int myPrivateDirty = memInfo.getOtherPrivateDirty(i);
+                    final int mySharedClean = memInfo.getOtherSharedClean(i);
+                    final int myPrivateClean = memInfo.getOtherPrivateClean(i);
+                    final int mySwappedOut = memInfo.getOtherSwappedOut(i);
+                    if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
+                            || mySharedClean != 0 || myPrivateClean != 0) {
+                        if (dumpFullInfo) {
+                            printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                    myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+                                    mySharedClean, myPrivateClean, mySwappedOut, "", "", "");
+                        } else {
+                            printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                    myPss, myPrivateDirty,
+                                    myPrivateClean, mySwappedOut, "", "", "");
+                        }
+                    }
                 }
             }
         }
+
+        pw.println(" ");
+        pw.println(" App Summary");
+        printRow(pw, ONE_COUNT_COLUMN_HEADER, "", "Pss(KB)");
+        printRow(pw, ONE_COUNT_COLUMN_HEADER, "", "------");
+        printRow(pw, ONE_COUNT_COLUMN,
+            "Java Heap:", memInfo.getSummaryJavaHeap());
+        printRow(pw, ONE_COUNT_COLUMN,
+            "Native Heap:", memInfo.getSummaryNativeHeap());
+        printRow(pw, ONE_COUNT_COLUMN,
+            "Code:", memInfo.getSummaryCode());
+        printRow(pw, ONE_COUNT_COLUMN,
+            "Stack:", memInfo.getSummaryStack());
+        printRow(pw, ONE_COUNT_COLUMN,
+            "Graphics:", memInfo.getSummaryGraphics());
+        printRow(pw, ONE_COUNT_COLUMN,
+            "Private Other:", memInfo.getSummaryPrivateOther());
+        printRow(pw, ONE_COUNT_COLUMN,
+            "System:", memInfo.getSummarySystem());
+        pw.println(" ");
+        printRow(pw, TWO_COUNT_COLUMNS,
+            "TOTAL:", memInfo.getSummaryTotalPss(),
+            "TOTAL SWAP (KB):", memInfo.getSummaryTotalSwap());
     }
 
     public void registerOnActivityPausedListener(Activity activity,
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index b6989ab..1461380 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -529,10 +529,12 @@
             boolean checkin = data.readInt() != 0;
             boolean dumpInfo = data.readInt() != 0;
             boolean dumpDalvik = data.readInt() != 0;
+            boolean dumpSummaryOnly = data.readInt() != 0;
             String[] args = data.readStringArray();
             if (fd != null) {
                 try {
-                    dumpMemInfo(fd.getFileDescriptor(), mi, checkin, dumpInfo, dumpDalvik, args);
+                    dumpMemInfo(fd.getFileDescriptor(), mi, checkin, dumpInfo,
+                            dumpDalvik, dumpSummaryOnly, args);
                 } finally {
                     try {
                         fd.close();
@@ -1248,7 +1250,7 @@
     }
 
     public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
-            boolean dumpInfo, boolean dumpDalvik, String[] args) throws RemoteException {
+            boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1257,6 +1259,7 @@
         data.writeInt(checkin ? 1 : 0);
         data.writeInt(dumpInfo ? 1 : 0);
         data.writeInt(dumpDalvik ? 1 : 0);
+        data.writeInt(dumpSummaryOnly ? 1 : 0);
         data.writeStringArray(args);
         mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
         reply.readException();
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 3fb82f6..185578f 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -131,7 +131,7 @@
     void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
     void scheduleTrimMemory(int level) throws RemoteException;
     void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, boolean dumpInfo,
-            boolean dumpDalvik, String[] args) throws RemoteException;
+            boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException;
     void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void unstableProviderDied(IBinder provider) throws RemoteException;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 4aff7a1..19c8fa9d 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -169,6 +169,65 @@
         public int otherSwappedOut;
 
         /** @hide */
+        public static final int HEAP_UNKNOWN = 0;
+        /** @hide */
+        public static final int HEAP_DALVIK = 1;
+        /** @hide */
+        public static final int HEAP_NATIVE = 2;
+
+        /** @hide */
+        public static final int OTHER_DALVIK_OTHER = 0;
+        /** @hide */
+        public static final int OTHER_STACK = 1;
+        /** @hide */
+        public static final int OTHER_CURSOR = 2;
+        /** @hide */
+        public static final int OTHER_ASHMEM = 3;
+        /** @hide */
+        public static final int OTHER_GL_DEV = 4;
+        /** @hide */
+        public static final int OTHER_UNKNOWN_DEV = 5;
+        /** @hide */
+        public static final int OTHER_SO = 6;
+        /** @hide */
+        public static final int OTHER_JAR = 7;
+        /** @hide */
+        public static final int OTHER_APK = 8;
+        /** @hide */
+        public static final int OTHER_TTF = 9;
+        /** @hide */
+        public static final int OTHER_DEX = 10;
+        /** @hide */
+        public static final int OTHER_OAT = 11;
+        /** @hide */
+        public static final int OTHER_ART = 12;
+        /** @hide */
+        public static final int OTHER_UNKNOWN_MAP = 13;
+        /** @hide */
+        public static final int OTHER_GRAPHICS = 14;
+        /** @hide */
+        public static final int OTHER_GL = 15;
+        /** @hide */
+        public static final int OTHER_OTHER_MEMTRACK = 16;
+
+        /** @hide */
+        public static final int OTHER_DALVIK_NORMAL = 17;
+        /** @hide */
+        public static final int OTHER_DALVIK_LARGE = 18;
+        /** @hide */
+        public static final int OTHER_DALVIK_LINEARALLOC = 19;
+        /** @hide */
+        public static final int OTHER_DALVIK_ACCOUNTING = 20;
+        /** @hide */
+        public static final int OTHER_DALVIK_CODE_CACHE = 21;
+        /** @hide */
+        public static final int OTHER_DALVIK_ZYGOTE = 22;
+        /** @hide */
+        public static final int OTHER_DALVIK_NON_MOVING = 23;
+        /** @hide */
+        public static final int OTHER_DALVIK_INDIRECT_REFERENCE_TABLE = 24;
+
+        /** @hide */
         public static final int NUM_OTHER_STATS = 17;
 
         /** @hide */
@@ -284,6 +343,11 @@
         }
 
         /** @hide */
+        public int getOtherPrivate(int which) {
+          return getOtherPrivateClean(which) + getOtherPrivateDirty(which);
+        }
+
+        /** @hide */
         public int getOtherSharedClean(int which) {
             return otherStats[which*NUM_CATEGORIES + offsetSharedClean];
         }
@@ -296,35 +360,157 @@
         /** @hide */
         public static String getOtherLabel(int which) {
             switch (which) {
-                case 0: return "Dalvik Other";
-                case 1: return "Stack";
-                case 2: return "Cursor";
-                case 3: return "Ashmem";
-                case 4: return "Gfx dev";
-                case 5: return "Other dev";
-                case 6: return ".so mmap";
-                case 7: return ".jar mmap";
-                case 8: return ".apk mmap";
-                case 9: return ".ttf mmap";
-                case 10: return ".dex mmap";
-                case 11: return ".oat mmap";
-                case 12: return ".art mmap";
-                case 13: return "Other mmap";
-                case 14: return "EGL mtrack";
-                case 15: return "GL mtrack";
-                case 16: return "Other mtrack";
-                case 17: return ".Heap";
-                case 18: return ".LOS";
-                case 19: return ".LinearAlloc";
-                case 20: return ".GC";
-                case 21: return ".JITCache";
-                case 22: return ".Zygote";
-                case 23: return ".NonMoving";
-                case 24: return ".IndirectRef";
+                case OTHER_DALVIK_OTHER: return "Dalvik Other";
+                case OTHER_STACK: return "Stack";
+                case OTHER_CURSOR: return "Cursor";
+                case OTHER_ASHMEM: return "Ashmem";
+                case OTHER_GL_DEV: return "Gfx dev";
+                case OTHER_UNKNOWN_DEV: return "Other dev";
+                case OTHER_SO: return ".so mmap";
+                case OTHER_JAR: return ".jar mmap";
+                case OTHER_APK: return ".apk mmap";
+                case OTHER_TTF: return ".ttf mmap";
+                case OTHER_DEX: return ".dex mmap";
+                case OTHER_OAT: return ".oat mmap";
+                case OTHER_ART: return ".art mmap";
+                case OTHER_UNKNOWN_MAP: return "Other mmap";
+                case OTHER_GRAPHICS: return "EGL mtrack";
+                case OTHER_GL: return "GL mtrack";
+                case OTHER_OTHER_MEMTRACK: return "Other mtrack";
+                case OTHER_DALVIK_NORMAL: return ".Heap";
+                case OTHER_DALVIK_LARGE: return ".LOS";
+                case OTHER_DALVIK_LINEARALLOC: return ".LinearAlloc";
+                case OTHER_DALVIK_ACCOUNTING: return ".GC";
+                case OTHER_DALVIK_CODE_CACHE: return ".JITCache";
+                case OTHER_DALVIK_ZYGOTE: return ".Zygote";
+                case OTHER_DALVIK_NON_MOVING: return ".NonMoving";
+                case OTHER_DALVIK_INDIRECT_REFERENCE_TABLE: return ".IndirectRef";
                 default: return "????";
             }
         }
 
+        /**
+         * Pss of Java Heap bytes in KB due to the application.
+         * Notes:
+         *  * OTHER_ART is the boot image. Anything private here is blamed on
+         *    the application, not the system.
+         *  * dalvikPrivateDirty includes private zygote, which means the
+         *    application dirtied something allocated by the zygote. We blame
+         *    the application for that memory, not the system.
+         *  * Does not include OTHER_DALVIK_OTHER, which is considered VM
+         *    Overhead and lumped into Private Other.
+         *  * We don't include dalvikPrivateClean, because there should be no
+         *    such thing as private clean for the Java Heap.
+         * @hide
+         */
+        public int getSummaryJavaHeap() {
+            return dalvikPrivateDirty + getOtherPrivate(OTHER_ART);
+        }
+
+        /**
+         * Pss of Native Heap bytes in KB due to the application.
+         * Notes:
+         *  * Includes private dirty malloc space.
+         *  * We don't include nativePrivateClean, because there should be no
+         *    such thing as private clean for the Native Heap.
+         * @hide
+         */
+        public int getSummaryNativeHeap() {
+            return nativePrivateDirty;
+        }
+
+        /**
+         * Pss of code and other static resource bytes in KB due to
+         * the application.
+         * @hide
+         */
+        public int getSummaryCode() {
+            return getOtherPrivate(OTHER_SO)
+              + getOtherPrivate(OTHER_JAR)
+              + getOtherPrivate(OTHER_APK)
+              + getOtherPrivate(OTHER_TTF)
+              + getOtherPrivate(OTHER_DEX)
+              + getOtherPrivate(OTHER_OAT);
+        }
+
+        /**
+         * Pss in KB of the stack due to the application.
+         * Notes:
+         *  * Includes private dirty stack, which includes both Java and Native
+         *    stack.
+         *  * Does not include private clean stack, because there should be no
+         *    such thing as private clean for the stack.
+         * @hide
+         */
+        public int getSummaryStack() {
+            return getOtherPrivateDirty(OTHER_STACK);
+        }
+
+        /**
+         * Pss in KB of graphics due to the application.
+         * Notes:
+         *  * Includes private Gfx, EGL, and GL.
+         *  * Warning: These numbers can be misreported by the graphics drivers.
+         *  * We don't include shared graphics. It may make sense to, because
+         *    shared graphics are likely buffers due to the application
+         *    anyway, but it's simpler to implement to just group all shared
+         *    memory into the System category.
+         * @hide
+         */
+        public int getSummaryGraphics() {
+            return getOtherPrivate(OTHER_GL_DEV)
+              + getOtherPrivate(OTHER_GRAPHICS)
+              + getOtherPrivate(OTHER_GL);
+        }
+
+        /**
+         * Pss in KB due to the application that haven't otherwise been
+         * accounted for.
+         * @hide
+         */
+        public int getSummaryPrivateOther() {
+            return getTotalPrivateClean()
+              + getTotalPrivateDirty()
+              - getSummaryJavaHeap()
+              - getSummaryNativeHeap()
+              - getSummaryCode()
+              - getSummaryStack()
+              - getSummaryGraphics();
+        }
+
+        /**
+         * Pss in KB due to the system.
+         * Notes:
+         *  * Includes all shared memory.
+         * @hide
+         */
+        public int getSummarySystem() {
+            return getTotalPss()
+              - getTotalPrivateClean()
+              - getTotalPrivateDirty();
+        }
+
+        /**
+         * Total Pss in KB.
+         * @hide
+         */
+        public int getSummaryTotalPss() {
+            return getTotalPss();
+        }
+
+        /**
+         * Total Swap in KB.
+         * Notes:
+         *  * Some of this memory belongs in other categories, but we don't
+         *    know if the Swap memory is shared or private, so we don't know
+         *    what to blame on the application and what on the system.
+         *    For now, just lump all the Swap in one place.
+         * @hide
+         */
+        public int getSummaryTotalSwap() {
+            return getTotalSwappedOut();
+        }
+
         public int describeContents() {
             return 0;
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 82dbfeec..d1df7e2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14121,6 +14121,7 @@
         boolean dumpDetails = false;
         boolean dumpFullDetails = false;
         boolean dumpDalvik = false;
+        boolean dumpSummaryOnly = false;
         boolean oomOnly = false;
         boolean isCompact = false;
         boolean localOnly = false;
@@ -14141,6 +14142,9 @@
                 dumpDalvik = true;
             } else if ("-c".equals(opt)) {
                 isCompact = true;
+            } else if ("-s".equals(opt)) {
+                dumpDetails = true;
+                dumpSummaryOnly = true;
             } else if ("--oom".equals(opt)) {
                 oomOnly = true;
             } else if ("--local".equals(opt)) {
@@ -14148,10 +14152,11 @@
             } else if ("--package".equals(opt)) {
                 packages = true;
             } else if ("-h".equals(opt)) {
-                pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]");
+                pw.println("meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]");
                 pw.println("  -a: include all available information for each process.");
                 pw.println("  -d: include dalvik details.");
                 pw.println("  -c: dump in a compact machine-parseable representation.");
+                pw.println("  -s: dump only summary of application memory usage.");
                 pw.println("  --oom: only show processes organized by oom adj.");
                 pw.println("  --local: only collect details locally, don't call process.");
                 pw.println("  --package: interpret process arg as package, dumping all");
@@ -14212,7 +14217,7 @@
                             mi.dalvikPrivateDirty = (int)tmpLong[0];
                         }
                         ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
-                                dumpDalvik, pid, r.baseName, 0, 0, 0, 0, 0, 0);
+                                dumpDalvik, dumpSummaryOnly, pid, r.baseName, 0, 0, 0, 0, 0, 0);
                         if (isCheckinRequest) {
                             pw.println();
                         }
@@ -14278,7 +14283,7 @@
                 if (dumpDetails) {
                     if (localOnly) {
                         ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
-                                dumpDalvik, pid, r.processName, 0, 0, 0, 0, 0, 0);
+                                dumpDalvik, dumpSummaryOnly, pid, r.processName, 0, 0, 0, 0, 0, 0);
                         if (isCheckinRequest) {
                             pw.println();
                         }
@@ -14286,7 +14291,7 @@
                         try {
                             pw.flush();
                             thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
-                                    dumpDalvik, innerArgs);
+                                    dumpDalvik, dumpSummaryOnly, innerArgs);
                         } catch (RemoteException e) {
                             if (!isCheckinRequest) {
                                 pw.println("Got RemoteException!");