summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2009-08-27 12:26:44 -0700
committerDianne Hackborn <hackbod@google.com>2009-08-27 12:26:44 -0700
commit6ccd2aff3eb4450c6f1021637d18e4e5d9346bf0 (patch)
tree692dfb78939b511e815e41783036c0d7d4028063 /services
parent4d5b4225e492f3de543efa195204f38d03a6721a (diff)
parent301b97ac19caf677c481cdf86ed27b2dd80a81b3 (diff)
downloadframeworks_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')
-rw-r--r--services/java/com/android/server/SystemServer.java4
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java176
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java2
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java9
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) {