summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/am
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-07-29 01:25:18 -0700
committerDianne Hackborn <hackbod@google.com>2011-07-29 02:06:46 -0700
commitc68c913d357e2955d4bd7ca52829071e531c7825 (patch)
tree764dddf699a1db5e44d74e94e3f354b9ed61ff71 /services/java/com/android/server/am
parent3970f6833d3c19f96cc7b6831327c8488932fa57 (diff)
downloadframeworks_base-c68c913d357e2955d4bd7ca52829071e531c7825.zip
frameworks_base-c68c913d357e2955d4bd7ca52829071e531c7825.tar.gz
frameworks_base-c68c913d357e2955d4bd7ca52829071e531c7825.tar.bz2
Various work on out of memory managment.
- Improve how we handle processes that have shown UI, to take care of more cases where we want to push them into the background LRU list. - New trim memory level for when an application that has done UI is no longer visible to the user. - Add APIs to get new trim memory callback. - Add a host of new bind flags to tweak how the system will adjust the OOM level of the target process. Change-Id: I23ba354112f411a9f8773a67426b4dff85fa2439
Diffstat (limited to 'services/java/com/android/server/am')
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java222
-rw-r--r--services/java/com/android/server/am/ActivityStack.java1
-rw-r--r--services/java/com/android/server/am/AppBindRecord.java2
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java21
4 files changed, 188 insertions, 58 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 66f88fc..14c6306 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -53,7 +53,7 @@ import android.app.Service;
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
-import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -8067,6 +8067,21 @@ public final class ActivityManagerService extends ActivityManagerNative
if (needSep) pw.println(" ");
needSep = true;
+ pw.println(" OOM levels:");
+ pw.print(" SYSTEM_ADJ: "); pw.println(SYSTEM_ADJ);
+ pw.print(" CORE_SERVER_ADJ: "); pw.println(CORE_SERVER_ADJ);
+ pw.print(" FOREGROUND_APP_ADJ: "); pw.println(FOREGROUND_APP_ADJ);
+ pw.print(" VISIBLE_APP_ADJ: "); pw.println(VISIBLE_APP_ADJ);
+ pw.print(" PERCEPTIBLE_APP_ADJ: "); pw.println(PERCEPTIBLE_APP_ADJ);
+ pw.print(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(HEAVY_WEIGHT_APP_ADJ);
+ pw.print(" BACKUP_APP_ADJ: "); pw.println(BACKUP_APP_ADJ);
+ pw.print(" SECONDARY_SERVER_ADJ: "); pw.println(SECONDARY_SERVER_ADJ);
+ pw.print(" HOME_APP_ADJ: "); pw.println(HOME_APP_ADJ);
+ pw.print(" HIDDEN_APP_MIN_ADJ: "); pw.println(HIDDEN_APP_MIN_ADJ);
+ pw.print(" EMPTY_APP_ADJ: "); pw.println(EMPTY_APP_ADJ);
+
+ if (needSep) pw.println(" ");
+ needSep = true;
pw.println(" Process OOM control:");
dumpProcessOomList(pw, this, procs, " ",
"Proc", "PERS", true);
@@ -8814,7 +8829,8 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(" ");
pw.print("keeping="); pw.print(r.keeping);
pw.print(" hidden="); pw.print(r.hidden);
- pw.print(" empty="); pw.println(r.empty);
+ pw.print(" empty="); pw.print(r.empty);
+ pw.print(" hasAboveClient="); pw.println(r.hasAboveClient);
if (!r.keeping) {
if (r.lastWakeTime != 0) {
@@ -9226,6 +9242,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.foregroundServices = false;
app.foregroundActivities = false;
app.hasShownUi = false;
+ app.hasAboveClient = false;
killServicesLocked(app, allowRestart);
@@ -10452,6 +10469,9 @@ public final class ActivityManagerService extends ActivityManagerNative
activity.connections.add(c);
}
b.client.connections.add(c);
+ if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ b.client.hasAboveClient = true;
+ }
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
@@ -10523,6 +10543,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (b.client != skipApp) {
b.client.connections.remove(c);
+ if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ b.client.updateHasAboveClientLocked();
+ }
}
clist = mServiceConnections.get(binder);
if (clist != null) {
@@ -12577,9 +12600,9 @@ 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 = hiddenAdj;
+ app.curAdj = app.curRawAdj = hiddenAdj;
}
- return app.curAdj;
+ return app.curRawAdj;
}
if (app.thread == null) {
@@ -12588,28 +12611,47 @@ public final class ActivityManagerService extends ActivityManagerNative
return (app.curAdj=EMPTY_APP_ADJ);
}
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
+ app.adjSource = null;
+ app.adjTarget = null;
+ app.empty = false;
+ app.hidden = false;
+
+ final int activitiesSize = app.activities.size();
+
if (app.maxAdj <= FOREGROUND_APP_ADJ) {
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
+ app.foregroundActivities = false;
app.keeping = true;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
+ // System process can do UI, and when they do we want to have
+ // them trim their memory after the user leaves the UI. To
+ // facilitate this, here we need to determine whether or not it
+ // is currently showing UI.
+ app.systemNoUi = true;
+ if (app == TOP_APP) {
+ app.systemNoUi = false;
+ } else if (activitiesSize > 0) {
+ for (int j = 0; j < activitiesSize; j++) {
+ final ActivityRecord r = app.activities.get(j);
+ if (r.visible) {
+ app.systemNoUi = false;
+ break;
+ }
+ }
+ }
return (app.curAdj=app.maxAdj);
}
final boolean hadForegroundActivities = app.foregroundActivities;
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
- app.adjSource = null;
- app.adjTarget = null;
- app.keeping = false;
- app.empty = false;
- app.hidden = false;
app.foregroundActivities = false;
-
- final int activitiesSize = app.activities.size();
+ app.keeping = false;
+ app.systemNoUi = false;
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
@@ -12784,7 +12826,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Binding to ourself is not interesting.
continue;
}
- if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
+ if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
ProcessRecord client = cr.binding.client;
int clientAdj = adj;
int myHiddenAdj = hiddenAdj;
@@ -12825,15 +12867,32 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
if (adj > clientAdj) {
- adj = clientAdj >= VISIBLE_APP_ADJ
- ? clientAdj : VISIBLE_APP_ADJ;
- if (!client.hidden) {
- app.hidden = false;
- }
- if (client.keeping) {
- app.keeping = true;
+ // If this process has recently shown UI, and
+ // the process that is binding to it is less
+ // important than being visible, then we don't
+ // care about the binding as much as we care
+ // about letting this process get into the LRU
+ // list to be killed and restarted if needed for
+ // memory.
+ if (app.hasShownUi && clientAdj > PERCEPTIBLE_APP_ADJ) {
+ adjType = "bound-bg-ui-services";
+ } else {
+ if ((cr.flags&(Context.BIND_ABOVE_CLIENT
+ |Context.BIND_IMPORTANT)) != 0) {
+ adj = clientAdj;
+ } else if (clientAdj >= VISIBLE_APP_ADJ) {
+ adj = clientAdj;
+ } else {
+ adj = VISIBLE_APP_ADJ;
+ }
+ if (!client.hidden) {
+ app.hidden = false;
+ }
+ if (client.keeping) {
+ app.keeping = true;
+ }
+ adjType = "service";
}
- adjType = "service";
}
if (adjType != null) {
app.adjType = adjType;
@@ -12848,21 +12907,22 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
- ActivityRecord a = cr.activity;
- //if (a != null) {
- // Slog.i(TAG, "Connection to " + a ": state=" + a.state);
- //}
- if (a != null && adj > FOREGROUND_APP_ADJ &&
- (a.state == ActivityState.RESUMED
- || a.state == ActivityState.PAUSING)) {
- adj = FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.hidden = false;
- app.adjType = "service";
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = a;
- app.adjTarget = s.name;
+ if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
+ ActivityRecord a = cr.activity;
+ if (a != null && adj > FOREGROUND_APP_ADJ &&
+ (a.visible || a.state == ActivityState.RESUMED
+ || a.state == ActivityState.PAUSING)) {
+ adj = FOREGROUND_APP_ADJ;
+ if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
+ app.hidden = false;
+ app.adjType = "service";
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
+ app.adjSource = a;
+ app.adjTarget = s.name;
+ }
}
}
}
@@ -12906,15 +12966,19 @@ public final class ActivityManagerService extends ActivityManagerNative
int clientAdj = computeOomAdjLocked(
client, myHiddenAdj, TOP_APP, true);
if (adj > clientAdj) {
- adj = clientAdj > FOREGROUND_APP_ADJ
- ? clientAdj : FOREGROUND_APP_ADJ;
+ if (app.hasShownUi && clientAdj > PERCEPTIBLE_APP_ADJ) {
+ app.adjType = "bg-ui-provider";
+ } else {
+ adj = clientAdj > FOREGROUND_APP_ADJ
+ ? clientAdj : FOREGROUND_APP_ADJ;
+ app.adjType = "provider";
+ }
if (!client.hidden) {
app.hidden = false;
}
if (client.keeping) {
app.keeping = true;
}
- app.adjType = "provider";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE;
app.adjSource = client;
@@ -12955,6 +13019,25 @@ public final class ActivityManagerService extends ActivityManagerNative
app.keeping = true;
}
+ if (app.hasAboveClient) {
+ // If this process has bound to any services with BIND_ABOVE_CLIENT,
+ // then we need to drop its adjustment to be lower than the service's
+ // in order to honor the request. We want to drop it by one adjustment
+ // level... but there is special meaning applied to various levels so
+ // we will skip some of them.
+ if (adj < FOREGROUND_APP_ADJ) {
+ // System process will not get dropped, ever
+ } else if (adj < VISIBLE_APP_ADJ) {
+ adj = VISIBLE_APP_ADJ;
+ } else if (adj < PERCEPTIBLE_APP_ADJ) {
+ adj = PERCEPTIBLE_APP_ADJ;
+ } else if (adj < HIDDEN_APP_MIN_ADJ) {
+ adj = HIDDEN_APP_MIN_ADJ;
+ } else if (adj < EMPTY_APP_ADJ) {
+ adj++;
+ }
+ }
+
app.curAdj = adj;
app.curSchedGroup = schedGroup;
@@ -12963,7 +13046,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.foregroundActivities).sendToTarget();
}
- return adj;
+ return app.curRawAdj;
}
/**
@@ -13204,7 +13287,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final boolean wasKeeping = app.keeping;
- int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
+ computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
if (app.curRawAdj != app.setRawAdj) {
if (app.curRawAdj > FOREGROUND_APP_ADJ
@@ -13233,14 +13316,14 @@ public final class ActivityManagerService extends ActivityManagerNative
app.setRawAdj = app.curRawAdj;
}
- if (adj != app.setAdj) {
- if (Process.setOomAdj(app.pid, adj)) {
+ if (app.curAdj != app.setAdj) {
+ if (Process.setOomAdj(app.pid, app.curAdj)) {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
TAG, "Set app " + app.processName +
- " oom adj to " + adj + " because " + app.adjType);
- app.setAdj = adj;
+ " oom adj to " + app.curAdj + " because " + app.adjType);
+ app.setAdj = app.curAdj;
} else {
- Slog.w(TAG, "Failed setting oom adj of " + app + " to " + adj);
+ Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
}
}
if (app.setSchedGroup != app.curSchedGroup) {
@@ -13377,7 +13460,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final int N = mLruProcesses.size();
factor = numBg/3;
step = 0;
- int curLevel = ComponentCallbacks.TRIM_MEMORY_COMPLETE;
+ int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
for (i=0; i<N; i++) {
ProcessRecord app = mLruProcesses.get(i);
if (app.curAdj >= HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
@@ -13386,7 +13469,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.thread.scheduleTrimMemory(curLevel);
} catch (RemoteException e) {
}
- if (curLevel >= ComponentCallbacks.TRIM_MEMORY_COMPLETE) {
+ if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
// For these apps we will also finish their activities
// to help them free memory.
mMainStack.destroyActivitiesLocked(app, false);
@@ -13396,23 +13479,36 @@ public final class ActivityManagerService extends ActivityManagerNative
step++;
if (step >= factor) {
switch (curLevel) {
- case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
- curLevel = ComponentCallbacks.TRIM_MEMORY_MODERATE;
+ case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+ curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
break;
- case ComponentCallbacks.TRIM_MEMORY_MODERATE:
- curLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND;
+ case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+ curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
break;
}
}
} else if (app.curAdj == HEAVY_WEIGHT_APP_ADJ) {
- if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_BACKGROUND
+ if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
- app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_BACKGROUND);
+ app.thread.scheduleTrimMemory(
+ ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
} catch (RemoteException e) {
}
}
- app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND;
+ app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+ } else if ((app.curAdj > VISIBLE_APP_ADJ || app.systemNoUi)
+ && app.pendingUiClean) {
+ if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
+ && app.thread != null) {
+ try {
+ app.thread.scheduleTrimMemory(
+ ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
+ } catch (RemoteException e) {
+ }
+ }
+ app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+ app.pendingUiClean = false;
} else {
app.trimMemoryLevel = 0;
}
@@ -13421,7 +13517,21 @@ public final class ActivityManagerService extends ActivityManagerNative
final int N = mLruProcesses.size();
for (i=0; i<N; i++) {
ProcessRecord app = mLruProcesses.get(i);
- app.trimMemoryLevel = 0;
+ if ((app.curAdj > VISIBLE_APP_ADJ || app.systemNoUi)
+ && app.pendingUiClean) {
+ if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
+ && app.thread != null) {
+ try {
+ app.thread.scheduleTrimMemory(
+ ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
+ } catch (RemoteException e) {
+ }
+ }
+ app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+ app.pendingUiClean = false;
+ } else {
+ app.trimMemoryLevel = 0;
+ }
}
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index cc58eaf..33b21ab 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -560,6 +560,7 @@ final class ActivityStack {
showAskCompatModeDialogLocked(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
app.hasShownUi = true;
+ app.pendingUiClean = true;
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
r.info, r.compat, r.icicle, results, newIntents, !andResume,
diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/java/com/android/server/am/AppBindRecord.java
index 9c57360..f1c54fa 100644
--- a/services/java/com/android/server/am/AppBindRecord.java
+++ b/services/java/com/android/server/am/AppBindRecord.java
@@ -26,7 +26,7 @@ import java.util.Iterator;
class AppBindRecord {
final ServiceRecord service; // The running service.
final IntentBindRecord intent; // The intent we are bound to.
- final ProcessRecord client; // Who has started/bound the service.
+ final ProcessRecord client; // Who has started/bound the service.
final HashSet<ConnectionRecord> connections = new HashSet<ConnectionRecord>();
// All ConnectionRecord for this client.
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 5b59363..a896ce4 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -23,6 +23,7 @@ import android.app.Dialog;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.os.Bundle;
@@ -66,7 +67,10 @@ class ProcessRecord {
boolean setIsForeground; // Running foreground UI when last set?
boolean foregroundServices; // Running any services that are foreground?
boolean foregroundActivities; // Running any activities that are foreground?
+ boolean systemNoUi; // This is a system process, but not currently showing UI.
boolean hasShownUi; // Has UI been shown in this process since it was started?
+ boolean pendingUiClean; // Want to clean up resources from showing UI?
+ boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower
boolean bad; // True if disabled in the bad process list
boolean killedBackground; // True when proc has been killed due to too many bg
String waitingToKill; // Process is waiting to be killed when in the bg; reason
@@ -185,8 +189,11 @@ class ProcessRecord {
pw.print(" set="); pw.println(setAdj);
pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
pw.print(" setSchedGroup="); pw.print(setSchedGroup);
+ pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
- pw.print(" hasShownUi="); pw.println(hasShownUi);
+ pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
+ pw.print(" pendingUiClean="); pw.print(pendingUiClean);
+ pw.print(" hasAboveClient="); pw.println(hasAboveClient);
pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
pw.print(" foregroundServices="); pw.print(foregroundServices);
pw.print(" forcingToForeground="); pw.println(forcingToForeground);
@@ -307,6 +314,18 @@ class ProcessRecord {
deathRecipient = null;
}
+ void updateHasAboveClientLocked() {
+ hasAboveClient = false;
+ if (connections.size() > 0) {
+ for (ConnectionRecord cr : connections) {
+ if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ hasAboveClient = true;
+ break;
+ }
+ }
+ }
+ }
+
public String toShortString() {
if (shortStringName != null) {
return shortStringName;