diff options
author | Dianne Hackborn <hackbod@google.com> | 2009-08-27 12:26:44 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2009-08-27 12:26:44 -0700 |
commit | 6ccd2aff3eb4450c6f1021637d18e4e5d9346bf0 (patch) | |
tree | 692dfb78939b511e815e41783036c0d7d4028063 /services | |
parent | 4d5b4225e492f3de543efa195204f38d03a6721a (diff) | |
parent | 301b97ac19caf677c481cdf86ed27b2dd80a81b3 (diff) | |
download | frameworks_base-6ccd2aff3eb4450c6f1021637d18e4e5d9346bf0.zip frameworks_base-6ccd2aff3eb4450c6f1021637d18e4e5d9346bf0.tar.gz frameworks_base-6ccd2aff3eb4450c6f1021637d18e4e5d9346bf0.tar.bz2 |
resolved conflicts for merge of 301b97ac to eclair
Change-Id: I0fb70cbe0a52006ad14f43a02c30b72aad457c48
Diffstat (limited to 'services')
4 files changed, 151 insertions, 40 deletions
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 98f35f4..95edbeb 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -19,7 +19,6 @@ package com.android.server; import com.android.server.am.ActivityManagerService; import com.android.server.status.StatusBarService; -import dalvik.system.PathClassLoader; import dalvik.system.VMRuntime; import android.app.ActivityManagerNative; @@ -42,9 +41,6 @@ import android.util.EventLog; import android.util.Log; import android.accounts.AccountManagerService; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - class ServerThread extends Thread { private static final String TAG = "SystemServer"; private final static boolean INCLUDE_DEMO = false; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 23eb7c1..0d4a4bf 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -239,6 +239,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // How long to wait after going idle before forcing apps to GC. static final int GC_TIMEOUT = 5*1000; + // The minimum amount of time between successive GC requests for a process. + static final int GC_MIN_INTERVAL = 60*1000; + // How long we wait until giving up on an activity telling us it has // finished destroying itself. static final int DESTROY_TIMEOUT = 10*1000; @@ -253,10 +256,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // is no longer considered to be a relaunch of the service. static final int SERVICE_RESTART_DURATION = 5*1000; + // How long a service needs to be running until it will start back at + // SERVICE_RESTART_DURATION after being killed. + static final int SERVICE_RESET_RUN_DURATION = 60*1000; + + // Multiplying factor to increase restart duration time by, for each time + // a service is killed before it has run for SERVICE_RESET_RUN_DURATION. + static final int SERVICE_RESTART_DURATION_FACTOR = 4; + + // The minimum amount of time between restarting services that we allow. + // That is, when multiple services are restarting, we won't allow each + // to restart less than this amount of time from the last one. + static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000; + // Maximum amount of time for there to be no activity on a service before // we consider it non-essential and allow its process to go on the // LRU background list. - static final int MAX_SERVICE_INACTIVITY = 10*60*1000; + static final int MAX_SERVICE_INACTIVITY = 30*60*1000; // How long we wait until we timeout on key dispatching. static final int KEY_DISPATCHING_TIMEOUT = 5*1000; @@ -1102,8 +1118,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } } - break; - } + } break; case SHOW_UID_ERROR_MSG: { // XXX This is a temporary dialog, no need to localize. AlertDialog d = new BaseErrorDialog(mContext); @@ -1147,7 +1162,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen synchronized (ActivityManagerService.this) { resumeTopActivityLocked(null); } - } + } break; case PROC_START_TIMEOUT_MSG: { if (mDidDexOpt) { mDidDexOpt = false; @@ -1160,12 +1175,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen synchronized (ActivityManagerService.this) { processStartTimedOutLocked(app); } - } + } break; case DO_PENDING_ACTIVITY_LAUNCHES_MSG: { synchronized (ActivityManagerService.this) { doPendingActivityLaunchesLocked(true); } - } + } break; case KILL_APPLICATION_MSG: { synchronized (ActivityManagerService.this) { int uid = msg.arg1; @@ -4443,17 +4458,26 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (!haveBg) { Log.i(TAG, "Low Memory: No more background processes."); EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size()); + long now = SystemClock.uptimeMillis(); for (i=0; i<count; i++) { ProcessRecord rec = mLRUProcesses.get(i); - if (rec.thread != null) { - rec.lastRequestedGc = SystemClock.uptimeMillis(); - try { - rec.thread.scheduleLowMemory(); - } catch (RemoteException e) { - // Don't care if the process is gone. + if (rec.thread != null && + (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) { + // The low memory report is overriding any current + // state for a GC request. Make sure to do + // visible/foreground processes first. + if (rec.setAdj <= VISIBLE_APP_ADJ) { + rec.lastRequestedGc = 0; + } else { + rec.lastRequestedGc = rec.lastLowMemory; } + rec.reportLowMemory = true; + rec.lastLowMemory = now; + mProcessesToGc.remove(rec); + addProcessToGcListLocked(rec); } } + scheduleAppGcsLocked(); } } } else if (Config.LOGD) { @@ -5137,7 +5161,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen isRestrictedBackupMode || !normalMode, mConfiguration, getCommonServicesLocked()); updateLRUListLocked(app, false); - app.lastRequestedGc = SystemClock.uptimeMillis(); + app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); } catch (Exception e) { // todo: Yikes! What should we do? For now we will try to // start another process, but that could easily get us in @@ -8949,6 +8973,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "OnHold Norm", "OnHold PERS", false); } + if (mProcessesToGc.size() > 0) { + if (needSep) pw.println(" "); + needSep = true; + pw.println(" Processes that are waiting to GC:"); + long now = SystemClock.uptimeMillis(); + for (int i=0; i<mProcessesToGc.size(); i++) { + ProcessRecord proc = mProcessesToGc.get(i); + pw.print(" Process "); pw.println(proc); + pw.print(" lowMem="); pw.print(proc.reportLowMemory); + pw.print(", last gced="); + pw.print(now-proc.lastRequestedGc); + pw.print(" ms ago, last lowMwm="); + pw.print(now-proc.lastLowMemory); + pw.println(" ms ago"); + + } + } + if (mProcessCrashTimes.getMap().size() > 0) { if (needSep) pw.println(" "); needSep = true; @@ -10112,8 +10154,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen boolean allowCancel) { boolean canceled = false; + final long now = SystemClock.uptimeMillis(); long minDuration = SERVICE_RESTART_DURATION; - long resetTime = minDuration*2*2*2; + long resetTime = SERVICE_RESET_RUN_DURATION; // Any delivered but not yet finished starts should be put back // on the pending list. @@ -10149,24 +10192,46 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // the beginning, so we don't infinitely increase the duration // on a service that just occasionally gets killed (which is // a normal case, due to process being killed to reclaim memory). - long now = SystemClock.uptimeMillis(); if (now > (r.restartTime+resetTime)) { r.restartCount = 1; r.restartDelay = minDuration; } else { - r.restartDelay *= 4; + r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR; if (r.restartDelay < minDuration) { r.restartDelay = minDuration; } } } + + r.nextRestartTime = now + r.restartDelay; + + // Make sure that we don't end up restarting a bunch of services + // all at the same time. + boolean repeat; + do { + repeat = false; + for (int i=mRestartingServices.size()-1; i>=0; i--) { + ServiceRecord r2 = mRestartingServices.get(i); + if (r2 != r && r.nextRestartTime + >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN) + && r.nextRestartTime + < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) { + r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN; + r.restartDelay = r.nextRestartTime - now; + repeat = true; + break; + } + } + } while (repeat); + if (!mRestartingServices.contains(r)) { mRestartingServices.add(r); } + r.cancelNotification(); mHandler.removeCallbacks(r.restarter); - mHandler.postDelayed(r.restarter, r.restartDelay); + mHandler.postAtTime(r.restarter, r.nextRestartTime); r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay; Log.w(TAG, "Scheduling restart of crashed service " + r.shortName + " in " + r.restartDelay + "ms"); @@ -12656,15 +12721,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (app == TOP_APP) { // The last app on the list is the foreground app. adj = FOREGROUND_APP_ADJ; - app.adjType = "top"; + app.adjType = "top-activity"; } else if (app.instrumentationClass != null) { // Don't want to kill running instrumentation. adj = FOREGROUND_APP_ADJ; - app.adjType = "instr"; + app.adjType = "instrumentation"; } else if (app.persistentActivities > 0) { // Special persistent activities... shouldn't be used these days. adj = FOREGROUND_APP_ADJ; - app.adjType = "pers"; + app.adjType = "persistent"; } else if (app.curReceiver != null || (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) { // An app that is currently receiving a broadcast also @@ -12693,6 +12758,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } else if ((N=app.activities.size()) != 0) { // This app is in the background with paused activities. adj = hiddenAdj; + app.adjType = "bg-activities"; for (int j=0; j<N; j++) { if (((HistoryRecord)app.activities.get(j)).visible) { // This app has a visible activity! @@ -12732,7 +12798,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // its services we may bump it up from there. if (adj > hiddenAdj) { adj = hiddenAdj; - app.adjType = "services"; + app.adjType = "bg-services"; } final long now = SystemClock.uptimeMillis(); // This process is more important if the top activity is @@ -12874,7 +12940,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen try { app.lastRequestedGc = SystemClock.uptimeMillis(); if (app.thread != null) { - app.thread.processInBackground(); + if (app.reportLowMemory) { + app.reportLowMemory = false; + app.thread.scheduleLowMemory(); + } else { + app.thread.processInBackground(); + } } } catch (Exception e) { // whatever. @@ -12903,14 +12974,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (canGcNow()) { while (mProcessesToGc.size() > 0) { ProcessRecord proc = mProcessesToGc.remove(0); - if (proc.curRawAdj > VISIBLE_APP_ADJ) { - // To avoid spamming the system, we will GC processes one - // at a time, waiting a few seconds between each. - performAppGcLocked(proc); - scheduleAppGcsLocked(); - return; + if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) { + if ((proc.lastRequestedGc+GC_MIN_INTERVAL) + <= SystemClock.uptimeMillis()) { + // To avoid spamming the system, we will GC processes one + // at a time, waiting a few seconds between each. + performAppGcLocked(proc); + scheduleAppGcsLocked(); + return; + } else { + // It hasn't been long enough since we last GCed this + // process... put it in the list to wait for its time. + addProcessToGcListLocked(proc); + break; + } } } + + scheduleAppGcsLocked(); } } @@ -12931,8 +13012,39 @@ public final class ActivityManagerService extends ActivityManagerNative implemen */ final void scheduleAppGcsLocked() { mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG); - Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG); - mHandler.sendMessageDelayed(msg, GC_TIMEOUT); + + if (mProcessesToGc.size() > 0) { + // Schedule a GC for the time to the next process. + ProcessRecord proc = mProcessesToGc.get(0); + Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG); + + long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL; + long now = SystemClock.uptimeMillis(); + if (when < (now+GC_TIMEOUT)) { + when = now + GC_TIMEOUT; + } + mHandler.sendMessageAtTime(msg, when); + } + } + + /** + * Add a process to the array of processes waiting to be GCed. Keeps the + * list in sorted order by the last GC time. The process can't already be + * on the list. + */ + final void addProcessToGcListLocked(ProcessRecord proc) { + boolean added = false; + for (int i=mProcessesToGc.size()-1; i>=0; i--) { + if (mProcessesToGc.get(i).lastRequestedGc < + proc.lastRequestedGc) { + added = true; + mProcessesToGc.add(i+1, proc); + break; + } + } + if (!added) { + mProcessesToGc.add(0, proc); + } } /** @@ -12942,11 +13054,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen */ final void scheduleAppGcLocked(ProcessRecord app) { long now = SystemClock.uptimeMillis(); - if ((app.lastRequestedGc+5000) > now) { + if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) { return; } if (!mProcessesToGc.contains(app)) { - mProcessesToGc.add(app); + addProcessToGcListLocked(app); scheduleAppGcsLocked(); } } diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 544d034..76fdf09 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -71,6 +71,8 @@ class ProcessRecord implements Watchdog.PssRequestor { ComponentName instrumentationResultClass;// copy of instrumentationClass BroadcastRecord curReceiver;// receiver currently running in the app long lastRequestedGc; // When we last asked the app to do a gc + long lastLowMemory; // When we last told the app that memory is low + boolean reportLowMemory; // Set to true when waiting to report low mem int lastPss; // Last pss size reported by app. String adjType; // Debugging: primary thing impacting oom_adj. Object adjSource; // Debugging: option dependent object. diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index afbf9c7..2534410 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -136,6 +136,7 @@ class ServiceRecord extends Binder { if (permission != null) { pw.print(prefix); pw.print("permission="); pw.println(permission); } + long now = SystemClock.uptimeMillis(); pw.print(prefix); pw.print("baseDir="); pw.print(baseDir); if (!resDir.equals(baseDir)) pw.print(" resDir="); pw.print(resDir); pw.print(" dataDir="); pw.println(dataDir); @@ -145,8 +146,8 @@ class ServiceRecord extends Binder { pw.print(" foregroundId="); pw.print(foregroundId); pw.print(" foregroundNoti="); pw.println(foregroundNoti); } - pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity); - pw.print(" executingStart="); pw.print(executingStart); + pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity-now); + pw.print(" executingStart="); pw.print(executingStart-now); pw.print(" restartTime="); pw.println(restartTime); if (startRequested || lastStartId != 0) { pw.print(prefix); pw.print("startRequested="); pw.print(startRequested); @@ -158,8 +159,8 @@ class ServiceRecord extends Binder { || restartDelay != 0 || nextRestartTime != 0) { pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting); pw.print(" restartCount="); pw.print(restartCount); - pw.print(" restartDelay="); pw.print(restartDelay); - pw.print(" nextRestartTime="); pw.print(nextRestartTime); + pw.print(" restartDelay="); pw.print(restartDelay-now); + pw.print(" nextRestartTime="); pw.print(nextRestartTime-now); pw.print(" crashCount="); pw.println(crashCount); } if (deliveredStarts.size() > 0) { |