diff options
author | Dianne Hackborn <hackbod@google.com> | 2012-04-10 15:25:43 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-04-10 15:25:43 -0700 |
commit | 2a854c13f864d5493846a7fc66bb6aefeaac8c8b (patch) | |
tree | ebd489d95dd9276e93a92f33af507c321c6d7a97 /services | |
parent | 4245ab34d12cf7d608f1789981326d9009cc304f (diff) | |
parent | 162bc0ea0d7862b92f18d0ce47310a85304205f7 (diff) | |
download | frameworks_base-2a854c13f864d5493846a7fc66bb6aefeaac8c8b.zip frameworks_base-2a854c13f864d5493846a7fc66bb6aefeaac8c8b.tar.gz frameworks_base-2a854c13f864d5493846a7fc66bb6aefeaac8c8b.tar.bz2 |
Merge "Some small tweaks to improve memory management."
Diffstat (limited to 'services')
3 files changed, 104 insertions, 68 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 42c42c9..78b441a 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -13444,7 +13444,7 @@ public final class ActivityManagerService extends ActivityManagerNative // an earlier hidden adjustment that isn't really for us... if // so, use the new hidden adjustment. if (!recursed && app.hidden) { - app.curAdj = app.curRawAdj = hiddenAdj; + app.curAdj = app.curRawAdj = app.nonStoppingAdj = hiddenAdj; } return app.curRawAdj; } @@ -13468,7 +13468,7 @@ public final class ActivityManagerService extends ActivityManagerNative // below foreground, so it is not worth doing work for it. app.adjType = "fixed"; app.adjSeq = mAdjSeq; - app.curRawAdj = app.maxAdj; + app.curRawAdj = app.nonStoppingAdj = app.maxAdj; app.foregroundActivities = false; app.keeping = true; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; @@ -13545,6 +13545,8 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "bg-empty"; } + boolean hasStoppingActivities = false; + // Examine all activities if not already foreground. if (!app.foregroundActivities && activitiesSize > 0) { for (int j = 0; j < activitiesSize; j++) { @@ -13559,15 +13561,20 @@ public final class ActivityManagerService extends ActivityManagerNative app.hidden = false; app.foregroundActivities = true; break; - } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED - || r.state == ActivityState.STOPPING) { - // Only upgrade adjustment. + } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) { if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; - app.adjType = "stopping"; + app.adjType = "pausing"; } app.hidden = false; app.foregroundActivities = true; + } else if (r.state == ActivityState.STOPPING) { + // We will apply the actual adjustment later, because + // we want to allow this process to immediately go through + // any memory trimming that is in effect. + app.hidden = false; + app.foregroundActivities = true; + hasStoppingActivities = true; } } } @@ -13625,7 +13632,7 @@ public final class ActivityManagerService extends ActivityManagerNative // this gives us a baseline and makes sure we don't get into an // infinite recursion. app.adjSeq = mAdjSeq; - app.curRawAdj = adj; + app.curRawAdj = app.nonStoppingAdj = adj; if (mBackupTarget != null && app == mBackupTarget.app) { // If possible we want to avoid killing apps while they're being backed up @@ -13882,6 +13889,28 @@ public final class ActivityManagerService extends ActivityManagerNative } } + if (adj == ProcessList.SERVICE_ADJ) { + if (doingAll) { + app.serviceb = mNewNumServiceProcs > (mNumServiceProcs/3); + mNewNumServiceProcs++; + } + if (app.serviceb) { + adj = ProcessList.SERVICE_B_ADJ; + } + } else { + app.serviceb = false; + } + + app.nonStoppingAdj = adj; + + if (hasStoppingActivities) { + // Only upgrade adjustment. + if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_APP_ADJ; + app.adjType = "stopping"; + } + } + app.curRawAdj = adj; //Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid + @@ -13915,18 +13944,6 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (adj == ProcessList.SERVICE_ADJ) { - if (doingAll) { - app.serviceb = mNewNumServiceProcs > (mNumServiceProcs/3); - mNewNumServiceProcs++; - } - if (app.serviceb) { - adj = ProcessList.SERVICE_B_ADJ; - } - } else { - app.serviceb = false; - } - app.curAdj = adj; app.curSchedGroup = schedGroup; @@ -14138,7 +14155,7 @@ public final class ActivityManagerService extends ActivityManagerNative } // If a process has held a wake lock for more // than 50% of the time during this period, - // that sounds pad. Kill! + // that sounds bad. Kill! if (doWakeKills && realtimeSince > 0 && ((wtimeUsed*100)/realtimeSince) >= 50) { synchronized (stats) { @@ -14186,23 +14203,6 @@ public final class ActivityManagerService extends ActivityManagerNative computeOomAdjLocked(app, hiddenAdj, TOP_APP, false, doingAll); if (app.curRawAdj != app.setRawAdj) { - if (false) { - // Removing for now. Forcing GCs is not so useful anymore - // with Dalvik, and the new memory level hint facility is - // better for what we need to do these days. - 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 >= 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); - } - } - if (wasKeeping && !app.keeping) { // This app is no longer something we want to keep. Note // its current wake lock time to later know to kill it if @@ -14319,6 +14319,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (factor < 1) factor = 1; int step = 0; int numHidden = 0; + int numTrimming = 0; // First update the OOM adjustment for each of the // application processes based on their current state. @@ -14363,6 +14364,11 @@ public final class ActivityManagerService extends ActivityManagerNative app.killedBackground = true; Process.killProcessQuiet(app.pid); } + if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ + && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ + && !app.killedBackground) { + numTrimming++; + } } } @@ -14376,7 +14382,7 @@ public final class ActivityManagerService extends ActivityManagerNative // memory they want. if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/2)) { final int N = mLruProcesses.size(); - factor = numHidden/3; + factor = numTrimming/3; int minFactor = 2; if (mHomeProcess != null) minFactor++; if (mPreviousProcess != null) minFactor++; @@ -14393,8 +14399,8 @@ public final class ActivityManagerService extends ActivityManagerNative int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; for (i=0; i<N; i++) { ProcessRecord app = mLruProcesses.get(i); - if (app.curAdj >= ProcessList.HOME_APP_ADJ - && app.curAdj != ProcessList.SERVICE_B_ADJ + if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ + && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ && !app.killedBackground) { if (app.trimMemoryLevel < curLevel && app.thread != null) { try { @@ -14426,7 +14432,7 @@ public final class ActivityManagerService extends ActivityManagerNative break; } } - } else if (app.curAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) { + } else if (app.nonStoppingAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) { if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND && app.thread != null) { try { @@ -14437,7 +14443,7 @@ public final class ActivityManagerService extends ActivityManagerNative } app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND; } else { - if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi) + if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi) && app.pendingUiClean) { // If this application is now in the background and it // had done UI, then give it the special trim level to @@ -14464,7 +14470,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 > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi) + if ((app.nonStoppingAdj > 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/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index a01ed25..6596e1f 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -97,6 +97,11 @@ final class ActivityStack { // next activity. static final int PAUSE_TIMEOUT = 500; + // How long we wait for the activity to tell us it has stopped before + // giving up. This is a good amount of time because we really need this + // from the application in order to get its saved state. + static final int STOP_TIMEOUT = 10*1000; + // How long we can hold the sleep wake lock before giving up. static final int SLEEP_TIMEOUT = 5*1000; @@ -280,6 +285,7 @@ final class ActivityStack { static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5; static final int RESUME_TOP_ACTIVITY_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6; static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7; + static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 8; final Handler mHandler = new Handler() { //public Handler() { @@ -364,6 +370,17 @@ final class ActivityStack { resumeTopActivityLocked(null); } } break; + case STOP_TIMEOUT_MSG: { + ActivityRecord r = (ActivityRecord)msg.obj; + // We don't at this point know if the activity is fullscreen, + // so we need to be conservative and assume it isn't. + Slog.w(TAG, "Activity stop timeout for " + r); + synchronized (mService) { + if (r.isInHistory()) { + activityStoppedLocked(r, null, null, null); + } + } + } break; } } }; @@ -1000,31 +1017,38 @@ final class ActivityStack { final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail, CharSequence description) { if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle); - r.icicle = icicle; - r.haveState = true; - r.updateThumbnail(thumbnail, description); - r.stopped = true; - if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)"); - r.state = ActivityState.STOPPED; - if (!r.finishing) { - if (r.configDestroy) { - destroyActivityLocked(r, true, false, "stop-config"); - resumeTopActivityLocked(null); - } else { - // Now that this process has stopped, we may want to consider - // it to be the previous app to try to keep around in case - // the user wants to return to it. - ProcessRecord fgApp = null; - if (mResumedActivity != null) { - fgApp = mResumedActivity.app; - } else if (mPausingActivity != null) { - fgApp = mPausingActivity.app; - } - if (r.app != null && fgApp != null && r.app != fgApp - && r.lastVisibleTime > mService.mPreviousProcessVisibleTime - && r.app != mService.mHomeProcess) { - mService.mPreviousProcess = r.app; - mService.mPreviousProcessVisibleTime = r.lastVisibleTime; + if (icicle != null) { + // If icicle is null, this is happening due to a timeout, so we + // haven't really saved the state. + r.icicle = icicle; + r.haveState = true; + r.updateThumbnail(thumbnail, description); + } + if (!r.stopped) { + if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)"); + mHandler.removeMessages(STOP_TIMEOUT_MSG, r); + r.stopped = true; + r.state = ActivityState.STOPPED; + if (!r.finishing) { + if (r.configDestroy) { + destroyActivityLocked(r, true, false, "stop-config"); + resumeTopActivityLocked(null); + } else { + // Now that this process has stopped, we may want to consider + // it to be the previous app to try to keep around in case + // the user wants to return to it. + ProcessRecord fgApp = null; + if (mResumedActivity != null) { + fgApp = mResumedActivity.app; + } else if (mPausingActivity != null) { + fgApp = mPausingActivity.app; + } + if (r.app != null && fgApp != null && r.app != fgApp + && r.lastVisibleTime > mService.mPreviousProcessVisibleTime + && r.app != mService.mHomeProcess) { + mService.mPreviousProcess = r.app; + mService.mPreviousProcessVisibleTime = r.lastVisibleTime; + } } } } @@ -3228,6 +3252,9 @@ final class ActivityStack { if (mService.isSleeping()) { r.setSleeping(true); } + Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG); + msg.obj = r; + mHandler.sendMessageDelayed(msg, STOP_TIMEOUT); } catch (Exception e) { // Maybe just ignore exceptions here... if the process // has crashed, our death notification will clean things @@ -3694,6 +3721,7 @@ final class ActivityStack { // Get rid of any pending idle timeouts. mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); + mHandler.removeMessages(STOP_TIMEOUT_MSG, r); mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r); r.finishLaunchTickingLocked(); diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index b64261d..4529ecc 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -63,6 +63,7 @@ class ProcessRecord { int hiddenAdj; // If hidden, this is the adjustment to use int curRawAdj; // Current OOM unlimited adjustment for this process int setRawAdj; // Last set OOM unlimited adjustment for this process + int nonStoppingAdj; // Adjustment not counting any stopping activities int curAdj; // Current OOM adjustment for this process int setAdj; // Last set OOM adjustment for this process int curSchedGroup; // Currently desired scheduling class @@ -199,6 +200,7 @@ class ProcessRecord { pw.print(" hidden="); pw.print(hiddenAdj); pw.print(" curRaw="); pw.print(curRawAdj); pw.print(" setRaw="); pw.print(setRawAdj); + pw.print(" nonStopping="); pw.print(nonStoppingAdj); pw.print(" cur="); pw.print(curAdj); pw.print(" set="); pw.println(setAdj); pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup); |