Move OOM kernel settings to activity manager.

The activity manager now take care of plugging the correct settings
into the OOM killer in the kernel.  This is a lot cleaner because
it is really central to how the activity manager works, and nobody
else cares about them.

Taking advantage of this, the activity manager computes what it
thinks are appropriate OOM levels based on the RAM and display
size of the device.

Also a small optization to the package manager to keep a binding
to the package install helper for a bit after done using it, to
avoid thrashing on it.

And some new APIs that are now needed by Settings.

Change-Id: I2b2d379194445d8305bde331c19bde91c8f24751
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d207a0a..f7e5cf1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -864,6 +864,15 @@
          */
         public boolean lowMemory;
 
+        /** @hide */
+        public long hiddenAppThreshold;
+        /** @hide */
+        public long secondaryServerThreshold;
+        /** @hide */
+        public long visibleAppThreshold;
+        /** @hide */
+        public long foregroundAppThreshold;
+
         public MemoryInfo() {
         }
 
@@ -875,12 +884,20 @@
             dest.writeLong(availMem);
             dest.writeLong(threshold);
             dest.writeInt(lowMemory ? 1 : 0);
+            dest.writeLong(hiddenAppThreshold);
+            dest.writeLong(secondaryServerThreshold);
+            dest.writeLong(visibleAppThreshold);
+            dest.writeLong(foregroundAppThreshold);
         }
         
         public void readFromParcel(Parcel source) {
             availMem = source.readLong();
             threshold = source.readLong();
             lowMemory = source.readInt() != 0;
+            hiddenAppThreshold = source.readLong();
+            secondaryServerThreshold = source.readLong();
+            visibleAppThreshold = source.readLong();
+            foregroundAppThreshold = source.readLong();
         }
 
         public static final Creator<MemoryInfo> CREATOR
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
new file mode 100644
index 0000000..850e1f0
--- /dev/null
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import java.io.FileInputStream;
+
+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 void readMemInfo() {
+        // Permit disk reads here, as /proc/meminfo isn't really "on
+        // disk" and should be fast.  TODO: make BlockGuard ignore
+        // /proc/ and /sys/ files perhaps?
+        StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            mTotalSize = 0;
+            mFreeSize = 0;
+            mCachedSize = 0;
+            FileInputStream is = new FileInputStream("/proc/meminfo");
+            int len = is.read(mBuffer);
+            is.close();
+            final int BUFLEN = mBuffer.length;
+            int count = 0;
+            for (int i=0; i<len && count < 3; i++) {
+                if (matchText(mBuffer, i, "MemTotal")) {
+                    i += 8;
+                    mTotalSize = extractMemValue(mBuffer, i);
+                    count++;
+                } else if (matchText(mBuffer, i, "MemFree")) {
+                    i += 7;
+                    mFreeSize = extractMemValue(mBuffer, i);
+                    count++;
+                } else if (matchText(mBuffer, i, "Cached")) {
+                    i += 6;
+                    mCachedSize = extractMemValue(mBuffer, i);
+                    count++;
+                }
+                while (i < BUFLEN && mBuffer[i] != '\n') {
+                    i++;
+                }
+            }
+        } catch (java.io.FileNotFoundException e) {
+        } catch (java.io.IOException e) {
+        } finally {
+            StrictMode.setThreadPolicy(savedPolicy);
+        }
+    }
+
+    public long getTotalSize() {
+        return mTotalSize;
+    }
+
+    public long getFreeSize() {
+        return mFreeSize;
+    }
+
+    public long getCachedSize() {
+        return mCachedSize;
+    }
+}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index ba8b58b..d3e12f7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -248,135 +248,9 @@
     // How long we wait until we timeout on key dispatching.
     static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
 
-    // The minimum time we allow between crashes, for us to consider this
-    // application to be bad and stop and its services and reject broadcasts.
-    static final int MIN_CRASH_INTERVAL = 60*1000;
-
     // How long we wait until we timeout on key dispatching during instrumentation.
     static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
 
-    // OOM adjustments for processes in various states:
-
-    // This is a process without anything currently running in it.  Definitely
-    // the first to go! Value set in system/rootdir/init.rc on startup.
-    // This value is initalized in the constructor, careful when refering to
-    // this static variable externally.
-    static final int EMPTY_APP_ADJ;
-
-    // This is a process only hosting activities that are not visible,
-    // so it can be killed without any disruption. Value set in
-    // system/rootdir/init.rc on startup.
-    static final int HIDDEN_APP_MAX_ADJ;
-    static int HIDDEN_APP_MIN_ADJ;
-
-    // This is a process holding the home application -- we want to try
-    // avoiding killing it, even if it would normally be in the background,
-    // because the user interacts with it so much.
-    static final int HOME_APP_ADJ;
-
-    // This is a process currently hosting a backup operation.  Killing it
-    // is not entirely fatal but is generally a bad idea.
-    static final int BACKUP_APP_ADJ;
-
-    // This is a process holding a secondary server -- killing it will not
-    // have much of an impact as far as the user is concerned. Value set in
-    // system/rootdir/init.rc on startup.
-    static final int SECONDARY_SERVER_ADJ;
-
-    // This is a process with a heavy-weight application.  It is in the
-    // background, but we want to try to avoid killing it.  Value set in
-    // system/rootdir/init.rc on startup.
-    static final int HEAVY_WEIGHT_APP_ADJ;
-
-    // This is a process only hosting components that are perceptible to the
-    // user, and we really want to avoid killing them, but they are not
-    // immediately visible. An example is background music playback.  Value set in
-    // system/rootdir/init.rc on startup.
-    static final int PERCEPTIBLE_APP_ADJ;
-
-    // This is a process only hosting activities that are visible to the
-    // user, so we'd prefer they don't disappear. Value set in
-    // system/rootdir/init.rc on startup.
-    static final int VISIBLE_APP_ADJ;
-
-    // This is the process running the current foreground app.  We'd really
-    // rather not kill it! Value set in system/rootdir/init.rc on startup.
-    static final int FOREGROUND_APP_ADJ;
-
-    // This is a process running a core server, such as telephony.  Definitely
-    // don't want to kill it, but doing so is not completely fatal.
-    static final int CORE_SERVER_ADJ = -12;
-
-    // The system process runs at the default adjustment.
-    static final int SYSTEM_ADJ = -16;
-
-    // Memory pages are 4K.
-    static final int PAGE_SIZE = 4*1024;
-    
-    // Corresponding memory levels for above adjustments.
-    static final int EMPTY_APP_MEM;
-    static final int HIDDEN_APP_MEM;
-    static final int HOME_APP_MEM;
-    static final int BACKUP_APP_MEM;
-    static final int SECONDARY_SERVER_MEM;
-    static final int HEAVY_WEIGHT_APP_MEM;
-    static final int PERCEPTIBLE_APP_MEM;
-    static final int VISIBLE_APP_MEM;
-    static final int FOREGROUND_APP_MEM;
-
-    // The minimum number of hidden apps we want to be able to keep around,
-    // without empty apps being able to push them out of memory.
-    static final int MIN_HIDDEN_APPS = 2;
-    
-    // The maximum number of hidden processes we will keep around before
-    // killing them; this is just a control to not let us go too crazy with
-    // keeping around processes on devices with large amounts of RAM.
-    static final int MAX_HIDDEN_APPS = 15;
-    
-    // We put empty content processes after any hidden processes that have
-    // been idle for less than 15 seconds.
-    static final long CONTENT_APP_IDLE_OFFSET = 15*1000;
-    
-    // We put empty content processes after any hidden processes that have
-    // been idle for less than 120 seconds.
-    static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
-    
-    static int getIntProp(String name, boolean allowZero) {
-        String str = SystemProperties.get(name);
-        if (str == null) {
-            throw new IllegalArgumentException("Property not defined: " + name);
-        }
-        int val = Integer.valueOf(str);
-        if (val == 0 && !allowZero) {
-            throw new IllegalArgumentException("Property must not be zero: " + name);
-        }
-        return val;
-    }
-    
-    static {
-        // These values are set in system/rootdir/init.rc on startup.
-        FOREGROUND_APP_ADJ = getIntProp("ro.FOREGROUND_APP_ADJ", true);
-        VISIBLE_APP_ADJ = getIntProp("ro.VISIBLE_APP_ADJ", true);
-        PERCEPTIBLE_APP_ADJ = getIntProp("ro.PERCEPTIBLE_APP_ADJ", true);
-        HEAVY_WEIGHT_APP_ADJ = getIntProp("ro.HEAVY_WEIGHT_APP_ADJ", true);
-        SECONDARY_SERVER_ADJ = getIntProp("ro.SECONDARY_SERVER_ADJ", true);
-        BACKUP_APP_ADJ = getIntProp("ro.BACKUP_APP_ADJ", true);
-        HOME_APP_ADJ = getIntProp("ro.HOME_APP_ADJ", true);
-        HIDDEN_APP_MIN_ADJ = getIntProp("ro.HIDDEN_APP_MIN_ADJ", true);
-        EMPTY_APP_ADJ = getIntProp("ro.EMPTY_APP_ADJ", true);
-        // These days we use the last empty slot for hidden apps as well.
-        HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ;
-        FOREGROUND_APP_MEM = getIntProp("ro.FOREGROUND_APP_MEM", false)*PAGE_SIZE;
-        VISIBLE_APP_MEM = getIntProp("ro.VISIBLE_APP_MEM", false)*PAGE_SIZE;
-        PERCEPTIBLE_APP_MEM = getIntProp("ro.PERCEPTIBLE_APP_MEM", false)*PAGE_SIZE;
-        HEAVY_WEIGHT_APP_MEM = getIntProp("ro.HEAVY_WEIGHT_APP_MEM", false)*PAGE_SIZE;
-        SECONDARY_SERVER_MEM = getIntProp("ro.SECONDARY_SERVER_MEM", false)*PAGE_SIZE;
-        BACKUP_APP_MEM = getIntProp("ro.BACKUP_APP_MEM", false)*PAGE_SIZE;
-        HOME_APP_MEM = getIntProp("ro.HOME_APP_MEM", false)*PAGE_SIZE;
-        HIDDEN_APP_MEM = getIntProp("ro.HIDDEN_APP_MEM", false)*PAGE_SIZE;
-        EMPTY_APP_MEM = getIntProp("ro.EMPTY_APP_MEM", false)*PAGE_SIZE;
-    }
-    
     static final int MY_PID = Process.myPid();
     
     static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -437,6 +311,11 @@
     final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
 
     /**
+     * Process management.
+     */
+    final ProcessList mProcessList = new ProcessList();
+
+    /**
      * All of the applications we currently have running organized by name.
      * The keys are strings of the application package name (as
      * returned by the package manager), and the keys are ApplicationRecord
@@ -900,7 +779,7 @@
      */
     boolean mBooted = false;
 
-    int mProcessLimit = MAX_HIDDEN_APPS;
+    int mProcessLimit = ProcessList.MAX_HIDDEN_APPS;
     int mProcessLimitOverride = -1;
 
     WindowManagerService mWindowManager;
@@ -1327,7 +1206,7 @@
                         info.processName);
                 app.persistent = true;
                 app.pid = MY_PID;
-                app.maxAdj = SYSTEM_ADJ;
+                app.maxAdj = ProcessList.SYSTEM_ADJ;
                 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
                 synchronized (mSelf.mPidsSelfLocked) {
                     mSelf.mPidsSelfLocked.put(app.pid, app);
@@ -1702,23 +1581,23 @@
         } else if (app.pubProviders.size() > 0) {
             // If this process contains content providers, we want to keep
             // it a little more strongly.
-            app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
+            app.lruWeight = app.lastActivityTime - ProcessList.CONTENT_APP_IDLE_OFFSET;
             // Also don't let it kick out the first few "real" hidden processes.
-            skipTop = MIN_HIDDEN_APPS;
+            skipTop = ProcessList.MIN_HIDDEN_APPS;
         } else {
             // If this process doesn't have activities, we less strongly
             // want to keep it around, and generally want to avoid getting
             // in front of any very recently used activities.
-            app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
+            app.lruWeight = app.lastActivityTime - ProcessList.EMPTY_APP_IDLE_OFFSET;
             // Also don't let it kick out the first few "real" hidden processes.
-            skipTop = MIN_HIDDEN_APPS;
+            skipTop = ProcessList.MIN_HIDDEN_APPS;
         }
         
         while (i >= 0) {
             ProcessRecord p = mLruProcesses.get(i);
             // If this app shouldn't be in front of the first N background
             // apps, then skip over that many that are currently hidden.
-            if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
+            if (skipTop > 0 && p.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                 skipTop--;
             }
             if (p.lruWeight <= app.lruWeight || i < bestPos) {
@@ -2800,7 +2679,7 @@
                 boolean haveBg = false;
                 for (int i=mLruProcesses.size()-1; i>=0; i--) {
                     ProcessRecord rec = mLruProcesses.get(i);
-                    if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
+                    if (rec.thread != null && rec.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                         haveBg = true;
                         break;
                     }
@@ -2817,7 +2696,7 @@
                             // The low memory report is overriding any current
                             // state for a GC request.  Make sure to do
                             // heavy/important/visible/foreground processes first.
-                            if (rec.setAdj <= HEAVY_WEIGHT_APP_ADJ) {
+                            if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                                 rec.lastRequestedGc = 0;
                             } else {
                                 rec.lastRequestedGc = rec.lastLowMemory;
@@ -3195,7 +3074,7 @@
                     return;
                 }
                 killPackageProcessesLocked(packageName, pkgUid,
-                        SECONDARY_SERVER_ADJ, false, true, true);
+                        ProcessList.SECONDARY_SERVER_ADJ, false, true, true);
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
@@ -4167,7 +4046,7 @@
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                 "setProcessLimit()");
         synchronized (this) {
-            mProcessLimit = max < 0 ? MAX_HIDDEN_APPS : max;
+            mProcessLimit = max < 0 ? ProcessList.MAX_HIDDEN_APPS : max;
             mProcessLimitOverride = max;
         }
         trimApplications();
@@ -4916,10 +4795,18 @@
     }
 
     public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
+        final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
+        final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ);
         outInfo.availMem = Process.getFreeMemory();
-        outInfo.threshold = HOME_APP_MEM;
-        outInfo.lowMemory = outInfo.availMem <
-                (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
+        outInfo.threshold = homeAppMem;
+        outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2));
+        outInfo.hiddenAppThreshold = hiddenAppMem;
+        outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
+                ProcessList.SECONDARY_SERVER_ADJ);
+        outInfo.visibleAppThreshold = mProcessList.getMemLevel(
+                ProcessList.VISIBLE_APP_ADJ);
+        outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
+                ProcessList.FOREGROUND_APP_ADJ);
     }
     
     // =========================================================
@@ -5641,7 +5528,7 @@
                         r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
                     }
                     cpr.clients.add(r);
-                    if (cpr.app != null && r.setAdj <= PERCEPTIBLE_APP_ADJ) {
+                    if (cpr.app != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                         // If this is a perceptible app accessing the provider,
                         // make sure to count it as being accessed and thus
                         // back up on the LRU list.  This is good because
@@ -6031,7 +5918,7 @@
         if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
                 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
             app.persistent = true;
-            app.maxAdj = CORE_SERVER_ADJ;
+            app.maxAdj = ProcessList.CORE_SERVER_ADJ;
         }
         if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
             mPersistentStartingProcesses.add(app);
@@ -6405,14 +6292,14 @@
             
             // If the worst oom_adj is somewhere in the hidden proc LRU range,
             // then constrain it so we will kill all hidden procs.
-            if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
-                worstType = HIDDEN_APP_MIN_ADJ;
+            if (worstType < ProcessList.EMPTY_APP_ADJ && worstType > ProcessList.HIDDEN_APP_MIN_ADJ) {
+                worstType = ProcessList.HIDDEN_APP_MIN_ADJ;
             }
 
             // If this is not a secure call, don't let it kill processes that
             // are important.
-            if (!secure && worstType < SECONDARY_SERVER_ADJ) {
-                worstType = SECONDARY_SERVER_ADJ;
+            if (!secure && worstType < ProcessList.SECONDARY_SERVER_ADJ) {
+                worstType = ProcessList.SECONDARY_SERVER_ADJ;
             }
 
             Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType);
@@ -6826,7 +6713,7 @@
 
         Long crashTime = mProcessCrashTimes.get(app.info.processName,
                 app.info.uid);
-        if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
+        if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
             // This process loses!
             Slog.w(TAG, "Process " + app.info.processName
                     + " has crashed too many times: killing!");
@@ -7555,21 +7442,21 @@
                         currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
                     }
                     int adj = app.curAdj;
-                    if (adj >= EMPTY_APP_ADJ) {
+                    if (adj >= ProcessList.EMPTY_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
-                    } else if (adj >= HIDDEN_APP_MIN_ADJ) {
+                    } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-                        currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
-                    } else if (adj >= HOME_APP_ADJ) {
+                        currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
+                    } else if (adj >= ProcessList.HOME_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
                         currApp.lru = 0;
-                    } else if (adj >= SECONDARY_SERVER_ADJ) {
+                    } else if (adj >= ProcessList.SECONDARY_SERVER_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
-                    } else if (adj >= HEAVY_WEIGHT_APP_ADJ) {
+                    } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
-                    } else if (adj >= PERCEPTIBLE_APP_ADJ) {
+                    } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
-                    } else if (adj >= VISIBLE_APP_ADJ) {
+                    } else if (adj >= ProcessList.VISIBLE_APP_ADJ) {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
                     } else {
                         currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
@@ -8076,17 +7963,17 @@
             if (needSep) pw.println(" ");
             needSep = true;
             pw.println("  OOM levels:");
-            pw.print("    SYSTEM_ADJ: "); pw.println(SYSTEM_ADJ);
-            pw.print("    CORE_SERVER_ADJ: "); pw.println(CORE_SERVER_ADJ);
-            pw.print("    FOREGROUND_APP_ADJ: "); pw.println(FOREGROUND_APP_ADJ);
-            pw.print("    VISIBLE_APP_ADJ: "); pw.println(VISIBLE_APP_ADJ);
-            pw.print("    PERCEPTIBLE_APP_ADJ: "); pw.println(PERCEPTIBLE_APP_ADJ);
-            pw.print("    HEAVY_WEIGHT_APP_ADJ: "); pw.println(HEAVY_WEIGHT_APP_ADJ);
-            pw.print("    BACKUP_APP_ADJ: "); pw.println(BACKUP_APP_ADJ);
-            pw.print("    SECONDARY_SERVER_ADJ: "); pw.println(SECONDARY_SERVER_ADJ);
-            pw.print("    HOME_APP_ADJ: "); pw.println(HOME_APP_ADJ);
-            pw.print("    HIDDEN_APP_MIN_ADJ: "); pw.println(HIDDEN_APP_MIN_ADJ);
-            pw.print("    EMPTY_APP_ADJ: "); pw.println(EMPTY_APP_ADJ);
+            pw.print("    SYSTEM_ADJ: "); pw.println(ProcessList.SYSTEM_ADJ);
+            pw.print("    CORE_SERVER_ADJ: "); pw.println(ProcessList.CORE_SERVER_ADJ);
+            pw.print("    FOREGROUND_APP_ADJ: "); pw.println(ProcessList.FOREGROUND_APP_ADJ);
+            pw.print("    VISIBLE_APP_ADJ: "); pw.println(ProcessList.VISIBLE_APP_ADJ);
+            pw.print("    PERCEPTIBLE_APP_ADJ: "); pw.println(ProcessList.PERCEPTIBLE_APP_ADJ);
+            pw.print("    HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ);
+            pw.print("    BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ);
+            pw.print("    SECONDARY_SERVER_ADJ: "); pw.println(ProcessList.SECONDARY_SERVER_ADJ);
+            pw.print("    HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ);
+            pw.print("    HIDDEN_APP_MIN_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MIN_ADJ);
+            pw.print("    EMPTY_APP_ADJ: "); pw.println(ProcessList.EMPTY_APP_ADJ);
 
             if (needSep) pw.println(" ");
             needSep = true;
@@ -8754,28 +8641,28 @@
         for (int i=N; i>=0; i--) {
             ProcessRecord r = list.get(i);
             String oomAdj;
-            if (r.setAdj >= EMPTY_APP_ADJ) {
-                oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
-            } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
-                oomAdj = buildOomTag("bak", "  ", r.setAdj, HIDDEN_APP_MIN_ADJ);
-            } else if (r.setAdj >= HOME_APP_ADJ) {
-                oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
-            } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
-                oomAdj = buildOomTag("svc", "  ", r.setAdj, SECONDARY_SERVER_ADJ);
-            } else if (r.setAdj >= BACKUP_APP_ADJ) {
-                oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
-            } else if (r.setAdj >= HEAVY_WEIGHT_APP_ADJ) {
-                oomAdj = buildOomTag("hvy  ", null, r.setAdj, HEAVY_WEIGHT_APP_ADJ);
-            } else if (r.setAdj >= PERCEPTIBLE_APP_ADJ) {
-                oomAdj = buildOomTag("prcp ", null, r.setAdj, PERCEPTIBLE_APP_ADJ);
-            } else if (r.setAdj >= VISIBLE_APP_ADJ) {
-                oomAdj = buildOomTag("vis  ", null, r.setAdj, VISIBLE_APP_ADJ);
-            } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
-                oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
-            } else if (r.setAdj >= CORE_SERVER_ADJ) {
-                oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
-            } else if (r.setAdj >= SYSTEM_ADJ) {
-                oomAdj = buildOomTag("sys  ", null, r.setAdj, SYSTEM_ADJ);
+            if (r.setAdj >= ProcessList.EMPTY_APP_ADJ) {
+                oomAdj = buildOomTag("empty", null, r.setAdj, ProcessList.EMPTY_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+                oomAdj = buildOomTag("bak", "  ", r.setAdj, ProcessList.HIDDEN_APP_MIN_ADJ);
+            } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) {
+                oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.SECONDARY_SERVER_ADJ) {
+                oomAdj = buildOomTag("svc", "  ", r.setAdj, ProcessList.SECONDARY_SERVER_ADJ);
+            } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
+                oomAdj = buildOomTag("bckup", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+                oomAdj = buildOomTag("hvy  ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+                oomAdj = buildOomTag("prcp ", null, r.setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.VISIBLE_APP_ADJ) {
+                oomAdj = buildOomTag("vis  ", null, r.setAdj, ProcessList.VISIBLE_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+                oomAdj = buildOomTag("fore ", null, r.setAdj, ProcessList.FOREGROUND_APP_ADJ);
+            } else if (r.setAdj >= ProcessList.CORE_SERVER_ADJ) {
+                oomAdj = buildOomTag("core ", null, r.setAdj, ProcessList.CORE_SERVER_ADJ);
+            } else if (r.setAdj >= ProcessList.SYSTEM_ADJ) {
+                oomAdj = buildOomTag("sys  ", null, r.setAdj, ProcessList.SYSTEM_ADJ);
             } else {
                 oomAdj = Integer.toString(r.setAdj);
             }
@@ -9029,9 +8916,9 @@
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
 
         final int[] oomAdj = new int[] {
-            SYSTEM_ADJ, CORE_SERVER_ADJ, FOREGROUND_APP_ADJ,
-            VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ, HEAVY_WEIGHT_APP_ADJ,
-            BACKUP_APP_ADJ, SECONDARY_SERVER_ADJ, HOME_APP_ADJ, EMPTY_APP_ADJ
+            ProcessList.SYSTEM_ADJ, ProcessList.CORE_SERVER_ADJ, ProcessList.FOREGROUND_APP_ADJ,
+            ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
+            ProcessList.BACKUP_APP_ADJ, ProcessList.SECONDARY_SERVER_ADJ, ProcessList.HOME_APP_ADJ, ProcessList.EMPTY_APP_ADJ
         };
         final String[] oomLabel = new String[] {
                 "System", "Persistent", "Foreground",
@@ -12538,7 +12425,11 @@
                 // sentinel: fetch the current configuration from the window manager
                 values = mWindowManager.computeNewConfiguration();
             }
-            
+
+            if (mWindowManager != null) {
+                mProcessList.applyDisplaySize(mWindowManager);
+            }
+
             final long origId = Binder.clearCallingIdentity();
             if (values != null) {
                 Settings.System.clearConfiguration(values);
@@ -12688,7 +12579,7 @@
         if (app.thread == null) {
             app.adjSeq = mAdjSeq;
             app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            return (app.curAdj=EMPTY_APP_ADJ);
+            return (app.curAdj=ProcessList.EMPTY_APP_ADJ);
         }
 
         app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
@@ -12699,7 +12590,7 @@
 
         final int activitiesSize = app.activities.size();
 
-        if (app.maxAdj <= FOREGROUND_APP_ADJ) {
+        if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
             // The max adjustment doesn't allow this app to be anything
             // below foreground, so it is not worth doing work for it.
             app.adjType = "fixed";
@@ -12739,26 +12630,26 @@
         int schedGroup;
         if (app == TOP_APP) {
             // The last app on the list is the foreground app.
-            adj = FOREGROUND_APP_ADJ;
+            adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "top-activity";
             app.foregroundActivities = true;
         } else if (app.instrumentationClass != null) {
             // Don't want to kill running instrumentation.
-            adj = FOREGROUND_APP_ADJ;
+            adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "instrumentation";
         } else if (app.curReceiver != null ||
                 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
             // An app that is currently receiving a broadcast also
             // counts as being in the foreground.
-            adj = FOREGROUND_APP_ADJ;
+            adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "broadcast";
         } else if (app.executingServices.size() > 0) {
             // An app that is currently executing a service callback also
             // counts as being in the foreground.
-            adj = FOREGROUND_APP_ADJ;
+            adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "exec-service";
         } else if (activitiesSize > 0) {
@@ -12784,8 +12675,8 @@
                 final ActivityRecord r = app.activities.get(j);
                 if (r.visible) {
                     // App has a visible activity; only upgrade adjustment.
-                    if (adj > VISIBLE_APP_ADJ) {
-                        adj = VISIBLE_APP_ADJ;
+                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
+                        adj = ProcessList.VISIBLE_APP_ADJ;
                         app.adjType = "visible";
                     }
                     schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -12795,8 +12686,8 @@
                 } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED
                         || r.state == ActivityState.STOPPING) {
                     // Only upgrade adjustment.
-                    if (adj > PERCEPTIBLE_APP_ADJ) {
-                        adj = PERCEPTIBLE_APP_ADJ;
+                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                         app.adjType = "stopping";
                     }
                     app.foregroundActivities = true;
@@ -12804,32 +12695,32 @@
             }
         }
 
-        if (adj > PERCEPTIBLE_APP_ADJ) {
+        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
             if (app.foregroundServices) {
                 // The user is aware of this app, so make it visible.
-                adj = PERCEPTIBLE_APP_ADJ;
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                 app.adjType = "foreground-service";
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             } else if (app.forcingToForeground != null) {
                 // The user is aware of this app, so make it visible.
-                adj = PERCEPTIBLE_APP_ADJ;
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                 app.adjType = "force-foreground";
                 app.adjSource = app.forcingToForeground;
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             }
         }
 
-        if (adj > HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) {
+        if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) {
             // We don't want to kill the current heavy-weight process.
-            adj = HEAVY_WEIGHT_APP_ADJ;
+            adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.adjType = "heavy";
         }
 
-        if (adj > HOME_APP_ADJ && app == mHomeProcess) {
+        if (adj > ProcessList.HOME_APP_ADJ && app == mHomeProcess) {
             // This process is hosting what we currently consider to be the
             // home app, so we don't want to let it go into the background.
-            adj = HOME_APP_ADJ;
+            adj = ProcessList.HOME_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.adjType = "home";
         }
@@ -12845,21 +12736,21 @@
 
         if (mBackupTarget != null && app == mBackupTarget.app) {
             // If possible we want to avoid killing apps while they're being backed up
-            if (adj > BACKUP_APP_ADJ) {
+            if (adj > ProcessList.BACKUP_APP_ADJ) {
                 if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app);
-                adj = BACKUP_APP_ADJ;
+                adj = ProcessList.BACKUP_APP_ADJ;
                 app.adjType = "backup";
                 app.hidden = false;
             }
         }
 
-        if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
+        if (app.services.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
             final long now = SystemClock.uptimeMillis();
             // This process is more important if the top activity is
             // bound to the service.
             Iterator<ServiceRecord> jt = app.services.iterator();
-            while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
+            while (jt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
                 ServiceRecord s = jt.next();
                 if (s.startRequested) {
                     if (app.hasShownUi) {
@@ -12867,7 +12758,7 @@
                         // go to the LRU list because it may be pretty heavy with
                         // UI stuff.  We'll tag it with a label just to help
                         // debug and understand what is going on.
-                        if (adj > SECONDARY_SERVER_ADJ) {
+                        if (adj > ProcessList.SECONDARY_SERVER_ADJ) {
                             app.adjType = "started-bg-ui-services";
                         }
                     } else {
@@ -12875,8 +12766,8 @@
                             // This service has seen some activity within
                             // recent memory, so we will keep its process ahead
                             // of the background processes.
-                            if (adj > SECONDARY_SERVER_ADJ) {
-                                adj = SECONDARY_SERVER_ADJ;
+                            if (adj > ProcessList.SECONDARY_SERVER_ADJ) {
+                                adj = ProcessList.SECONDARY_SERVER_ADJ;
                                 app.adjType = "started-services";
                                 app.hidden = false;
                             }
@@ -12884,7 +12775,7 @@
                         // If we have let the service slide into the background
                         // state, still have some text describing what it is doing
                         // even though the service no longer has an impact.
-                        if (adj > SECONDARY_SERVER_ADJ) {
+                        if (adj > ProcessList.SECONDARY_SERVER_ADJ) {
                             app.adjType = "started-bg-services";
                         }
                     }
@@ -12892,13 +12783,13 @@
                     // has said it is doing work.
                     app.keeping = true;
                 }
-                if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
+                if (s.connections.size() > 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                         || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
                     Iterator<ArrayList<ConnectionRecord>> kt
                             = s.connections.values().iterator();
-                    while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
+                    while (kt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
                         ArrayList<ConnectionRecord> clist = kt.next();
-                        for (int i=0; i<clist.size() && adj > FOREGROUND_APP_ADJ; i++) {
+                        for (int i=0; i<clist.size() && adj > ProcessList.FOREGROUND_APP_ADJ; i++) {
                             // XXX should compute this based on the max of
                             // all connected clients.
                             ConnectionRecord cr = clist.get(i);
@@ -12911,10 +12802,10 @@
                                 int clientAdj = adj;
                                 int myHiddenAdj = hiddenAdj;
                                 if (myHiddenAdj > client.hiddenAdj) {
-                                    if (client.hiddenAdj >= VISIBLE_APP_ADJ) {
+                                    if (client.hiddenAdj >= ProcessList.VISIBLE_APP_ADJ) {
                                         myHiddenAdj = client.hiddenAdj;
                                     } else {
-                                        myHiddenAdj = VISIBLE_APP_ADJ;
+                                        myHiddenAdj = ProcessList.VISIBLE_APP_ADJ;
                                     }
                                 }
                                 clientAdj = computeOomAdjLocked(
@@ -12954,16 +12845,16 @@
                                     // about letting this process get into the LRU
                                     // list to be killed and restarted if needed for
                                     // memory.
-                                    if (app.hasShownUi && clientAdj > PERCEPTIBLE_APP_ADJ) {
+                                    if (app.hasShownUi && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                         adjType = "bound-bg-ui-services";
                                     } else {
                                         if ((cr.flags&(Context.BIND_ABOVE_CLIENT
                                                 |Context.BIND_IMPORTANT)) != 0) {
                                             adj = clientAdj;
-                                        } else if (clientAdj >= VISIBLE_APP_ADJ) {
+                                        } else if (clientAdj >= ProcessList.VISIBLE_APP_ADJ) {
                                             adj = clientAdj;
                                         } else {
-                                            adj = VISIBLE_APP_ADJ;
+                                            adj = ProcessList.VISIBLE_APP_ADJ;
                                         }
                                         if (!client.hidden) {
                                             app.hidden = false;
@@ -12989,10 +12880,10 @@
                             }
                             if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
                                 ActivityRecord a = cr.activity;
-                                if (a != null && adj > FOREGROUND_APP_ADJ &&
+                                if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
                                         (a.visible || a.state == ActivityState.RESUMED
                                          || a.state == ActivityState.PAUSING)) {
-                                    adj = FOREGROUND_APP_ADJ;
+                                    adj = ProcessList.FOREGROUND_APP_ADJ;
                                     if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
                                         schedGroup = Process.THREAD_GROUP_DEFAULT;
                                     }
@@ -13021,15 +12912,15 @@
             }
         }
 
-        if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
+        if (app.pubProviders.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
             Iterator<ContentProviderRecord> jt = app.pubProviders.values().iterator();
-            while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
+            while (jt.hasNext() && (adj > ProcessList.FOREGROUND_APP_ADJ
                     || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
                 ContentProviderRecord cpr = jt.next();
                 if (cpr.clients.size() != 0) {
                     Iterator<ProcessRecord> kt = cpr.clients.iterator();
-                    while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
+                    while (kt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
                         ProcessRecord client = kt.next();
                         if (client == app) {
                             // Being our own client is not interesting.
@@ -13037,20 +12928,20 @@
                         }
                         int myHiddenAdj = hiddenAdj;
                         if (myHiddenAdj > client.hiddenAdj) {
-                            if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
+                            if (client.hiddenAdj > ProcessList.FOREGROUND_APP_ADJ) {
                                 myHiddenAdj = client.hiddenAdj;
                             } else {
-                                myHiddenAdj = FOREGROUND_APP_ADJ;
+                                myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
                             }
                         }
                         int clientAdj = computeOomAdjLocked(
                             client, myHiddenAdj, TOP_APP, true);
                         if (adj > clientAdj) {
-                            if (app.hasShownUi && clientAdj > PERCEPTIBLE_APP_ADJ) {
+                            if (app.hasShownUi && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                 app.adjType = "bg-ui-provider";
                             } else {
-                                adj = clientAdj > FOREGROUND_APP_ADJ
-                                        ? clientAdj : FOREGROUND_APP_ADJ;
+                                adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
+                                        ? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
                                 app.adjType = "provider";
                             }
                             if (!client.hidden) {
@@ -13073,8 +12964,8 @@
                 // dependencies, ensure that its adjustment is at least
                 // FOREGROUND_APP_ADJ.
                 if (cpr.externals != 0) {
-                    if (adj > FOREGROUND_APP_ADJ) {
-                        adj = FOREGROUND_APP_ADJ;
+                    if (adj > ProcessList.FOREGROUND_APP_ADJ) {
+                        adj = ProcessList.FOREGROUND_APP_ADJ;
                         schedGroup = Process.THREAD_GROUP_DEFAULT;
                         app.hidden = false;
                         app.keeping = true;
@@ -13091,11 +12982,11 @@
         //      " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
         if (adj > app.maxAdj) {
             adj = app.maxAdj;
-            if (app.maxAdj <= PERCEPTIBLE_APP_ADJ) {
+            if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
             }
         }
-        if (adj < HIDDEN_APP_MIN_ADJ) {
+        if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) {
             app.keeping = true;
         }
 
@@ -13105,15 +12996,15 @@
             // in order to honor the request.  We want to drop it by one adjustment
             // level...  but there is special meaning applied to various levels so
             // we will skip some of them.
-            if (adj < FOREGROUND_APP_ADJ) {
+            if (adj < ProcessList.FOREGROUND_APP_ADJ) {
                 // System process will not get dropped, ever
-            } else if (adj < VISIBLE_APP_ADJ) {
-                adj = VISIBLE_APP_ADJ;
-            } else if (adj < PERCEPTIBLE_APP_ADJ) {
-                adj = PERCEPTIBLE_APP_ADJ;
-            } else if (adj < HIDDEN_APP_MIN_ADJ) {
-                adj = HIDDEN_APP_MIN_ADJ;
-            } else if (adj < EMPTY_APP_ADJ) {
+            } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
+                adj = ProcessList.VISIBLE_APP_ADJ;
+            } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+            } else if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) {
+                adj = ProcessList.HIDDEN_APP_MIN_ADJ;
+            } else if (adj < ProcessList.EMPTY_APP_ADJ) {
                 adj++;
             }
         }
@@ -13170,7 +13061,7 @@
         if (canGcNowLocked()) {
             while (mProcessesToGc.size() > 0) {
                 ProcessRecord proc = mProcessesToGc.remove(0);
-                if (proc.curRawAdj > PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
+                if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
                     if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
                             <= SystemClock.uptimeMillis()) {
                         // To avoid spamming the system, we will GC processes one
@@ -13370,13 +13261,13 @@
         computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
 
         if (app.curRawAdj != app.setRawAdj) {
-            if (app.curRawAdj > FOREGROUND_APP_ADJ
-                    && app.setRawAdj <= FOREGROUND_APP_ADJ) {
+            if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
+                    && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
                 // If this app is transitioning from foreground to
                 // non-foreground, have it do a gc.
                 scheduleAppGcLocked(app);
-            } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
-                    && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
+            } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+                    && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
                 // Likewise do a gc when an app is moving in to the
                 // background (such as a service stopping).
                 scheduleAppGcLocked(app);
@@ -13456,14 +13347,14 @@
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
         int curAdj = app.curAdj;
-        final boolean wasHidden = curAdj >= HIDDEN_APP_MIN_ADJ
-            && curAdj <= HIDDEN_APP_MAX_ADJ;
+        final boolean wasHidden = curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+            && curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ;
 
         mAdjSeq++;
 
         updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
-        final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
-            && app.curAdj <= HIDDEN_APP_MAX_ADJ;
+        final boolean nowHidden = app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+            && app.curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ;
         if (nowHidden != wasHidden) {
             // Changed to/from hidden state, so apps after it in the LRU
             // list may also be changed.
@@ -13487,7 +13378,7 @@
         // how many slots we have for background processes; we may want
         // to put multiple processes in a slot of there are enough of
         // them.
-        int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
+        int numSlots = ProcessList.HIDDEN_APP_MAX_ADJ - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
         int factor = (mLruProcesses.size()-4)/numSlots;
         if (factor < 1) factor = 1;
         int step = 0;
@@ -13496,14 +13387,14 @@
         // First update the OOM adjustment for each of the
         // application processes based on their current state.
         int i = mLruProcesses.size();
-        int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
+        int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
         int numBg = 0;
         while (i > 0) {
             i--;
             ProcessRecord app = mLruProcesses.get(i);
             //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
             updateOomAdjLocked(app, curHiddenAdj, TOP_APP);
-            if (curHiddenAdj < EMPTY_APP_ADJ
+            if (curHiddenAdj < ProcessList.EMPTY_APP_ADJ
                 && app.curAdj == curHiddenAdj) {
                 step++;
                 if (step >= factor) {
@@ -13512,7 +13403,7 @@
                 }
             }
             if (!app.killedBackground) {
-                if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
+                if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                     numHidden++;
                     if (numHidden > mProcessLimit) {
                         Slog.i(TAG, "No longer want " + app.processName
@@ -13524,7 +13415,7 @@
                     } else {
                         numBg++;
                     }
-                } else if (app.curAdj >= HOME_APP_ADJ) {
+                } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) {
                     numBg++;
                 }
             }
@@ -13536,14 +13427,14 @@
         // are managing to keep around is less than half the maximum we desire;
         // if we are keeping a good number around, we'll let them use whatever
         // memory they want.
-        if (numHidden <= (MAX_HIDDEN_APPS/2)) {
+        if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/2)) {
             final int N = mLruProcesses.size();
             factor = numBg/3;
             step = 0;
             int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
             for (i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if (app.curAdj >= HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
+                if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
                     if (app.trimMemoryLevel < curLevel && app.thread != null) {
                         try {
                             app.thread.scheduleTrimMemory(curLevel);
@@ -13567,7 +13458,7 @@
                                 break;
                         }
                     }
-                } else if (app.curAdj == HEAVY_WEIGHT_APP_ADJ) {
+                } else if (app.curAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
                             && app.thread != null) {
                         try {
@@ -13577,7 +13468,7 @@
                         }
                     }
                     app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
-                } else if ((app.curAdj > VISIBLE_APP_ADJ || app.systemNoUi)
+                } else if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
                         && app.pendingUiClean) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                             && app.thread != null) {
@@ -13597,7 +13488,7 @@
             final int N = mLruProcesses.size();
             for (i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if ((app.curAdj > VISIBLE_APP_ADJ || app.systemNoUi)
+                if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
                         && app.pendingUiClean) {
                     if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
                             && app.thread != null) {
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
new file mode 100644
index 0000000..dfcc0bf
--- /dev/null
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import com.android.internal.util.MemInfoReader;
+import com.android.server.wm.WindowManagerService;
+
+import android.graphics.Point;
+import android.os.StrictMode;
+import android.util.Slog;
+
+/**
+ * Activity manager code dealing with processes.
+ */
+class ProcessList {
+    // The minimum time we allow between crashes, for us to consider this
+    // application to be bad and stop and its services and reject broadcasts.
+    static final int MIN_CRASH_INTERVAL = 60*1000;
+
+    // OOM adjustments for processes in various states:
+
+    // This is a process without anything currently running in it.  Definitely
+    // the first to go! Value set in system/rootdir/init.rc on startup.
+    // This value is initalized in the constructor, careful when refering to
+    // this static variable externally.
+    static final int EMPTY_APP_ADJ = 15;
+
+    // This is a process only hosting activities that are not visible,
+    // so it can be killed without any disruption. Value set in
+    // system/rootdir/init.rc on startup.
+    static final int HIDDEN_APP_MAX_ADJ = 15;
+    static int HIDDEN_APP_MIN_ADJ = 7;
+
+    // This is a process holding the home application -- we want to try
+    // avoiding killing it, even if it would normally be in the background,
+    // because the user interacts with it so much.
+    static final int HOME_APP_ADJ = 6;
+
+    // This is a process holding a secondary server -- killing it will not
+    // have much of an impact as far as the user is concerned. Value set in
+    // system/rootdir/init.rc on startup.
+    static final int SECONDARY_SERVER_ADJ = 5;
+
+    // This is a process currently hosting a backup operation.  Killing it
+    // is not entirely fatal but is generally a bad idea.
+    static final int BACKUP_APP_ADJ = 4;
+
+    // This is a process with a heavy-weight application.  It is in the
+    // background, but we want to try to avoid killing it.  Value set in
+    // system/rootdir/init.rc on startup.
+    static final int HEAVY_WEIGHT_APP_ADJ = 3;
+
+    // This is a process only hosting components that are perceptible to the
+    // user, and we really want to avoid killing them, but they are not
+    // immediately visible. An example is background music playback.  Value set in
+    // system/rootdir/init.rc on startup.
+    static final int PERCEPTIBLE_APP_ADJ = 2;
+
+    // This is a process only hosting activities that are visible to the
+    // user, so we'd prefer they don't disappear. Value set in
+    // system/rootdir/init.rc on startup.
+    static final int VISIBLE_APP_ADJ = 1;
+
+    // This is the process running the current foreground app.  We'd really
+    // rather not kill it! Value set in system/rootdir/init.rc on startup.
+    static final int FOREGROUND_APP_ADJ = 0;
+
+    // This is a process running a core server, such as telephony.  Definitely
+    // don't want to kill it, but doing so is not completely fatal.
+    static final int CORE_SERVER_ADJ = -12;
+
+    // The system process runs at the default adjustment.
+    static final int SYSTEM_ADJ = -16;
+
+    // Memory pages are 4K.
+    static final int PAGE_SIZE = 4*1024;
+
+    // The minimum number of hidden apps we want to be able to keep around,
+    // without empty apps being able to push them out of memory.
+    static final int MIN_HIDDEN_APPS = 2;
+
+    // The maximum number of hidden processes we will keep around before
+    // killing them; this is just a control to not let us go too crazy with
+    // keeping around processes on devices with large amounts of RAM.
+    static final int MAX_HIDDEN_APPS = 15;
+
+    // We put empty content processes after any hidden processes that have
+    // been idle for less than 15 seconds.
+    static final long CONTENT_APP_IDLE_OFFSET = 15*1000;
+
+    // We put empty content processes after any hidden processes that have
+    // been idle for less than 120 seconds.
+    static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
+
+    // These are the various interesting memory levels that we will give to
+    // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
+    // can't give it a different value for every possible kind of process.
+    private final int[] mOomAdj = new int[] {
+            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
+            BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, EMPTY_APP_ADJ
+    };
+    // These are the low-end OOM level limits.  This is appropriate for an
+    // HVGA or smaller phone with less than 512MB.  Values are in KB.
+    private final long[] mOomMinFreeLow = new long[] {
+            8192, 12288, 16384,
+            24576, 28672, 32768
+    };
+    // These are the high-end OOM level limits.  This is appropriate for a
+    // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
+    private final long[] mOomMinFreeHigh = new long[] {
+            32768, 40960, 49152,
+            57344, 65536, 81920
+    };
+    // The actual OOM killer memory levels we are using.
+    private final long[] mOomMinFree = new long[mOomAdj.length];
+
+    private final long mTotalMemMb;
+
+    private boolean mHaveDisplaySize;
+
+    ProcessList() {
+        MemInfoReader minfo = new MemInfoReader();
+        minfo.readMemInfo();
+        mTotalMemMb = minfo.getTotalSize()/(1024*1024);
+        updateOomLevels(0, 0, false);
+    }
+
+    void applyDisplaySize(WindowManagerService wm) {
+        if (!mHaveDisplaySize) {
+            Point p = new Point();
+            wm.getInitialDisplaySize(p);
+            if (p.x != 0 && p.y != 0) {
+                updateOomLevels(p.x, p.y, true);
+                mHaveDisplaySize = true;
+            }
+        }
+    }
+
+    private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
+        // Scale buckets from avail memory: at 300MB we use the lowest values to
+        // 700MB or more for the top values.
+        float scaleMem = ((float)(mTotalMemMb-300))/(700-300);
+
+        // Scale buckets from screen size.
+        int minSize = 320*480;  //  153600
+        int maxSize = 1280*800; // 1024000  230400 870400  .264
+        float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
+        Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth + " dh=" + displayHeight);
+
+        StringBuilder adjString = new StringBuilder();
+        StringBuilder memString = new StringBuilder();
+
+        float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
+        if (scale < 0) scale = 0;
+        else if (scale > 1) scale = 1;
+        for (int i=0; i<mOomAdj.length; i++) {
+            long low = mOomMinFreeLow[i];
+            long high = mOomMinFreeHigh[i];
+            mOomMinFree[i] = (long)(low + ((high-low)*scale));
+
+            if (i > 0) {
+                adjString.append(',');
+                memString.append(',');
+            }
+            adjString.append(mOomAdj[i]);
+            memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
+        }
+
+        //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
+        if (write) {
+            writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
+            writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
+        }
+        // GB: 2048,3072,4096,6144,7168,8192
+        // HC: 8192,10240,12288,14336,16384,20480
+    }
+
+    long getMemLevel(int adjustment) {
+        for (int i=0; i<mOomAdj.length; i++) {
+            if (adjustment <= mOomAdj[i]) {
+                return mOomMinFree[i] * 1024;
+            }
+        }
+        return mOomMinFree[mOomAdj.length-1] * 1024;
+    }
+
+    private void writeFile(String path, String data) {
+        FileOutputStream fos = null;
+        try {
+            fos = new FileOutputStream(path);
+            fos.write(data.getBytes());
+        } catch (IOException e) {
+            Slog.w(ActivityManagerService.TAG, "Unable to write " + path);
+        } finally {
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index a896ce4..24d92cf 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -270,8 +270,8 @@
         processName = _processName;
         pkgList.add(_info.packageName);
         thread = _thread;
-        maxAdj = ActivityManagerService.EMPTY_APP_ADJ;
-        hiddenAdj = ActivityManagerService.HIDDEN_APP_MIN_ADJ;
+        maxAdj = ProcessList.EMPTY_APP_ADJ;
+        hiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
         curRawAdj = setRawAdj = -100;
         curAdj = setAdj = -100;
         persistent = false;
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 36371a57..463f801 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -432,7 +432,7 @@
         PackageHandler(Looper looper) {
             super(looper);
         }
-        
+
         public void handleMessage(Message msg) {
             try {
                 doHandleMessage(msg);
@@ -490,7 +490,34 @@
                     } else if (mPendingInstalls.size() > 0) {
                         HandlerParams params = mPendingInstalls.get(0);
                         if (params != null) {
-                            params.startCopy();
+                            if (params.startCopy()) {
+                                // We are done...  look for more work or to
+                                // go idle.
+                                if (DEBUG_SD_INSTALL) Log.i(TAG,
+                                        "Checking for more work or unbind...");
+                                // Delete pending install
+                                if (mPendingInstalls.size() > 0) {
+                                    mPendingInstalls.remove(0);
+                                }
+                                if (mPendingInstalls.size() == 0) {
+                                    if (mBound) {
+                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
+                                                "Posting delayed MCS_UNBIND");
+                                        removeMessages(MCS_UNBIND);
+                                        Message ubmsg = obtainMessage(MCS_UNBIND);
+                                        // Unbind after a little delay, to avoid
+                                        // continual thrashing.
+                                        sendMessageDelayed(ubmsg, 10000);
+                                    }
+                                } else {
+                                    // There are more pending requests in queue.
+                                    // Just post MCS_BOUND message to trigger processing
+                                    // of next pending install.
+                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
+                                            "Posting MCS_BOUND for next woek");
+                                    mHandler.sendEmptyMessage(MCS_BOUND);
+                                }
+                            }
                         }
                     } else {
                         // Should never happen ideally.
@@ -517,11 +544,8 @@
                     break;
                 }
                 case MCS_UNBIND : {
+                    // If there is no actual work left, then time to unbind.
                     if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_unbind");
-                    // Delete pending install
-                    if (mPendingInstalls.size() > 0) {
-                        mPendingInstalls.remove(0);
-                    }
                     if (mPendingInstalls.size() == 0) {
                         if (mBound) {
                             disconnectService();
@@ -4814,7 +4838,8 @@
     abstract class HandlerParams {
         final static int MAX_RETRIES = 4;
         int retry = 0;
-        final void startCopy() {
+        final boolean startCopy() {
+            boolean res;
             try {
                 if (DEBUG_SD_INSTALL) Log.i(TAG, "startCopy");
                 retry++;
@@ -4822,17 +4847,18 @@
                     Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                     mHandler.sendEmptyMessage(MCS_GIVE_UP);
                     handleServiceError();
-                    return;
+                    return false;
                 } else {
                     handleStartCopy();
-                    if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_UNBIND");
-                    mHandler.sendEmptyMessage(MCS_UNBIND);
+                    res = true;
                 }
             } catch (RemoteException e) {
                 if (DEBUG_SD_INSTALL) Log.i(TAG, "Posting install MCS_RECONNECT");
                 mHandler.sendEmptyMessage(MCS_RECONNECT);
+                res = false;
             }
             handleReturnCode();
+            return res;
         }
 
         final void serviceError() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index c07531e..f80be1b 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -6664,6 +6664,13 @@
         }
     }
 
+    public void getInitialDisplaySize(Point size) {
+        synchronized(mWindowMap) {
+            size.x = mInitialDisplayWidth;
+            size.y = mInitialDisplayHeight;
+        }
+    }
+
     public int getMaximumSizeDimension() {
         synchronized(mWindowMap) {
             // Do this based on the raw screen size, until we are smarter.