diff options
Diffstat (limited to 'services/java/com')
8 files changed, 297 insertions, 210 deletions
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index 98b5f66..bb6c4e6 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -470,7 +470,8 @@ class AlarmManagerService extends IAlarmManager.Stub { mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0, new Intent(Intent.ACTION_TIME_TICK).addFlags( - Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0, + Intent.FLAG_RECEIVER_REGISTERED_ONLY + | Intent.FLAG_RECEIVER_FOREGROUND), 0, UserHandle.ALL); Intent intent = new Intent(Intent.ACTION_DATE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index fea7623..4379c70 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -311,7 +311,7 @@ public final class ActiveServices { final ServiceMap smap = getServiceMap(r.userId); boolean addToStarting = false; if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) { - ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid); + ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false); if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) { // If this is not coming from a foreground caller, then we may want // to delay the start if there are already other background services @@ -562,7 +562,7 @@ public final class ActiveServices { if (r.isForeground) { r.isForeground = false; if (r.app != null) { - mAm.updateLruProcessLocked(r.app, false); + mAm.updateLruProcessLocked(r.app, false, false); updateServiceForegroundLocked(r.app, true); } } @@ -1241,9 +1241,9 @@ public final class ActiveServices { ProcessRecord app; if (!isolated) { - app = mAm.getProcessRecordLocked(procName, r.appInfo.uid); - if (DEBUG_MU) - Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app); + app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); + if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + + " app=" + app); if (app != null && app.thread != null) { try { app.addPackage(r.appInfo.packageName, mAm.mProcessStats); @@ -1270,7 +1270,7 @@ public final class ActiveServices { // to be executed when the app comes up. if (app == null) { if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, - "service", r.name, false, isolated)) == null) { + "service", r.name, false, isolated, false)) == null) { String msg = "Unable to launch app " + r.appInfo.packageName + "/" + r.appInfo.uid + " for service " @@ -1322,7 +1322,7 @@ public final class ActiveServices { app.services.add(r); bumpServiceExecutingLocked(r, execInFg, "create"); - mAm.updateLruProcessLocked(app, true); + mAm.updateLruProcessLocked(app, true, false); boolean created = false; try { 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) { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index d22a9f2..3bdd01a 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -69,7 +69,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -1342,7 +1341,7 @@ final class ActivityStack { if (next.app != null && next.app.thread != null) { // No reason to do full oom adj update here; we'll let that // happen whenever it needs to later. - mService.updateLruProcessLocked(next.app, false); + mService.updateLruProcessLocked(next.app, false, true); } if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; @@ -1470,7 +1469,7 @@ final class ActivityStack { mResumedActivity = next; next.task.touchActiveTime(); mService.addRecentTaskLocked(next.task); - mService.updateLruProcessLocked(next.app, true); + mService.updateLruProcessLocked(next.app, true, true); updateLRUListLocked(next); // Have the window manager re-evaluate the orientation of @@ -2707,7 +2706,8 @@ final class ActivityStack { ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG); } if (r.app.activities.isEmpty()) { - // No longer have activities, so update oom adj. + // No longer have activities, so update LRU list and oom adj. + mService.updateLruProcessLocked(r.app, false, false); mService.updateOomAdjLocked(); } } diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java index 9b1db7f..6ff5dcb 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -912,7 +912,7 @@ public final class ActivityStackSupervisor { if (idx < 0) { app.activities.add(r); } - mService.updateLruProcessLocked(app, true); + mService.updateLruProcessLocked(app, true, true); final ActivityStack stack = r.task.stack; try { @@ -1052,7 +1052,7 @@ public final class ActivityStackSupervisor { boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app = mService.getProcessRecordLocked(r.processName, - r.info.applicationInfo.uid); + r.info.applicationInfo.uid, true); r.task.stack.setLaunchTime(r); @@ -1071,7 +1071,7 @@ public final class ActivityStackSupervisor { } mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, - "activity", r.intent.getComponent(), false, false); + "activity", r.intent.getComponent(), false, false, true); } final int startActivityLocked(IApplicationThread caller, diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index b35ca79..b2e3ce7 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -220,7 +220,7 @@ public final class BroadcastQueue { r.curApp = app; app.curReceiver = r; app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); - mService.updateLruProcessLocked(app, true); + mService.updateLruProcessLocked(app, true, false); // Tell the application to launch this receiver. r.intent.setComponent(r.curComponent); @@ -334,6 +334,7 @@ public final class BroadcastQueue { public boolean finishReceiverLocked(BroadcastRecord r, int resultCode, String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) { final int state = r.state; + final ActivityInfo receiver = r.curReceiver; r.state = BroadcastRecord.IDLE; if (state == BroadcastRecord.IDLE) { Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE"); @@ -363,15 +364,27 @@ public final class BroadcastQueue { if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices && r.queue.mOrderedBroadcasts.size() > 0 && r.queue.mOrderedBroadcasts.get(0) == r) { - // In this case, we are ready to process the next receiver for the current broadcast, - // but are on a queue that would like to wait for services to finish before moving - // on. If there are background services currently starting, then we will go into a - // special state where we hold off on continuing this broadcast until they are done. - if (mService.mServices.hasBackgroundServices(r.userId)) { - Slog.i(ActivityManagerService.TAG, "Delay finish: " - + r.curComponent.flattenToShortString()); - r.state = BroadcastRecord.WAITING_SERVICES; - return false; + ActivityInfo nextReceiver; + if (r.nextReceiver < r.receivers.size()) { + Object obj = r.receivers.get(r.nextReceiver); + nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null; + } else { + nextReceiver = null; + } + // Don't do this if the next receive is in the same process as the current one. + if (receiver == null || nextReceiver == null + || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid + || !receiver.processName.equals(nextReceiver.processName)) { + // In this case, we are ready to process the next receiver for the current broadcast, + // but are on a queue that would like to wait for services to finish before moving + // on. If there are background services currently starting, then we will go into a + // special state where we hold off on continuing this broadcast until they are done. + if (mService.mServices.hasBackgroundServices(r.userId)) { + Slog.i(ActivityManagerService.TAG, "Delay finish: " + + r.curComponent.flattenToShortString()); + r.state = BroadcastRecord.WAITING_SERVICES; + return false; + } } } @@ -833,7 +846,7 @@ public final class BroadcastQueue { // Is this receiver's application already running? ProcessRecord app = mService.getProcessRecordLocked(targetProcess, - info.activityInfo.applicationInfo.uid); + info.activityInfo.applicationInfo.uid, false); if (app != null && app.thread != null) { try { app.addPackage(info.activityInfo.packageName, mService.mProcessStats); @@ -871,7 +884,7 @@ public final class BroadcastQueue { info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, "broadcast", r.curComponent, - (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false)) + (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) { // Ah, this recipient is unavailable. Finish it if necessary, // and mark the broadcast record as ready for the next. diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java index 54593aa..ef7f523 100644 --- a/services/java/com/android/server/am/ProcessList.java +++ b/services/java/com/android/server/am/ProcessList.java @@ -173,6 +173,8 @@ final class ProcessList { private final long mTotalMemMb; + private long mCachedRestoreLevel; + private boolean mHaveDisplaySize; ProcessList() { @@ -243,6 +245,11 @@ final class ProcessList { } } + // The maximum size we will restore a process from cached to background, when under + // memory duress, is 1/3 the size we have reserved for kernel caches and other overhead + // before killing background processes. + mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3; + for (int i=0; i<mOomAdj.length; i++) { if (i > 0) { adjString.append(','); @@ -323,6 +330,70 @@ final class ProcessList { } } + public static String makeProcStateString(int curProcState) { + String procState; + switch (curProcState) { + case -1: + procState = "N "; + break; + case ActivityManager.PROCESS_STATE_PERSISTENT: + procState = "P "; + break; + case ActivityManager.PROCESS_STATE_PERSISTENT_UI: + procState = "PU"; + break; + case ActivityManager.PROCESS_STATE_TOP: + procState = "T "; + break; + case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND: + procState = "IF"; + break; + case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND: + procState = "IB"; + break; + case ActivityManager.PROCESS_STATE_BACKUP: + procState = "BU"; + break; + case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT: + procState = "HW"; + break; + case ActivityManager.PROCESS_STATE_SERVICE: + procState = "S "; + break; + case ActivityManager.PROCESS_STATE_RECEIVER: + procState = "R "; + break; + case ActivityManager.PROCESS_STATE_HOME: + procState = "HO"; + break; + case ActivityManager.PROCESS_STATE_LAST_ACTIVITY: + procState = "LA"; + break; + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: + procState = "CA"; + break; + case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: + procState = "Ca"; + break; + case ActivityManager.PROCESS_STATE_CACHED_EMPTY: + procState = "CE"; + break; + default: + procState = "??"; + break; + } + return procState; + } + + public static void appendRamKb(StringBuilder sb, long ramKb) { + for (int j=0, fact=10; j<6; j++, fact*=10) { + if (ramKb < fact) { + sb.append(' '); + } + } + sb.append(ramKb); + } + // The minimum amount of time after a state change it is safe ro collect PSS. public static final int PSS_MIN_TIME_FROM_STATE_CHANGE = 15*1000; @@ -336,10 +407,13 @@ final class ProcessList { private static final int PSS_SHORT_INTERVAL = 2*60*1000; // The amount of time until PSS when a process first becomes top. - private static final int PSS_FIRST_TOP_INTERVAL = 15*1000; + private static final int PSS_FIRST_TOP_INTERVAL = 10*1000; + + // The amount of time until PSS when a process first goes into the background. + private static final int PSS_FIRST_BACKGROUND_INTERVAL = 20*1000; // The amount of time until PSS when a process first becomes cached. - private static final int PSS_FIRST_CACHED_INTERVAL = 5*60*1000; + private static final int PSS_FIRST_CACHED_INTERVAL = 30*1000; // The amount of time until PSS when an important process stays in the same state. private static final int PSS_SAME_IMPORTANT_INTERVAL = 15*60*1000; @@ -377,12 +451,12 @@ final class ProcessList { PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_PERSISTENT PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_PERSISTENT_UI PSS_FIRST_TOP_INTERVAL, // ActivityManager.PROCESS_STATE_TOP - PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND - PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND - PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP - PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT - PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE - PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_RECEIVER + PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND + PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND + PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP + PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT + PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE + PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_RECEIVER PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_HOME PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY @@ -411,70 +485,6 @@ final class ProcessList { return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2]; } - public static String makeProcStateString(int curProcState) { - String procState; - switch (curProcState) { - case -1: - procState = "N "; - break; - case ActivityManager.PROCESS_STATE_PERSISTENT: - procState = "P "; - break; - case ActivityManager.PROCESS_STATE_PERSISTENT_UI: - procState = "PU"; - break; - case ActivityManager.PROCESS_STATE_TOP: - procState = "T "; - break; - case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND: - procState = "IF"; - break; - case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND: - procState = "IB"; - break; - case ActivityManager.PROCESS_STATE_BACKUP: - procState = "BU"; - break; - case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT: - procState = "HW"; - break; - case ActivityManager.PROCESS_STATE_SERVICE: - procState = "S "; - break; - case ActivityManager.PROCESS_STATE_RECEIVER: - procState = "R "; - break; - case ActivityManager.PROCESS_STATE_HOME: - procState = "HO"; - break; - case ActivityManager.PROCESS_STATE_LAST_ACTIVITY: - procState = "LA"; - break; - case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: - procState = "CA"; - break; - case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: - procState = "Ca"; - break; - case ActivityManager.PROCESS_STATE_CACHED_EMPTY: - procState = "CE"; - break; - default: - procState = "??"; - break; - } - return procState; - } - - public static void appendRamKb(StringBuilder sb, long ramKb) { - for (int j=0, fact=10; j<6; j++, fact*=10) { - if (ramKb < fact) { - sb.append(' '); - } - } - sb.append(ramKb); - } - public static long computeNextPssTime(int procState, boolean first, boolean sleeping, long now) { final long[] table = sleeping @@ -496,6 +506,14 @@ final class ProcessList { return mOomMinFree[mOomAdj.length-1] * 1024; } + /** + * Return the maximum pss size in kb that we consider a process acceptable to + * restore from its cached state for running in the background when RAM is low. + */ + long getCachedRestoreThreshold() { + return mCachedRestoreLevel; + } + private void writeFile(String path, String data) { FileOutputStream fos = null; try { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 7a456f7..c5491ef 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -62,12 +62,12 @@ final class ProcessRecord { int pid; // The process of this application; 0 if none boolean starting; // True if the process is being started long lastActivityTime; // For managing the LRU list - long lruWeight; // Weight for ordering in LRU list long lastPssTime; // Last time we retrieved PSS data long nextPssTime; // Next time we want to request PSS data long lastStateTime; // Last time setProcState changed long initialIdlePss; // Initial memory pss of process for idle maintenance. long lastPss; // Last computed memory pss. + long lastCachedPss; // Last computed pss when in cached state. int maxAdj; // Maximum OOM adjustment for this process int curRawAdj; // Current OOM unlimited adjustment for this process int setRawAdj; // Last set OOM unlimited adjustment for this process @@ -214,15 +214,22 @@ final class ProcessRecord { pw.println(starting); pw.print(prefix); pw.print("lastActivityTime="); TimeUtils.formatDuration(lastActivityTime, now, pw); - pw.print(" lruWeight="); pw.println(lruWeight); + pw.print(" lastPssTime="); + TimeUtils.formatDuration(lastPssTime, now, pw); + pw.print(" nextPssTime="); + TimeUtils.formatDuration(nextPssTime, now, pw); + pw.println(); + pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); + pw.print(" lruSeq="); pw.print(lruSeq); + pw.print(" lastPss="); pw.print(lastPss); + pw.print(" lastCachedPss="); pw.println(lastCachedPss); pw.print(prefix); pw.print("serviceb="); pw.print(serviceb); pw.print(" keeping="); pw.print(keeping); pw.print(" cached="); pw.print(cached); pw.print(" empty="); pw.println(empty); if (notCachedSinceIdle) { pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle); - pw.print(" initialIdlePss="); pw.print(initialIdlePss); - pw.print(" lastPss="); pw.println(lastPss); + pw.print(" initialIdlePss="); pw.println(initialIdlePss); } pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj); pw.print(" curRaw="); pw.print(curRawAdj); @@ -240,13 +247,6 @@ final class ProcessRecord { pw.print(" lastStateTime="); TimeUtils.formatDuration(lastStateTime, now, pw); pw.println(); - pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq); - pw.print(" lruSeq="); pw.print(lruSeq); - pw.print(" lastPssTime="); - TimeUtils.formatDuration(lastPssTime, now, pw); - pw.print(" nextPssTime="); - TimeUtils.formatDuration(nextPssTime, now, pw); - pw.println(); if (hasShownUi || pendingUiClean || hasAboveClient) { pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi); pw.print(" pendingUiClean="); pw.print(pendingUiClean); |
