Add more memory usage stats

Added support for teasing apart different parts of the dalvik heap.

Note this adds more public api and we should talk to hackbod before going into master with this.

(cherry picked from commit 73407daf3f6110e933d8614605b21586c4c5fde2)

Change-Id: If4431f50e67e18bcc42e00694c97805477bd6815
diff --git a/api/current.txt b/api/current.txt
index 3685cf4..96a8481 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17065,28 +17065,29 @@
     ctor public Debug.MemoryInfo();
     method public int describeContents();
     method public static java.lang.String getOtherLabel(int);
+    method public int getOtherPrivateClean(int);
     method public int getOtherPrivateDirty(int);
     method public int getOtherPss(int);
     method public int getOtherSharedClean(int);
     method public int getOtherSharedDirty(int);
+    method public int getOtherSwappablePss(int);
+    method public int getTotalPrivateClean();
     method public int getTotalPrivateDirty();
     method public int getTotalPss();
     method public int getTotalSharedClean();
     method public int getTotalSharedDirty();
+    method public int getTotalSwappablePss();
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public int dalvikPrivateDirty;
     field public int dalvikPss;
-    field public int dalvikSharedClean;
     field public int dalvikSharedDirty;
     field public int nativePrivateDirty;
     field public int nativePss;
-    field public int nativeSharedClean;
     field public int nativeSharedDirty;
     field public int otherPrivateDirty;
     field public int otherPss;
-    field public int otherSharedClean;
     field public int otherSharedDirty;
   }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 82ecfa3..d1bf0af 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -543,13 +543,13 @@
     private native void dumpGraphicsInfo(FileDescriptor fd);
 
     private class ApplicationThread extends ApplicationThreadNative {
-        private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s %8s";
+        private static final String HEAP_COLUMN = "%13s %8s %8s %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 DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
 
         // Formatting for checkin service - update version if row format changes
-        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
+        private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 2;
 
         private void updatePendingConfiguration(Configuration config) {
             synchronized (mPackages) {
@@ -970,6 +970,12 @@
                 pw.print(memInfo.otherPss); pw.print(',');
                 pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
 
+                // Heap info - proportional set size
+                pw.print(memInfo.nativeSwappablePss); pw.print(',');
+                pw.print(memInfo.dalvikSwappablePss); pw.print(',');
+                pw.print(memInfo.otherSwappablePss); pw.print(',');
+                pw.print(memInfo.nativeSwappablePss + memInfo.dalvikSwappablePss + memInfo.otherSwappablePss); pw.print(',');
+
                 // Heap info - shared dirty
                 pw.print(memInfo.nativeSharedDirty); pw.print(',');
                 pw.print(memInfo.dalvikSharedDirty); pw.print(',');
@@ -984,7 +990,7 @@
                 pw.print(memInfo.nativeSharedClean + memInfo.dalvikSharedClean
                         + memInfo.otherSharedClean); pw.print(',');
 
-                // Heap info - private
+                // Heap info - private Dirty
                 pw.print(memInfo.nativePrivateDirty); pw.print(',');
                 pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
                 pw.print(memInfo.otherPrivateDirty); pw.print(',');
@@ -992,6 +998,14 @@
                         + memInfo.otherPrivateDirty); pw.print(',');
 
 
+                // Heap info - private Clean
+                pw.print(memInfo.nativePrivateClean); pw.print(',');
+                pw.print(memInfo.dalvikPrivateClean); pw.print(',');
+                pw.print(memInfo.otherPrivateClean); pw.print(',');
+                pw.print(memInfo.nativePrivateClean + memInfo.dalvikPrivateClean
+                        + memInfo.otherPrivateClean); pw.print(',');
+
+
                 // Object counts
                 pw.print(viewInstanceCount); pw.print(',');
                 pw.print(viewRootInstanceCount); pw.print(',');
@@ -1026,36 +1040,62 @@
             }
 
             // otherwise, show human-readable format
-            printRow(pw, HEAP_COLUMN, "", "", "Shared", "Private", "Shared", "Heap", "Heap", "Heap");
-            printRow(pw, HEAP_COLUMN, "", "Pss", "Dirty", "Dirty", "Clean", "Size", "Alloc", "Free");
-            printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------", "------",
+            printRow(pw, HEAP_COLUMN, "", "", "Swapable","Shared", "Private", "Shared", "Private", "Heap", "Heap", "Heap");
+            printRow(pw, HEAP_COLUMN, "", "Pss", "Pss", "Dirty", "Dirty", "Clean", "Clean", "Size", "Alloc", "Free");
+            printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------", "------", "------", "------",
                     "------");
-            printRow(pw, HEAP_COLUMN, "Native", memInfo.nativePss, memInfo.nativeSharedDirty,
-                    memInfo.nativePrivateDirty, memInfo.nativeSharedClean, nativeMax, nativeAllocated, nativeFree);
-            printRow(pw, HEAP_COLUMN, "Dalvik", memInfo.dalvikPss, memInfo.dalvikSharedDirty,
-                    memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean, dalvikMax, dalvikAllocated, dalvikFree);
+            printRow(pw, HEAP_COLUMN, "Native", memInfo.nativePss, memInfo.nativeSwappablePss, memInfo.nativeSharedDirty,
+                     memInfo.nativePrivateDirty, memInfo.nativeSharedClean, memInfo.nativePrivateClean,nativeMax, 
+                     nativeAllocated, nativeFree);
+            printRow(pw, HEAP_COLUMN, "Dalvik", memInfo.dalvikPss, memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
+                     memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean, memInfo.dalvikPrivateClean, 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;
 
             for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
                 printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
-                        memInfo.getOtherPss(i), memInfo.getOtherSharedDirty(i),
-                        memInfo.getOtherPrivateDirty(i), memInfo.getOtherSharedClean(i), "", "", "");
+                         memInfo.getOtherPss(i), memInfo.getOtherSwappablePss(i), memInfo.getOtherSharedDirty(i),
+                         memInfo.getOtherPrivateDirty(i), memInfo.getOtherSharedClean(i), memInfo.getOtherPrivateClean(i),
+                         "", "", "");
                 otherPss -= memInfo.getOtherPss(i);
+                otherSwappablePss -= memInfo.getOtherSwappablePss(i);
                 otherSharedDirty -= memInfo.getOtherSharedDirty(i);
                 otherPrivateDirty -= memInfo.getOtherPrivateDirty(i);
                 otherSharedClean -= memInfo.getOtherSharedClean(i);
+                otherPrivateClean -= memInfo.getOtherPrivateClean(i);
             }
 
-            printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSharedDirty,
-                    otherPrivateDirty, otherSharedClean, "", "", "");
-            printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
-                    memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
-                    memInfo.getTotalSharedClean(), nativeMax+dalvikMax,
-                    nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+
+
+            printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSwappablePss, otherSharedDirty,
+                    otherPrivateDirty, otherSharedClean, otherPrivateClean,"", "", "");
+            printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(), memInfo.getTotalSwappablePss(),
+                     memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+                     memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(), nativeMax+dalvikMax,
+                     nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+
+            pw.println(" ");
+            pw.println(" Dalvik");
+
+            for (int i=Debug.MemoryInfo.NUM_OTHER_STATS;
+                 i<Debug.MemoryInfo.NUM_OTHER_STATS + Debug.MemoryInfo.NUM_DVK_STATS; i++) {
+                printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                         memInfo.getOtherPss(i), memInfo.getOtherSwappablePss(i), memInfo.getOtherSharedDirty(i),
+                         memInfo.getOtherPrivateDirty(i), memInfo.getOtherSharedClean(i),
+                         memInfo.getOtherPrivateClean(i), "", "", "");
+                otherPss -= memInfo.getOtherPss(i);
+                otherSwappablePss -= memInfo.getOtherSwappablePss(i);
+                otherSharedDirty -= memInfo.getOtherSharedDirty(i);
+                otherPrivateDirty -= memInfo.getOtherPrivateDirty(i);
+                otherSharedClean -= memInfo.getOtherSharedClean(i);
+                otherPrivateClean -= memInfo.getOtherPrivateClean(i);
+            }
 
             pw.println(" ");
             pw.println(" Objects");
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 72ef606..d8e30e2 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -110,38 +110,76 @@
     public static class MemoryInfo implements Parcelable {
         /** The proportional set size for dalvik. */
         public int dalvikPss;
+        /** The proportional set size that is swappable for dalvik. */
+        /** @hide We may want to expose this, eventually. */
+        public int dalvikSwappablePss;
         /** The private dirty pages used by dalvik. */
         public int dalvikPrivateDirty;
         /** The shared dirty pages used by dalvik. */
         public int dalvikSharedDirty;
+        /** The private clean pages used by dalvik. */
+        /** @hide We may want to expose this, eventually. */
+        public int dalvikPrivateClean;
         /** The shared clean pages used by dalvik. */
+        /** @hide We may want to expose this, eventually. */
         public int dalvikSharedClean;
 
         /** The proportional set size for the native heap. */
         public int nativePss;
+        /** The proportional set size that is swappable for the native heap. */
+        /** @hide We may want to expose this, eventually. */
+        public int nativeSwappablePss;
         /** The private dirty pages used by the native heap. */
         public int nativePrivateDirty;
         /** The shared dirty pages used by the native heap. */
         public int nativeSharedDirty;
+        /** The private clean pages used by the native heap. */
+        /** @hide We may want to expose this, eventually. */
+        public int nativePrivateClean;
         /** The shared clean pages used by the native heap. */
+        /** @hide We may want to expose this, eventually. */
         public int nativeSharedClean;
 
         /** The proportional set size for everything else. */
         public int otherPss;
+        /** The proportional set size that is swappable for everything else. */
+        /** @hide We may want to expose this, eventually. */
+        public int otherSwappablePss;
         /** The private dirty pages used by everything else. */
         public int otherPrivateDirty;
         /** The shared dirty pages used by everything else. */
         public int otherSharedDirty;
+        /** The private clean pages used by everything else. */
+        /** @hide We may want to expose this, eventually. */
+        public int otherPrivateClean;
         /** The shared clean pages used by everything else. */
+        /** @hide We may want to expose this, eventually. */
         public int otherSharedClean;
 
         /** @hide */
         public static final int NUM_OTHER_STATS = 12;
 
         /** @hide */
-        public static final int NUM_CATEGORIES = 4;
+        public static final int NUM_DVK_STATS = 5;
 
-        private int[] otherStats = new int[NUM_OTHER_STATS*NUM_CATEGORIES];
+        /** @hide */
+        public static final int NUM_CATEGORIES = 6;
+
+        /** @hide */
+        public static final int offsetPss = 0;
+        /** @hide */
+        public static final int offsetSwappablePss = 1;
+        /** @hide */
+        public static final int offsetPrivateDirty = 2;
+        /** @hide */
+        public static final int offsetSharedDirty = 3;
+        /** @hide */
+        public static final int offsetPrivateClean = 4;
+        /** @hide */
+        public static final int offsetSharedClean = 5;
+
+
+        private int[] otherStats = new int[(NUM_OTHER_STATS+NUM_DVK_STATS)*NUM_CATEGORIES];
 
         public MemoryInfo() {
         }
@@ -153,6 +191,14 @@
             return dalvikPss + nativePss + otherPss;
         }
 
+
+        /**
+         * Return total PSS memory usage in kB.
+         */
+        public int getTotalSwappablePss() {
+            return dalvikSwappablePss + nativeSwappablePss + otherSwappablePss;
+        }
+
         /**
          * Return total private dirty memory usage in kB.
          */
@@ -170,30 +216,50 @@
         /**
          * Return total shared clean memory usage in kB.
          */
+        public int getTotalPrivateClean() {
+            return dalvikPrivateClean + nativePrivateClean + otherPrivateClean;
+        }
+
+        /**
+         * Return total shared clean memory usage in kB.
+         */
         public int getTotalSharedClean() {
             return dalvikSharedClean + nativeSharedClean + otherSharedClean;
         }
 
         /* @hide */
         public int getOtherPss(int which) {
-            return otherStats[which*NUM_CATEGORIES];
+            return otherStats[which*NUM_CATEGORIES + offsetPss];
         }
 
+
+        /* @hide */
+        public int getOtherSwappablePss(int which) {
+            return otherStats[which*NUM_CATEGORIES + offsetSwappablePss];
+        }
+
+
         /* @hide */
         public int getOtherPrivateDirty(int which) {
-            return otherStats[which*NUM_CATEGORIES + 1];
+            return otherStats[which*NUM_CATEGORIES + offsetPrivateDirty];
         }
 
         /* @hide */
         public int getOtherSharedDirty(int which) {
-            return otherStats[which*NUM_CATEGORIES + 2];
+            return otherStats[which*NUM_CATEGORIES + offsetSharedDirty];
         }
 
         /* @hide */
-        public int getOtherSharedClean(int which) {
-            return otherStats[which*NUM_CATEGORIES + 3];
+        public int getOtherPrivateClean(int which) {
+            return otherStats[which*NUM_CATEGORIES + offsetPrivateClean];
         }
-        
+
+
+        /* @hide */
+        public int getOtherSharedClean(int which) {
+            return otherStats[which*NUM_CATEGORIES + offsetSharedClean];
+        }
+
         /* @hide */
         public static String getOtherLabel(int which) {
             switch (which) {
@@ -209,6 +275,11 @@
                 case 9: return "code mmap";
                 case 10: return "image mmap";
                 case 11: return "Other mmap";
+                case 12: return ".Heap";
+                case 13: return ".LOS";
+                case 14: return ".LinearAlloc";
+                case 15: return ".GC";
+                case 16: return ".JITCache";
                 default: return "????";
             }
         }
@@ -219,32 +290,44 @@
 
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(dalvikPss);
+            dest.writeInt(dalvikSwappablePss);
             dest.writeInt(dalvikPrivateDirty);
             dest.writeInt(dalvikSharedDirty);
+            dest.writeInt(dalvikPrivateClean);
             dest.writeInt(dalvikSharedClean);
             dest.writeInt(nativePss);
+            dest.writeInt(nativeSwappablePss);
             dest.writeInt(nativePrivateDirty);
             dest.writeInt(nativeSharedDirty);
+            dest.writeInt(nativePrivateClean);
             dest.writeInt(nativeSharedClean);
             dest.writeInt(otherPss);
+            dest.writeInt(otherSwappablePss);
             dest.writeInt(otherPrivateDirty);
             dest.writeInt(otherSharedDirty);
+            dest.writeInt(otherPrivateClean);
             dest.writeInt(otherSharedClean);
             dest.writeIntArray(otherStats);
         }
 
         public void readFromParcel(Parcel source) {
             dalvikPss = source.readInt();
+            dalvikSwappablePss = source.readInt();
             dalvikPrivateDirty = source.readInt();
             dalvikSharedDirty = source.readInt();
+            dalvikPrivateClean = source.readInt();
             dalvikSharedClean = source.readInt();
             nativePss = source.readInt();
+            nativeSwappablePss = source.readInt();
             nativePrivateDirty = source.readInt();
             nativeSharedDirty = source.readInt();
+            nativePrivateClean = source.readInt();
             nativeSharedClean = source.readInt();
             otherPss = source.readInt();
+            otherSwappablePss = source.readInt();
             otherPrivateDirty = source.readInt();
             otherSharedDirty = source.readInt();
+            otherPrivateClean = source.readInt();
             otherSharedClean = source.readInt();
             otherStats = source.createIntArray();
         }
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index ba82666..e356c28 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -55,39 +55,51 @@
     HEAP_OAT,
     HEAP_ART,
     HEAP_UNKNOWN_MAP,
+    HEAP_DALVIK_NORMAL,
+    HEAP_DALVIK_LARGE,
+    HEAP_DALVIK_LINEARALLOC,
+    HEAP_DALVIK_ACCOUNTING,
+    HEAP_DALVIK_CODE_CACHE,
 
     _NUM_HEAP,
+    _NUM_EXCLUSIVE_HEAP = HEAP_UNKNOWN_MAP+1,
     _NUM_CORE_HEAP = HEAP_NATIVE+1
 };
 
 struct stat_fields {
     jfieldID pss_field;
+    jfieldID pssSwappable_field;
     jfieldID privateDirty_field;
     jfieldID sharedDirty_field;
+    jfieldID privateClean_field;
     jfieldID sharedClean_field;
 };
 
 struct stat_field_names {
     const char* pss_name;
+    const char* pssSwappable_name;
     const char* privateDirty_name;
     const char* sharedDirty_name;
+    const char* privateClean_name;
     const char* sharedClean_name;
 };
 
 static stat_fields stat_fields[_NUM_CORE_HEAP];
 
 static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
-    { "otherPss", "otherPrivateDirty", "otherSharedDirty", "otherSharedClean" },
-    { "dalvikPss", "dalvikPrivateDirty", "dalvikSharedDirty", "dalvikSharedClean" },
-    { "nativePss", "nativePrivateDirty", "nativeSharedDirty", "nativeSharedClean" }
+    { "otherPss", "otherSwappablePss", "otherPrivateDirty", "otherSharedDirty", "otherPrivateClean", "otherSharedClean" },
+    { "dalvikPss", "dalvikSwappablePss", "dalvikPrivateDirty", "dalvikSharedDirty", "dalvikPrivateClean", "dalvikSharedClean" },
+    { "nativePss", "nativeSwappablePss", "nativePrivateDirty", "nativeSharedDirty", "nativePrivateClean", "nativeSharedClean" }
 };
 
 jfieldID otherStats_field;
 
 struct stats_t {
     int pss;
+    int swappablePss;
     int privateDirty;
     int sharedDirty;
+    int privateClean;
     int sharedClean;
 };
 
@@ -129,9 +141,11 @@
     int len, nameLen;
     bool skip, done = false;
 
-    unsigned size = 0, resident = 0, pss = 0;
+    unsigned size = 0, resident = 0, pss = 0, swappable_pss = 0;
+    float sharing_proportion = 0.0;
     unsigned shared_clean = 0, shared_dirty = 0;
     unsigned private_clean = 0, private_dirty = 0;
+    bool is_swappable = false;
     unsigned referenced = 0;
     unsigned temp;
 
@@ -142,6 +156,7 @@
     int name_pos;
 
     int whichHeap = HEAP_UNKNOWN;
+    int subHeap = HEAP_UNKNOWN;
     int prevHeap = HEAP_UNKNOWN;
 
     if(fgets(line, sizeof(line), fp) == 0) return;
@@ -150,7 +165,9 @@
         prevHeap = whichHeap;
         prevEnd = end;
         whichHeap = HEAP_UNKNOWN;
+        subHeap = HEAP_UNKNOWN;
         skip = false;
+        is_swappable = false;
 
         len = strlen(line);
         if (len < 1) return;
@@ -170,6 +187,26 @@
                 whichHeap = HEAP_NATIVE;
             } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
                 whichHeap = HEAP_DALVIK;
+                if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
+                    subHeap = HEAP_DALVIK_LINEARALLOC;
+                } else if ((strstr(name, "/dev/ashmem/dalvik-mark") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-allocspace alloc space live-bitmap") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-allocspace alloc space mark-bitmap") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-card table") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-allocation stack") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-live stack") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-imagespace") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-bitmap") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-card-table") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-mark-stack") == name) ||
+                           (strstr(name, "/dev/ashmem/dalvik-aux-structure") == name)) {
+                    subHeap = HEAP_DALVIK_ACCOUNTING;
+                } else if (strstr(name, "/dev/ashmem/dalvik-large") == name) {
+                    subHeap = HEAP_DALVIK_LARGE;
+                } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name) {
+                    subHeap = HEAP_DALVIK_CODE_CACHE;
+                } else
+                    subHeap = HEAP_DALVIK_NORMAL;
             } else if (strstr(name, "[stack") == name) {
                 whichHeap = HEAP_STACK;
             } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) {
@@ -180,19 +217,26 @@
                 whichHeap = HEAP_UNKNOWN_DEV;
             } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
                 whichHeap = HEAP_SO;
+                is_swappable = true;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
                 whichHeap = HEAP_JAR;
+                is_swappable = true;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
                 whichHeap = HEAP_APK;
+                is_swappable = true;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
                 whichHeap = HEAP_TTF;
+                is_swappable = true;
             } else if ((nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) ||
                        (nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
                 whichHeap = HEAP_DEX;
+                is_swappable = true;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".oat") == 0) {
                 whichHeap = HEAP_OAT;
+                is_swappable = true;
             } else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) {
                 whichHeap = HEAP_ART;
+                is_swappable = true;
             } else if (nameLen > 0) {
                 whichHeap = HEAP_UNKNOWN_MAP;
             } else if (start == prevEnd && prevHeap == HEAP_SO) {
@@ -234,10 +278,29 @@
         }
 
         if (!skip) {
+            if (is_swappable && (pss > 0)) {
+                sharing_proportion = 0.0;
+                if ((shared_clean > 0) || (shared_dirty > 0)) {
+                    sharing_proportion = (pss - private_clean - private_dirty)/(shared_clean+shared_dirty);
+                }
+                swappable_pss = (sharing_proportion*shared_clean) + private_clean;
+            } else
+                swappable_pss = 0;
+
             stats[whichHeap].pss += pss;
+            stats[whichHeap].swappablePss += swappable_pss;
             stats[whichHeap].privateDirty += private_dirty;
             stats[whichHeap].sharedDirty += shared_dirty;
+            stats[whichHeap].privateClean += private_clean;
             stats[whichHeap].sharedClean += shared_clean;
+            if (whichHeap == HEAP_DALVIK) {
+                stats[subHeap].pss += pss;
+                stats[subHeap].swappablePss += swappable_pss;
+                stats[subHeap].privateDirty += private_dirty;
+                stats[subHeap].sharedDirty += shared_dirty;
+                stats[subHeap].privateClean += private_clean;
+                stats[subHeap].sharedClean += shared_clean;
+            }
         }
     }
 }
@@ -261,22 +324,28 @@
     stats_t stats[_NUM_HEAP];
     memset(&stats, 0, sizeof(stats));
 
+
     load_maps(pid, stats);
 
-    for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+    for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
         stats[HEAP_UNKNOWN].pss += stats[i].pss;
+        stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss;
         stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
         stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
+        stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
         stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
     }
 
     for (int i=0; i<_NUM_CORE_HEAP; i++) {
         env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
+        env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss);
         env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
         env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
+        env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
         env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
     }
 
+
     jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
 
     jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
@@ -287,8 +356,10 @@
     int j=0;
     for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
         otherArray[j++] = stats[i].pss;
+        otherArray[j++] = stats[i].swappablePss;
         otherArray[j++] = stats[i].privateDirty;
         otherArray[j++] = stats[i].sharedDirty;
+        otherArray[j++] = stats[i].privateClean;
         otherArray[j++] = stats[i].sharedClean;
     }
 
@@ -630,11 +701,13 @@
     // Sanity check the number of other statistics expected in Java matches here.
     jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I");
     jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field);
+    jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I");
+    jint numDvkStats = env->GetStaticIntField(clazz, numDvkStats_field);
     int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP;
-    if (numOtherStats != expectedNumOtherStats) {
+    if ((numOtherStats + numDvkStats) != expectedNumOtherStats) {
         jniThrowExceptionFmt(env, "java/lang/RuntimeException",
-                             "android.os.Debug.Meminfo.NUM_OTHER_STATS=%d expected %d",
-                             numOtherStats, expectedNumOtherStats);
+                             "android.os.Debug.Meminfo.NUM_OTHER_STATS+android.os.Debug.Meminfo.NUM_DVK_STATS=%d expected %d",
+                             numOtherStats+numDvkStats, expectedNumOtherStats);
         return JNI_ERR;
     }
 
@@ -643,10 +716,14 @@
     for (int i=0; i<_NUM_CORE_HEAP; i++) {
         stat_fields[i].pss_field =
                 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
+        stat_fields[i].pssSwappable_field =
+                env->GetFieldID(clazz, stat_field_names[i].pssSwappable_name, "I");
         stat_fields[i].privateDirty_field =
                 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
         stat_fields[i].sharedDirty_field =
                 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
+        stat_fields[i].privateClean_field =
+                env->GetFieldID(clazz, stat_field_names[i].privateClean_name, "I");
         stat_fields[i].sharedClean_field =
                 env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I");
     }