Fix issue #10903002: com.facebook.katana keeps itself in A Services

Now when memory low, if a service's process is above
a selected pss, then the process is not allowed to go
in to the service a list.

Also simplified the normal meminfo details dump to not
include the shared dirty and shared clean sizes by
default, since these can be very confusing.  You will
still get to see them with the "-a" flag.

Finally some small steps to better managing service
processes in the LRU list, so hopefully we can some
day be better about letting them drop down in the list
when there isn't really much interesting happening in
the process.  Not yet used at this point.

Change-Id: I654bfd6d05de2a63120185ebb15ffda8cbeb5dac
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3e20f1f..6605b5b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -533,7 +533,8 @@
     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 %8s %8s";
+        private static final String HEAP_FULL_COLUMN = "%13s %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 DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
@@ -892,18 +893,18 @@
 
         @Override
         public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
-                boolean dumpInfo, boolean dumpDalvik, String[] args) {
+                boolean dumpFullInfo, boolean dumpDalvik, String[] args) {
             FileOutputStream fout = new FileOutputStream(fd);
             PrintWriter pw = new FastPrintWriter(fout);
             try {
-                dumpMemInfo(pw, mem, checkin, dumpInfo, dumpDalvik);
+                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik);
             } finally {
                 pw.flush();
             }
         }
 
         private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
-                boolean dumpInfo, boolean dumpDalvik) {
+                boolean dumpFullInfo, boolean dumpDalvik) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
             long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
             long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -1036,20 +1037,37 @@
             }
 
             // otherwise, show human-readable format
-            printRow(pw, HEAP_COLUMN, "", "Pss", "Pss","Shared", "Private", "Shared", "Private",
-                    "Heap", "Heap", "Heap");
-            printRow(pw, HEAP_COLUMN, "", "Total", "Clean", "Dirty", "Dirty", "Clean", "Clean",
-                    "Size", "Alloc", "Free");
-            printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------",
-                    "------", "------", "------", "------");
-            printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss, memInfo.nativeSwappablePss,
-                    memInfo.nativeSharedDirty,
-                    memInfo.nativePrivateDirty, memInfo.nativeSharedClean,
-                    memInfo.nativePrivateClean, nativeMax, nativeAllocated, nativeFree);
-            printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss, memInfo.dalvikSwappablePss,
-                    memInfo.dalvikSharedDirty,
-                    memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
-                    memInfo.dalvikPrivateClean, dalvikMax, dalvikAllocated, dalvikFree);
+            if (dumpFullInfo) {
+                printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private",
+                        "Shared", "Private", "Heap", "Heap", "Heap");
+                printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty",
+                        "Clean", "Clean", "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, nativeMax, nativeAllocated, nativeFree);
+                printRow(pw, HEAP_FULL_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+                        memInfo.dalvikSwappablePss, memInfo.dalvikSharedDirty,
+                        memInfo.dalvikPrivateDirty, memInfo.dalvikSharedClean,
+                        memInfo.dalvikPrivateClean, dalvikMax, dalvikAllocated, dalvikFree);
+            } else {
+                printRow(pw, HEAP_COLUMN, "", "Pss", "Pss", "Private",
+                        "Private", "Heap", "Heap", "Heap");
+                printRow(pw, HEAP_COLUMN, "", "Total", "Clean", "Dirty",
+                        "Clean", "Size", "Alloc", "Free");
+                printRow(pw, HEAP_COLUMN, "", "------", "------", "------",
+                        "------", "------", "------", "------");
+                printRow(pw, HEAP_COLUMN, "Native Heap", memInfo.nativePss,
+                        memInfo.nativeSwappablePss,
+                        memInfo.nativePrivateDirty,
+                        memInfo.nativePrivateClean, nativeMax, nativeAllocated, nativeFree);
+                printRow(pw, HEAP_COLUMN, "Dalvik Heap", memInfo.dalvikPss,
+                        memInfo.dalvikSwappablePss,
+                        memInfo.dalvikPrivateDirty,
+                        memInfo.dalvikPrivateClean, dalvikMax, dalvikAllocated, dalvikFree);
+            }
 
             int otherPss = memInfo.otherPss;
             int otherSwappablePss = memInfo.otherSwappablePss;
@@ -1067,9 +1085,15 @@
                 final int myPrivateClean = memInfo.getOtherPrivateClean(i);
                 if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
                         || mySharedClean != 0 || myPrivateClean != 0) {
-                    printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
-                            myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
-                            mySharedClean, myPrivateClean, "", "", "");
+                    if (dumpFullInfo) {
+                        printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+                                mySharedClean, myPrivateClean, "", "", "");
+                    } else {
+                        printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                myPss, mySwappablePss, myPrivateDirty,
+                                myPrivateClean, "", "", "");
+                    }
                     otherPss -= myPss;
                     otherSwappablePss -= mySwappablePss;
                     otherSharedDirty -= mySharedDirty;
@@ -1079,16 +1103,27 @@
                 }
             }
 
-
-
-            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);
+            if (dumpFullInfo) {
+                printRow(pw, HEAP_FULL_COLUMN, "Unknown", otherPss, otherSwappablePss,
+                        otherSharedDirty, otherPrivateDirty, otherSharedClean, otherPrivateClean,
+                        "", "", "");
+                printRow(pw, HEAP_FULL_COLUMN, "TOTAL", memInfo.getTotalPss(),
+                        memInfo.getTotalSwappablePss(),
+                        memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+                        memInfo.getTotalSharedClean(), memInfo.getTotalPrivateClean(),
+                        nativeMax+dalvikMax,
+                        nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+            } else {
+                printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSwappablePss,
+                        otherPrivateDirty, otherPrivateClean,
+                        "", "", "");
+                printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+                        memInfo.getTotalSwappablePss(),
+                        memInfo.getTotalPrivateDirty(),
+                        memInfo.getTotalPrivateClean(),
+                        nativeMax+dalvikMax,
+                        nativeAllocated+dalvikAllocated, nativeFree+dalvikFree);
+            }
 
             if (dumpDalvik) {
                 pw.println(" ");
@@ -1104,9 +1139,15 @@
                     final int myPrivateClean = memInfo.getOtherPrivateClean(i);
                     if (myPss != 0 || mySharedDirty != 0 || myPrivateDirty != 0
                             || mySharedClean != 0 || myPrivateClean != 0) {
-                        printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
-                                myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
-                                mySharedClean, myPrivateClean, "", "", "");
+                        if (dumpFullInfo) {
+                            printRow(pw, HEAP_FULL_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                    myPss, mySwappablePss, mySharedDirty, myPrivateDirty,
+                                    mySharedClean, myPrivateClean, "", "", "");
+                        } else {
+                            printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
+                                    myPss, mySwappablePss, myPrivateDirty,
+                                    myPrivateClean, "", "", "");
+                        }
                     }
                 }
             }
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 0c718f4..0a1ffc9 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1031,7 +1031,13 @@
     /** @hide */
     public static final int MEMINFO_SLAB = 5;
     /** @hide */
-    public static final int MEMINFO_COUNT = 6;
+    public static final int MEMINFO_SWAP_TOTAL = 6;
+    /** @hide */
+    public static final int MEMINFO_SWAP_FREE = 7;
+    /** @hide */
+    public static final int MEMINFO_ZRAM_TOTAL = 8;
+    /** @hide */
+    public static final int MEMINFO_COUNT = 9;
 
     /**
      * Retrieves /proc/meminfo.  outSizes is filled with fields
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index ad65433..5f240f7 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -16,47 +16,11 @@
 
 package com.android.internal.util;
 
-import java.io.FileInputStream;
-
 import android.os.Debug;
 import android.os.StrictMode;
 
-public class MemInfoReader {
-    byte[] mBuffer = new byte[1024];
-
-    private long mTotalSize;
-    private long mFreeSize;
-    private long mCachedSize;
-
-    private boolean matchText(byte[] buffer, int index, String text) {
-        int N = text.length();
-        if ((index+N) >= buffer.length) {
-            return false;
-        }
-        for (int i=0; i<N; i++) {
-            if (buffer[index+i] != text.charAt(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private long extractMemValue(byte[] buffer, int index) {
-        while (index < buffer.length && buffer[index] != '\n') {
-            if (buffer[index] >= '0' && buffer[index] <= '9') {
-                int start = index;
-                index++;
-                while (index < buffer.length && buffer[index] >= '0'
-                    && buffer[index] <= '9') {
-                    index++;
-                }
-                String str = new String(buffer, 0, start, index-start);
-                return ((long)Integer.parseInt(str)) * 1024;
-            }
-            index++;
-        }
-        return 0;
-    }
+public final class MemInfoReader {
+    final long[] mInfos = new long[Debug.MEMINFO_COUNT];
 
     public void readMemInfo() {
         // Permit disk reads here, as /proc/meminfo isn't really "on
@@ -64,25 +28,57 @@
         // /proc/ and /sys/ files perhaps?
         StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
         try {
-            long[] infos = new long[Debug.MEMINFO_COUNT];
-            Debug.getMemInfo(infos);
-            mTotalSize = infos[Debug.MEMINFO_TOTAL] * 1024;
-            mFreeSize = infos[Debug.MEMINFO_FREE] * 1024;
-            mCachedSize = infos[Debug.MEMINFO_CACHED] * 1024;
+            Debug.getMemInfo(mInfos);
         } finally {
             StrictMode.setThreadPolicy(savedPolicy);
         }
     }
 
     public long getTotalSize() {
-        return mTotalSize;
+        return mInfos[Debug.MEMINFO_TOTAL] * 1024;
     }
 
     public long getFreeSize() {
-        return mFreeSize;
+        return mInfos[Debug.MEMINFO_FREE] * 1024;
     }
 
     public long getCachedSize() {
-        return mCachedSize;
+        return mInfos[Debug.MEMINFO_CACHED] * 1024;
+    }
+
+    public long getTotalSizeKb() {
+        return mInfos[Debug.MEMINFO_TOTAL];
+    }
+
+    public long getFreeSizeKb() {
+        return mInfos[Debug.MEMINFO_FREE];
+    }
+
+    public long getCachedSizeKb() {
+        return mInfos[Debug.MEMINFO_CACHED];
+    }
+
+    public long getBuffersSizeKb() {
+        return mInfos[Debug.MEMINFO_BUFFERS];
+    }
+
+    public long getShmemSizeKb() {
+        return mInfos[Debug.MEMINFO_SHMEM];
+    }
+
+    public long getSlabSizeKb() {
+        return mInfos[Debug.MEMINFO_SLAB];
+    }
+
+    public long getSwapTotalSizeKb() {
+        return mInfos[Debug.MEMINFO_SWAP_TOTAL];
+    }
+
+    public long getSwapFreeSizeKb() {
+        return mInfos[Debug.MEMINFO_SWAP_FREE];
+    }
+
+    public long getZramTotalSizeKb() {
+        return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
     }
 }
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 60540f4..aa5b254 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -516,6 +516,19 @@
     return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
 }
 
+enum {
+    MEMINFO_TOTAL,
+    MEMINFO_FREE,
+    MEMINFO_BUFFERS,
+    MEMINFO_CACHED,
+    MEMINFO_SHMEM,
+    MEMINFO_SLAB,
+    MEMINFO_SWAP_TOTAL,
+    MEMINFO_SWAP_FREE,
+    MEMINFO_ZRAM_TOTAL,
+    MEMINFO_COUNT
+};
+
 static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
 {
     char buffer[1024];
@@ -529,15 +542,15 @@
     int fd = open("/proc/meminfo", O_RDONLY);
 
     if (fd < 0) {
-        printf("Unable to open /proc/meminfo: %s\n", strerror(errno));
+        ALOGW("Unable to open /proc/meminfo: %s\n", strerror(errno));
         return;
     }
 
-    const int len = read(fd, buffer, sizeof(buffer)-1);
+    int len = read(fd, buffer, sizeof(buffer)-1);
     close(fd);
 
     if (len < 0) {
-        printf("Empty /proc/meminfo");
+        ALOGW("Empty /proc/meminfo");
         return;
     }
     buffer[len] = 0;
@@ -549,6 +562,8 @@
             "Cached:",
             "Shmem:",
             "Slab:",
+            "SwapTotal:",
+            "SwapFree:",
             NULL
     };
     static const int tagsLen[] = {
@@ -558,12 +573,14 @@
             7,
             6,
             5,
+            10,
+            9,
             0
     };
-    long mem[] = { 0, 0, 0, 0, 0, 0 };
+    long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
     char* p = buffer;
-    while (*p && numFound < 6) {
+    while (*p && numFound < 8) {
         int i = 0;
         while (tags[i]) {
             if (strncmp(p, tags[i], tagsLen[i]) == 0) {
@@ -587,7 +604,20 @@
         if (*p) p++;
     }
 
+    fd = open("/sys/block/zram0/mem_used_total", O_RDONLY);
+    if (fd >= 0) {
+        len = read(fd, buffer, sizeof(buffer)-1);
+        close(fd);
+        if (len > 0) {
+            buffer[len] = 0;
+            mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer);
+        }
+    }
+
     int maxNum = env->GetArrayLength(out);
+    if (maxNum > MEMINFO_COUNT) {
+        maxNum = MEMINFO_COUNT;
+    }
     jlong* outArray = env->GetLongArrayElements(out, 0);
     if (outArray != NULL) {
         for (int i=0; i<maxNum && tags[i]; i++) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4f73588..3d1ace9 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -504,6 +504,12 @@
     int mLruProcessActivityStart = 0;
 
     /**
+     * Where in mLruProcesses that the processes hosting services start.
+     * This is after (lower index) than mLruProcessesActivityStart.
+     */
+    int mLruProcessServiceStart = 0;
+
+    /**
      * List of processes that should gc as soon as things are idle.
      */
     final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>();
@@ -853,6 +859,7 @@
      * determine on the next iteration which should be B services.
      */
     int mNumServiceProcs = 0;
+    int mNewNumAServiceProcs = 0;
     int mNewNumServiceProcs = 0;
 
     /**
@@ -1540,7 +1547,15 @@
                         logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
                         logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
                         logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
-
+                        if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
+                            logBuilder.append("  ZRAM: ");
+                            logBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
+                            logBuilder.append(" kB RAM, ");
+                            logBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
+                            logBuilder.append(" kB swap total, ");
+                            logBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
+                            logBuilder.append(" kB swap free\n");
+                        }
                         Slog.i(TAG, logBuilder.toString());
 
                         StringBuilder dropBuilder = new StringBuilder(1024);
@@ -2250,6 +2265,12 @@
             return index;
         }
 
+        if (lrui >= index) {
+            // Don't want to cause this to move dependent processes *back* in the
+            // list as if they were less frequently used.
+            return index;
+        }
+
         if (lrui >= mLruProcessActivityStart) {
             // Don't want to touch dependent processes that are hosting activities.
             return index;
@@ -2269,12 +2290,16 @@
             if (lrui <= mLruProcessActivityStart) {
                 mLruProcessActivityStart--;
             }
+            if (lrui <= mLruProcessServiceStart) {
+                mLruProcessServiceStart--;
+            }
             mLruProcesses.remove(lrui);
         }
     }
 
     final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj, boolean activityChange) {
         final boolean hasActivity = app.activities.size() > 0;
+        final boolean hasService = false; // not impl yet. app.services.size() > 0;
         if (!activityChange && hasActivity) {
             // The process has activties, so we are only going to allow activity-based
             // adjustments move it.  It should be kept in the front of the list with other
@@ -2293,19 +2318,28 @@
             if (lrui < mLruProcessActivityStart) {
                 mLruProcessActivityStart--;
             }
+            if (lrui < mLruProcessServiceStart) {
+                mLruProcessServiceStart--;
+            }
             mLruProcesses.remove(lrui);
         }
 
         int nextIndex;
-        if (!hasActivity) {
-            // Process doesn't have activities, it goes to the top of the non-activity area.
-            mLruProcesses.add(mLruProcessActivityStart, app);
-            nextIndex = mLruProcessActivityStart-1;
-            mLruProcessActivityStart++;
-        } else {
-            // Process does have activities, put it at the very tipsy-top.
+        if (hasActivity) {
+            // Process has activities, put it at the very tipsy-top.
             mLruProcesses.add(app);
             nextIndex = mLruProcessActivityStart;
+        } else if (hasService) {
+            // Process has services, put it at the top of the service list.
+            mLruProcesses.add(mLruProcessActivityStart, app);
+            nextIndex = mLruProcessServiceStart;
+            mLruProcessActivityStart++;
+        } else  {
+            // Process not otherwise of interest, it goes to the top of the non-service area.
+            mLruProcesses.add(mLruProcessServiceStart, app);
+            nextIndex = mLruProcessServiceStart-1;
+            mLruProcessActivityStart++;
+            mLruProcessServiceStart++;
         }
 
         // If the app is currently using a content provider or service,
@@ -2359,7 +2393,7 @@
                 && mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
                 && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
             if (DEBUG_PSS) Slog.d(TAG, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
-            if (proc.lastCachedPss >= mProcessList.getCachedRestoreThreshold()) {
+            if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
                 if (proc.baseProcessTracker != null) {
                     proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
                 }
@@ -10327,8 +10361,10 @@
                 pw.println();
             }
             pw.print("  Process LRU list (sorted by oom_adj, "); pw.print(mLruProcesses.size());
-                    pw.print(" total, non-activities at ");
+                    pw.print(" total, non-act at ");
                     pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+                    pw.print(", non-svc at ");
+                    pw.print(mLruProcesses.size()-mLruProcessServiceStart);
                     pw.println("):");
             dumpProcessOomList(pw, this, mLruProcesses, "    ", "Proc", "PERS", false, dumpPackage);
             needSep = true;
@@ -10704,8 +10740,10 @@
 
             if (needSep) pw.println();
             pw.print("  Process OOM control ("); pw.print(mLruProcesses.size());
-                    pw.print(" total, non-activities at ");
+                    pw.print(" total, non-act at ");
                     pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+                    pw.print(", non-svc at ");
+                    pw.print(mLruProcesses.size()-mLruProcessServiceStart);
                     pw.println("):");
             dumpProcessOomList(pw, this, mLruProcesses, "    ", "Proc", "PERS", true, null);
             needSep = true;
@@ -11513,6 +11551,7 @@
     final void dumpApplicationMemoryUsage(FileDescriptor fd,
             PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
         boolean dumpDetails = false;
+        boolean dumpFullDetails = false;
         boolean dumpDalvik = false;
         boolean oomOnly = false;
         boolean isCompact = false;
@@ -11526,6 +11565,7 @@
             opti++;
             if ("-a".equals(opt)) {
                 dumpDetails = true;
+                dumpFullDetails = true;
                 dumpDalvik = true;
             } else if ("-d".equals(opt)) {
                 dumpDalvik = true;
@@ -11613,7 +11653,8 @@
                 if (dumpDetails) {
                     try {
                         pw.flush();
-                        thread.dumpMemInfo(fd, mi, isCheckinRequest, true, dumpDalvik, innerArgs);
+                        thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
+                                dumpDalvik, innerArgs);
                     } catch (RemoteException e) {
                         if (!isCheckinRequest) {
                             pw.println("Got RemoteException!");
@@ -11754,25 +11795,53 @@
             if (!isCompact) {
                 pw.println();
             }
+            MemInfoReader memInfo = new MemInfoReader();
+            memInfo.readMemInfo();
             if (!brief) {
-                MemInfoReader memInfo = new MemInfoReader();
-                memInfo.readMemInfo();
                 if (!isCompact) {
-                    pw.print("Total RAM: "); pw.print(memInfo.getTotalSize()/1024);
+                    pw.print("Total RAM: "); pw.print(memInfo.getTotalSizeKb());
                     pw.println(" kB");
-                    pw.print(" Free RAM: "); pw.print(cachedPss + (memInfo.getCachedSize()/1024)
-                            + (memInfo.getFreeSize()/1024)); pw.println(" kB");
+                    pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
+                            + memInfo.getFreeSizeKb()); pw.print(" kB (");
+                            pw.print(cachedPss); pw.print(" cached pss + ");
+                            pw.print(memInfo.getCachedSizeKb()); pw.print(" cached + ");
+                            pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
                 } else {
-                    pw.print("ram,"); pw.print(memInfo.getTotalSize()/1024); pw.print(",");
-                    pw.print(cachedPss + (memInfo.getCachedSize()/1024)
-                            + (memInfo.getFreeSize()/1024)); pw.print(",");
+                    pw.print("ram,"); pw.print(memInfo.getTotalSizeKb()); pw.print(",");
+                    pw.print(cachedPss + memInfo.getCachedSizeKb()
+                            + memInfo.getFreeSizeKb()); pw.print(",");
                     pw.println(totalPss - cachedPss);
                 }
             }
             if (!isCompact) {
-                pw.print(" Used PSS: "); pw.print(totalPss - cachedPss); pw.println(" kB");
+                pw.print(" Used RAM: "); pw.print(totalPss - cachedPss
+                        + memInfo.getBuffersSizeKb() + memInfo.getShmemSizeKb()
+                        + memInfo.getSlabSizeKb()); pw.print(" kB (");
+                        pw.print(totalPss - cachedPss); pw.print(" used pss + ");
+                        pw.print(memInfo.getBuffersSizeKb()); pw.print(" buffers + ");
+                        pw.print(memInfo.getShmemSizeKb()); pw.print(" shmem + ");
+                        pw.print(memInfo.getSlabSizeKb()); pw.println(" slab)");
+                pw.print(" Lost RAM: "); pw.print(memInfo.getTotalSizeKb()
+                        - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+                        - memInfo.getBuffersSizeKb() - memInfo.getShmemSizeKb()
+                        - memInfo.getSlabSizeKb()); pw.println(" kB");
             }
             if (!brief) {
+                if (memInfo.getZramTotalSizeKb() != 0) {
+                    if (!isCompact) {
+                        pw.print("     ZRAM: "); pw.print(memInfo.getZramTotalSizeKb());
+                                pw.print(" kB used for ");
+                                pw.print(memInfo.getSwapTotalSizeKb()
+                                        - memInfo.getSwapFreeSizeKb());
+                                pw.print(" kB in swap (");
+                                pw.print(memInfo.getSwapTotalSizeKb());
+                                pw.println(" kB total swap)");
+                    } else {
+                        pw.print("zram,"); pw.print(memInfo.getZramTotalSizeKb()); pw.print(",");
+                                pw.print(memInfo.getSwapTotalSizeKb()); pw.print(",");
+                                pw.println(memInfo.getSwapFreeSizeKb());
+                    }
+                }
                 final int[] SINGLE_LONG_FORMAT = new int[] {
                     Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
                 };
@@ -11807,6 +11876,9 @@
                     pw.print("), oom ");
                     pw.print(mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024);
                     pw.print(" kB");
+                    pw.print(", restore limit ");
+                    pw.print(mProcessList.getCachedRestoreThresholdKb());
+                    pw.print(" kB");
                     if (ActivityManager.isLowRamDeviceStatic()) {
                         pw.print(" (low-ram)");
                     }
@@ -14342,14 +14414,30 @@
 
         if (adj == ProcessList.SERVICE_ADJ) {
             if (doingAll) {
-                app.serviceb = mNewNumServiceProcs > (mNumServiceProcs/3);
+                app.serviceb = mNewNumAServiceProcs > (mNumServiceProcs/3);
                 mNewNumServiceProcs++;
+                //Slog.i(TAG, "ADJ " + app + " serviceb=" + app.serviceb);
+                if (!app.serviceb) {
+                    // This service isn't far enough down on the LRU list to
+                    // normally be a B service, but if we are low on RAM and it
+                    // is large we want to force it down since we would prefer to
+                    // keep launcher over it.
+                    if (mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
+                            && app.lastPss >= mProcessList.getCachedRestoreThresholdKb()) {
+                        app.serviceHighRam = true;
+                        app.serviceb = true;
+                        //Slog.i(TAG, "ADJ " + app + " high ram!");
+                    } else {
+                        mNewNumAServiceProcs++;
+                        //Slog.i(TAG, "ADJ " + app + " not high ram!");
+                    }
+                } else {
+                    app.serviceHighRam = false;
+                }
             }
             if (app.serviceb) {
                 adj = ProcessList.SERVICE_B_ADJ;
             }
-        } else {
-            app.serviceb = false;
         }
 
         app.curRawAdj = adj;
@@ -14905,6 +14993,7 @@
 
         mAdjSeq++;
         mNewNumServiceProcs = 0;
+        mNewNumAServiceProcs = 0;
 
         final int emptyProcessLimit;
         final int cachedProcessLimit;
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index f24e7fe..d3777c7 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -502,7 +502,7 @@
      * Return the maximum pss size in kb that we consider a process acceptable to
      * restore from its cached state for running in the background when RAM is low.
      */
-    long getCachedRestoreThreshold() {
+    long getCachedRestoreThresholdKb() {
         return mCachedRestoreLevel;
     }
 
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index c5491ef..4b62e7d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -82,6 +82,7 @@
     int setProcState = -1;      // Last set process state in process tracker
     int pssProcState = -1;      // The proc state we are currently requesting pss for
     boolean serviceb;           // Process currently is on the service B list
+    boolean serviceHighRam;     // We are forcing to service B list due to its RAM use
     boolean keeping;            // Actively running code so don't kill due to that?
     boolean setIsForeground;    // Running foreground UI when last set?
     boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
@@ -223,10 +224,13 @@
                 pw.print(" lruSeq="); pw.print(lruSeq);
                 pw.print(" lastPss="); pw.print(lastPss);
                 pw.print(" lastCachedPss="); pw.println(lastCachedPss);
-        pw.print(prefix); pw.print("serviceb="); pw.print(serviceb);
-                pw.print(" keeping="); pw.print(keeping);
+        pw.print(prefix); pw.print("keeping="); pw.print(keeping);
                 pw.print(" cached="); pw.print(cached);
                 pw.print(" empty="); pw.println(empty);
+        if (serviceb) {
+            pw.print(prefix); pw.print("serviceb="); pw.print(serviceb);
+                    pw.print(" serviceHighRam="); pw.println(serviceHighRam);
+        }
         if (notCachedSinceIdle) {
             pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
                     pw.print(" initialIdlePss="); pw.println(initialIdlePss);