Merge "Add more memory usage stats"
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");
     }