Implement issue #11050739: Show swapped out RAM

Add "swapped out" field to mem info everywhere.

Change-Id: I89abe8eb0e91fa5c193da93815dc592593c8a3c8
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 62f057f..054ee4f6 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -80,6 +80,7 @@
     jfieldID sharedDirty_field;
     jfieldID privateClean_field;
     jfieldID sharedClean_field;
+    jfieldID swappedOut_field;
 };
 
 struct stat_field_names {
@@ -89,14 +90,18 @@
     const char* sharedDirty_name;
     const char* privateClean_name;
     const char* sharedClean_name;
+    const char* swappedOut_name;
 };
 
 static stat_fields stat_fields[_NUM_CORE_HEAP];
 
 static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
-    { "otherPss", "otherSwappablePss", "otherPrivateDirty", "otherSharedDirty", "otherPrivateClean", "otherSharedClean" },
-    { "dalvikPss", "dalvikSwappablePss", "dalvikPrivateDirty", "dalvikSharedDirty", "dalvikPrivateClean", "dalvikSharedClean" },
-    { "nativePss", "nativeSwappablePss", "nativePrivateDirty", "nativeSharedDirty", "nativePrivateClean", "nativeSharedClean" }
+    { "otherPss", "otherSwappablePss", "otherPrivateDirty", "otherSharedDirty",
+        "otherPrivateClean", "otherSharedClean", "otherSwappedOut" },
+    { "dalvikPss", "dalvikSwappablePss", "dalvikPrivateDirty", "dalvikSharedDirty",
+        "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut" },
+    { "nativePss", "nativeSwappablePss", "nativePrivateDirty", "nativeSharedDirty",
+        "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut" }
 };
 
 jfieldID otherStats_field;
@@ -110,6 +115,7 @@
     int sharedDirty;
     int privateClean;
     int sharedClean;
+    int swappedOut;
 };
 
 #define BINDER_STATS "/proc/binder/stats"
@@ -219,6 +225,7 @@
     float sharing_proportion = 0.0;
     unsigned shared_clean = 0, shared_dirty = 0;
     unsigned private_clean = 0, private_dirty = 0;
+    unsigned swapped_out = 0;
     bool is_swappable = false;
     unsigned referenced = 0;
     unsigned temp;
@@ -333,28 +340,36 @@
         //ALOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
         //    isSqliteHeap, line);
 
+        shared_clean = 0;
+        shared_dirty = 0;
+        private_clean = 0;
+        private_dirty = 0;
+        swapped_out = 0;
+
         while (true) {
             if (fgets(line, 1024, fp) == 0) {
                 done = true;
                 break;
             }
 
-            if (sscanf(line, "Size: %d kB", &temp) == 1) {
+            if (line[0] == 'S' && sscanf(line, "Size: %d kB", &temp) == 1) {
                 size = temp;
-            } else if (sscanf(line, "Rss: %d kB", &temp) == 1) {
+            } else if (line[0] == 'R' && sscanf(line, "Rss: %d kB", &temp) == 1) {
                 resident = temp;
-            } else if (sscanf(line, "Pss: %d kB", &temp) == 1) {
+            } else if (line[0] == 'P' && sscanf(line, "Pss: %d kB", &temp) == 1) {
                 pss = temp;
-            } else if (sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
+            } else if (line[0] == 'S' && sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
                 shared_clean = temp;
-            } else if (sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
+            } else if (line[0] == 'S' && sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
                 shared_dirty = temp;
-            } else if (sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
+            } else if (line[0] == 'P' && sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
                 private_clean = temp;
-            } else if (sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
+            } else if (line[0] == 'P' && sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
                 private_dirty = temp;
-            } else if (sscanf(line, "Referenced: %d kB", &temp) == 1) {
+            } else if (line[0] == 'R' && sscanf(line, "Referenced: %d kB", &temp) == 1) {
                 referenced = temp;
+            } else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
+                swapped_out = temp;
             } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') {
                 // looks like a new mapping
                 // example: "10000000-10001000 ---p 10000000 00:00 0"
@@ -366,7 +381,8 @@
             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);
+                    sharing_proportion = (pss - private_clean
+                            - private_dirty)/(shared_clean+shared_dirty);
                 }
                 swappable_pss = (sharing_proportion*shared_clean) + private_clean;
             } else
@@ -378,6 +394,7 @@
             stats[whichHeap].sharedDirty += shared_dirty;
             stats[whichHeap].privateClean += private_clean;
             stats[whichHeap].sharedClean += shared_clean;
+            stats[whichHeap].swappedOut += swapped_out;
             if (whichHeap == HEAP_DALVIK || whichHeap == HEAP_DALVIK_OTHER) {
                 stats[subHeap].pss += pss;
                 stats[subHeap].swappablePss += swappable_pss;
@@ -385,6 +402,7 @@
                 stats[subHeap].sharedDirty += shared_dirty;
                 stats[subHeap].privateClean += private_clean;
                 stats[subHeap].sharedClean += shared_clean;
+                stats[subHeap].swappedOut += swapped_out;
             }
         }
     }
@@ -428,6 +446,7 @@
         stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
         stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
         stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
+        stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
     }
 
     for (int i=0; i<_NUM_CORE_HEAP; i++) {
@@ -437,6 +456,7 @@
         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);
+        env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
     }
 
 
@@ -455,6 +475,7 @@
         otherArray[j++] = stats[i].sharedDirty;
         otherArray[j++] = stats[i].privateClean;
         otherArray[j++] = stats[i].sharedClean;
+        otherArray[j++] = stats[i].swappedOut;
     }
 
     env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
@@ -971,6 +992,8 @@
                 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");
+        stat_fields[i].swappedOut_field =
+                env->GetFieldID(clazz, stat_field_names[i].swappedOut_name, "I");
     }
 
     return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));