diff options
7 files changed, 550 insertions, 278 deletions
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 class ActivityManager { */ 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 @@ public class ActivityManager { 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative */ boolean mBooted = false; - int mProcessLimit = MAX_HIDDEN_APPS; + int mProcessLimit = ProcessList.MAX_HIDDEN_APPS; int mProcessLimitOverride = -1; WindowManagerService mWindowManager; @@ -1327,7 +1206,7 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative } } - 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative } } - 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 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative // " 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative } } 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 @@ public final class ActivityManagerService extends ActivityManagerNative } else { numBg++; } - } else if (app.curAdj >= HOME_APP_ADJ) { + } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) { numBg++; } } @@ -13536,14 +13427,14 @@ public final class ActivityManagerService extends ActivityManagerNative // 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } } 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 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ class ProcessRecord { 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 36371a5..463f801 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -432,7 +432,7 @@ public class PackageManagerService extends IPackageManager.Stub { PackageHandler(Looper looper) { super(looper); } - + public void handleMessage(Message msg) { try { doHandleMessage(msg); @@ -490,7 +490,34 @@ public class PackageManagerService extends IPackageManager.Stub { } 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 class WindowManagerService extends IWindowManager.Stub } } + 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. |