diff options
Diffstat (limited to 'services/java/com/android/server/am/ActivityManagerService.java')
| -rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 255 |
1 files changed, 155 insertions, 100 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index f08b5b9..7a480dc 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -499,6 +499,11 @@ public final class ActivityManagerService extends ActivityManagerNative final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>(); /** + * Where in mLruProcesses that the processes hosting activities start. + */ + int mLruProcessActivityStart = 0; + + /** * List of processes that should gc as soon as things are idle. */ final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>(); @@ -1638,7 +1643,7 @@ public final class ActivityManagerService extends ActivityManagerNative int pid; synchronized (ActivityManagerService.this) { if (i >= mPendingPssProcesses.size()) { - if (DEBUG_PSS) Slog.i(TAG, "Collected PSS of " + num + " of " + i + if (DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num + " of " + i + " processes in " + (SystemClock.uptimeMillis()-start) + "ms"); mPendingPssProcesses.clear(); return; @@ -1661,10 +1666,16 @@ public final class ActivityManagerService extends ActivityManagerNative num++; proc.lastPssTime = SystemClock.uptimeMillis(); proc.baseProcessTracker.addPss(pss, tmp[0], true); + if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString() + + ": " + pss + " lastPss=" + proc.lastPss + + " state=" + ProcessList.makeProcStateString(procState)); if (proc.initialIdlePss == 0) { proc.initialIdlePss = pss; } proc.lastPss = pss; + if (procState >= ActivityManager.PROCESS_STATE_HOME) { + proc.lastCachedPss = pss; + } } } } @@ -1704,7 +1715,7 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (mSelf.mPidsSelfLocked) { mSelf.mPidsSelfLocked.put(app.pid, app); } - mSelf.updateLruProcessLocked(app, true); + mSelf.updateLruProcessLocked(app, true, false); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( @@ -2219,52 +2230,76 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.sendMessage(msg); } - private final void updateLruProcessInternalLocked(ProcessRecord app, int bestPos) { - // put it on the LRU to keep track of when it should be exited. - int lrui = mLruProcesses.indexOf(app); - if (lrui >= 0) mLruProcesses.remove(lrui); + private final int updateLruProcessInternalLocked(ProcessRecord app, long now, int index) { + app.lastActivityTime = now; - int i = mLruProcesses.size()-1; - int skipTop = 0; + if (app.activities.size() > 0) { + // Don't want to touch dependent processes that are hosting activities. + return index; + } - app.lruSeq = mLruSeq; + int lrui = mLruProcesses.lastIndexOf(app); + if (lrui < 0) { + throw new IllegalStateException("Adding dependent process " + app + + " not on LRU list!"); + } - // compute the new weight for this process. - app.lastActivityTime = SystemClock.uptimeMillis(); - if (app.activities.size() > 0) { - // If this process has activities, we more strongly want to keep - // it around. - app.lruWeight = app.lastActivityTime; - } 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 - ProcessList.CONTENT_APP_IDLE_OFFSET; - // Also don't let it kick out the first few "real" cached processes. - skipTop = ProcessList.MIN_CACHED_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 - ProcessList.EMPTY_APP_IDLE_OFFSET; - // Also don't let it kick out the first few "real" cached processes. - skipTop = ProcessList.MIN_CACHED_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 cached. - if (skipTop > 0 && p.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) { - skipTop--; - } - if (p.lruWeight <= app.lruWeight || i < bestPos) { - mLruProcesses.add(i+1, app); - break; + if (lrui >= mLruProcessActivityStart) { + // Don't want to touch dependent processes that are hosting activities. + return index; + } + + mLruProcesses.remove(lrui); + if (index > 0) { + index--; + } + mLruProcesses.add(index, app); + return index; + } + + final void removeLruProcessLocked(ProcessRecord app) { + int lrui = mLruProcesses.lastIndexOf(app); + if (lrui >= 0) { + if (lrui <= mLruProcessActivityStart) { + mLruProcessActivityStart--; } - i--; + mLruProcesses.remove(lrui); + } + } + + final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj, boolean activityChange) { + final boolean hasActivity = app.activities.size() > 0; + if (!activityChange && hasActivity) { + // The process has activties, so we are only going to allow activity-based + // adjustments move it. It should be kept in the front of the list with other + // processes that have activities, and we don't want those to change their + // order except due to activity operations. + return; + } + + mLruSeq++; + final long now = SystemClock.uptimeMillis(); + app.lastActivityTime = now; + + int lrui = mLruProcesses.lastIndexOf(app); + + if (lrui >= 0) { + if (lrui < mLruProcessActivityStart) { + mLruProcessActivityStart--; + } + mLruProcesses.remove(lrui); } - if (i < 0) { - mLruProcesses.add(0, app); + + int nextIndex; + if (!hasActivity) { + // Process doesn't have activities, it goes to the top of the non-activity area. + mLruProcesses.add(mLruProcessActivityStart, app); + nextIndex = mLruProcessActivityStart-1; + mLruProcessActivityStart++; + } else { + // Process does have activities, put it at the very tipsy-top. + mLruProcesses.add(app); + nextIndex = mLruProcessActivityStart; } // If the app is currently using a content provider or service, @@ -2274,20 +2309,15 @@ public final class ActivityManagerService extends ActivityManagerNative if (cr.binding != null && cr.binding.service != null && cr.binding.service.app != null && cr.binding.service.app.lruSeq != mLruSeq) { - updateLruProcessInternalLocked(cr.binding.service.app, i+1); + nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex); } } for (int j=app.conProviders.size()-1; j>=0; j--) { ContentProviderRecord cpr = app.conProviders.get(j).provider; if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) { - updateLruProcessInternalLocked(cpr.proc, i+1); + nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex); } } - } - - final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj) { - mLruSeq++; - updateLruProcessInternalLocked(app, 0); //Slog.i(TAG, "Putting proc to front: " + app.processName); if (oomAdj) { @@ -2295,14 +2325,12 @@ public final class ActivityManagerService extends ActivityManagerNative } } - final ProcessRecord getProcessRecordLocked( - String processName, int uid) { + final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) { if (uid == Process.SYSTEM_UID) { // The system gets to run in any process. If there are multiple // processes with the same uid, just pick the first (this // should never happen). - SparseArray<ProcessRecord> procs = mProcessNames.getMap().get( - processName); + SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName); if (procs == null) return null; final int N = procs.size(); for (int i = 0; i < N; i++) { @@ -2310,6 +2338,26 @@ public final class ActivityManagerService extends ActivityManagerNative } } ProcessRecord proc = mProcessNames.get(processName, uid); + if (false && proc != null && !keepIfLarge + && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY + && proc.lastCachedPss >= 4000) { + // Turn this condition on to cause killing to happen regularly, for testing. + if (proc.baseProcessTracker != null) { + proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss); + } + killUnneededProcessLocked(proc, Long.toString(proc.lastCachedPss) + + "k from cached"); + } else if (proc != null && !keepIfLarge && mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL + && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) { + if (DEBUG_PSS) Slog.d(TAG, "May not keep " + proc + ": pss=" + proc.lastCachedPss); + if (proc.lastCachedPss >= mProcessList.getCachedRestoreThreshold()) { + if (proc.baseProcessTracker != null) { + proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss); + } + killUnneededProcessLocked(proc, Long.toString(proc.lastCachedPss) + + "k from cached"); + } + } return proc; } @@ -2333,10 +2381,10 @@ public final class ActivityManagerService extends ActivityManagerNative final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, - boolean isolated) { + boolean isolated, boolean keepIfLarge) { ProcessRecord app; if (!isolated) { - app = getProcessRecordLocked(processName, info.uid); + app = getProcessRecordLocked(processName, info.uid, keepIfLarge); } else { // If this is an isolated process, it can't re-use an existing process. app = null; @@ -2647,7 +2695,7 @@ public final class ActivityManagerService extends ActivityManagerNative aInfo = new ActivityInfo(aInfo); aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId); ProcessRecord app = getProcessRecordLocked(aInfo.processName, - aInfo.applicationInfo.uid); + aInfo.applicationInfo.uid, true); if (app == null || app.instrumentationClass == null) { intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); mStackSupervisor.startHomeActivity(intent, aInfo); @@ -3364,7 +3412,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean restarting, boolean allowRestart) { cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1); if (!restarting) { - mLruProcesses.remove(app); + removeLruProcessLocked(app); } if (mProfileProc == app) { @@ -4212,7 +4260,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Only the system server can kill an application if (callerUid == Process.SYSTEM_UID) { synchronized (this) { - ProcessRecord app = getProcessRecordLocked(processName, uid); + ProcessRecord app = getProcessRecordLocked(processName, uid, true); if (app != null && app.thread != null) { try { app.thread.scheduleSuicide(); @@ -4517,7 +4565,7 @@ public final class ActivityManagerService extends ActivityManagerNative } killUnneededProcessLocked(app, reason); handleAppDiedLocked(app, true, allowRestart); - mLruProcesses.remove(app); + removeLruProcessLocked(app); if (app.persistent && !app.isolated) { if (!callerWillRestart) { @@ -4712,7 +4760,7 @@ public final class ActivityManagerService extends ActivityManagerNative isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(mConfiguration), app.compat, getCommonServicesLocked(), mCoreSettingsObserver.getCoreSettingsLocked()); - updateLruProcessLocked(app, false); + updateLruProcessLocked(app, false, false); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); } catch (Exception e) { // todo: Yikes! What should we do? For now we will try to @@ -7175,7 +7223,7 @@ public final class ActivityManagerService extends ActivityManagerNative // make sure to count it as being accessed and thus // back up on the LRU list. This is good because // content providers are often expensive to start. - updateLruProcessLocked(cpr.proc, false); + updateLruProcessLocked(cpr.proc, false, false); } } @@ -7325,7 +7373,7 @@ public final class ActivityManagerService extends ActivityManagerNative ProcessRecord proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, - cpi.name), false, false); + cpi.name), false, false, false); if (proc == null) { Slog.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" @@ -7734,7 +7782,7 @@ public final class ActivityManagerService extends ActivityManagerNative final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) { ProcessRecord app; if (!isolated) { - app = getProcessRecordLocked(info.processName, info.uid); + app = getProcessRecordLocked(info.processName, info.uid, true); } else { app = null; } @@ -7745,7 +7793,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (isolated) { mIsolatedProcesses.put(app.uid, app); } - updateLruProcessLocked(app, true); + updateLruProcessLocked(app, true, false); } // This package really, really can not be stopped. @@ -8613,6 +8661,8 @@ public final class ActivityManagerService extends ActivityManagerNative } else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME) { proc.notCachedSinceIdle = true; proc.initialIdlePss = 0; + proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true, + mSleeping, now); } } @@ -10230,13 +10280,16 @@ public final class ActivityManagerService extends ActivityManagerNative } if (mLruProcesses.size() > 0) { - boolean printed = dumpProcessOomList(pw, this, mLruProcesses, " ", - "Proc", "PERS", false, dumpPackage, needSep, - " Process LRU list (sorted by oom_adj):"); - if (printed) { - needSep = true; - printedAnything = true; + if (needSep) { + pw.println(); } + pw.print(" Process LRU list (sorted by oom_adj, "); pw.print(mLruProcesses.size()); + pw.print(" total, non-activities at "); + pw.print(mLruProcesses.size()-mLruProcessActivityStart); + pw.println("):"); + dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", false, dumpPackage); + needSep = true; + printedAnything = true; } if (dumpAll || dumpPackage != null) { @@ -10607,14 +10660,15 @@ public final class ActivityManagerService extends ActivityManagerNative printOomLevel(pw, "CACHED_APP_MAX_ADJ", ProcessList.CACHED_APP_MAX_ADJ); if (needSep) pw.println(); - needSep = true; - pw.println(" Process OOM control:"); - dumpProcessOomList(pw, this, mLruProcesses, " ", - "Proc", "PERS", true, null, false, null); + pw.print(" Process OOM control ("); pw.print(mLruProcesses.size()); + pw.print(" total, non-activities at "); + pw.print(mLruProcesses.size()-mLruProcessActivityStart); + pw.println("):"); + dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", true, null); needSep = true; } - needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, null); + dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, null); pw.println(); pw.println(" mHomeProcess: " + mHomeProcess); @@ -11034,7 +11088,7 @@ public final class ActivityManagerService extends ActivityManagerNative private static final boolean dumpProcessOomList(PrintWriter pw, ActivityManagerService service, List<ProcessRecord> origList, String prefix, String normalLabel, String persistentLabel, - boolean inclDetails, String dumpPackage, boolean needSep, String header) { + boolean inclDetails, String dumpPackage) { ArrayList<Pair<ProcessRecord, Integer>> list = new ArrayList<Pair<ProcessRecord, Integer>>(origList.size()); @@ -11050,13 +11104,6 @@ public final class ActivityManagerService extends ActivityManagerNative return false; } - if (header != null) { - if (needSep) { - pw.println(); - } - pw.println(header); - } - Comparator<Pair<ProcessRecord, Integer>> comparator = new Comparator<Pair<ProcessRecord, Integer>>() { @Override @@ -11156,6 +11203,12 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(" set="); pw.println(r.setAdj); pw.print(prefix); pw.print(" "); + pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState)); + pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState)); + pw.print(" lastPss="); pw.print(r.lastPss); + pw.print(" lastCachedPss="); pw.println(r.lastCachedPss); + pw.print(prefix); + pw.print(" "); pw.print("keeping="); pw.print(r.keeping); pw.print(" cached="); pw.print(r.cached); pw.print(" empty="); pw.print(r.empty); @@ -11505,27 +11558,25 @@ public final class ActivityManagerService extends ActivityManagerNative if (!isCheckinRequest && dumpDetails) { pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **"); } + if (mi == null) { + mi = new Debug.MemoryInfo(); + } + if (dumpDetails || (!brief && !oomOnly)) { + Debug.getMemoryInfo(pid, mi); + } else { + mi.dalvikPss = (int)Debug.getPss(pid, tmpLong); + mi.dalvikPrivateDirty = (int)tmpLong[0]; + } if (dumpDetails) { try { pw.flush(); - mi = null; - mi = thread.dumpMemInfo(fd, isCheckinRequest, true, dumpDalvik, innerArgs); + thread.dumpMemInfo(fd, mi, isCheckinRequest, true, dumpDalvik, innerArgs); } catch (RemoteException e) { if (!isCheckinRequest) { pw.println("Got RemoteException!"); pw.flush(); } } - } else { - if (mi == null) { - mi = new Debug.MemoryInfo(); - } - if (!brief && !oomOnly) { - Debug.getMemoryInfo(pid, mi); - } else { - mi.dalvikPss = (int)Debug.getPss(pid, tmpLong); - mi.dalvikPrivateDirty = (int)tmpLong[0]; - } } final long myTotalPss = mi.getTotalPss(); @@ -11821,7 +11872,7 @@ public final class ActivityManagerService extends ActivityManagerNative private final void cleanUpApplicationRecordLocked(ProcessRecord app, boolean restarting, boolean allowRestart, int index) { if (index >= 0) { - mLruProcesses.remove(index); + removeLruProcessLocked(app); } mProcessesToGc.remove(app); @@ -12278,7 +12329,7 @@ public final class ActivityManagerService extends ActivityManagerNative : new ComponentName("android", "FullBackupAgent"); // startProcessLocked() returns existing proc's record if it's already running ProcessRecord proc = startProcessLocked(app.processName, app, - false, 0, "backup", hostingName, false, false); + false, 0, "backup", hostingName, false, false, false); if (proc == null) { Slog.e(TAG, "Unable to start backup agent process " + r); return false; @@ -14711,17 +14762,21 @@ public final class ActivityManagerService extends ActivityManagerNative } if (app.setProcState < 0 || ProcessList.procStatesDifferForMem(app.curProcState, app.setProcState)) { - if (DEBUG_PSS) Slog.d(TAG, "Process state change from " + app.setProcState - + " to " + app.curProcState + ": " + app); app.lastStateTime = now; app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true, mSleeping, now); + if (DEBUG_PSS) Slog.d(TAG, "Process state change from " + + ProcessList.makeProcStateString(app.setProcState) + " to " + + ProcessList.makeProcStateString(app.curProcState) + " next pss in " + + (app.nextPssTime-now) + ": " + app); } else { if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL) && now > (app.lastStateTime+ProcessList.PSS_MIN_TIME_FROM_STATE_CHANGE))) { requestPssLocked(app, app.setProcState); app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false, mSleeping, now); + } else if (false && DEBUG_PSS) { + Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now)); } } if (app.setProcState != app.curProcState) { |
