summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dianne Hackborn <hackbod@google.com> 2013-07-16 18:15:08 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2013-07-16 18:15:09 +0000
commitcdae0f3c608ed5aee5ddbdf9c54ac86a5619e64b (patch)
treeb8e54420bcf9b85f3ef4d9e8bff926c739f7f4eb
parent78b6a8615cf6c2c062187c23ced0c6fe6046498e (diff)
parentc8230519728b14065effd3b7d4eca273ff86160c (diff)
Merge "Switch proc stats to use new process state constants."
-rw-r--r--core/java/android/app/ActivityManager.java39
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/os/Debug.java13
-rw-r--r--core/jni/android_os_Debug.cpp36
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java2
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java3
-rw-r--r--services/java/com/android/server/am/ActiveServices.java126
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java971
-rw-r--r--services/java/com/android/server/am/IntentBindRecord.java31
-rw-r--r--services/java/com/android/server/am/ProcessList.java43
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java86
-rw-r--r--services/java/com/android/server/am/ProcessTracker.java227
12 files changed, 869 insertions, 718 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c79768ef1d7d..4e6c3dcb0702 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -234,32 +234,49 @@ public class ActivityManager {
/** @hide Process is a persistent system process and is doing UI. */
public static final int PROCESS_STATE_PERSISTENT_UI = 1;
- /** @hide Process is hosting the current top activity. */
+ /** @hide Process is hosting the current top activities. Note that this covers
+ * all activities that are visible to the user. */
public static final int PROCESS_STATE_TOP = 2;
/** @hide Process is important to the user, and something they are aware of. */
- public static final int PROCESS_STATE_IMPORTANT_PERCEPTIBLE = 3;
+ public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 3;
/** @hide Process is important to the user, but not something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 4;
- /** @hide Process is in the background running a receiver. */
- public static final int PROCESS_STATE_RECEIVER = 5;
-
/** @hide Process is in the background running a backup/restore operation. */
- public static final int PROCESS_STATE_BACKUP = 6;
+ public static final int PROCESS_STATE_BACKUP = 5;
+
+ /** @hide Process is in the background, but it can't restore its state so we want
+ * to try to avoid killing it. */
+ public static final int PROCESS_STATE_HEAVY_WEIGHT = 6;
- /** @hide Process is in the background running a service. */
+ /** @hide Process is in the background running a service. Unlike oom_adj, this level
+ * is used for both the normal running in background state and the executing
+ * operations state. */
public static final int PROCESS_STATE_SERVICE = 7;
+ /** @hide Process is in the background running a receiver. Note that from the
+ * perspective of oom_adj receivers run at a higher foreground level, but for our
+ * prioritization here that is not necessary and putting them below services means
+ * many fewer changes in some process states as they receive broadcasts. */
+ public static final int PROCESS_STATE_RECEIVER = 8;
+
/** @hide Process is in the background but hosts the home activity. */
- public static final int PROCESS_STATE_HOME = 8;
+ public static final int PROCESS_STATE_HOME = 9;
/** @hide Process is in the background but hosts the last shown activity. */
- public static final int PROCESS_STATE_LAST_ACTIVITY = 9;
+ public static final int PROCESS_STATE_LAST_ACTIVITY = 10;
+
+ /** @hide Process is being cached for later use and contains activities. */
+ public static final int PROCESS_STATE_CACHED_ACTIVITY = 11;
+
+ /** @hide Process is being cached for later use and is a client of another cached
+ * process that contains activities. */
+ public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 12;
- /** @hide Process is being cached for later use. */
- public static final int PROCESS_STATE_CACHED = 10;
+ /** @hide Process is being cached for later use and is empty. */
+ public static final int PROCESS_STATE_CACHED_EMPTY = 13;
/*package*/ ActivityManager(Context context, Handler handler) {
mContext = context;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c3d1971828e4..aa326adb498f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -230,7 +230,15 @@ public abstract class Context {
* tries to balance such requests from one app vs. the importantance of
* keeping other apps around.
*/
- public static final int BIND_VISIBLE = 0x0100;
+ public static final int BIND_VISIBLE = 0x10000000;
+
+ /**
+ * @hide
+ * Flag for {@link #bindService}: Consider this binding to be causing the target
+ * process to be showing UI, so it will be do a UI_HIDDEN memory trim when it goes
+ * away.
+ */
+ public static final int BIND_SHOWING_UI = 0x20000000;
/**
* Flag for {@link #bindService}: Don't consider the bound service to be
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index c5f473ea1946..0a6db25443a4 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -192,6 +192,14 @@ public final class Debug
return dalvikPss + nativePss + otherPss;
}
+ /**
+ * @hide Return total PSS memory usage in kB.
+ */
+ public int getTotalUss() {
+ return dalvikPrivateClean + dalvikPrivateDirty
+ + nativePrivateClean + nativePrivateDirty
+ + otherPrivateClean + otherPrivateDirty;
+ }
/**
* Return total PSS memory usage in kB.
@@ -1001,9 +1009,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
/**
* Retrieves the PSS memory used by the process as given by the
- * smaps. @hide
+ * smaps. Optionally supply a long array of 1 entry to also
+ * receive the uss of the process. @hide
*/
- public static native long getPss(int pid);
+ public static native long getPss(int pid, long[] outUss);
/**
* Establish an object allocation limit in the current thread.
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 8b7f3dd5fd3c..61ace4a19bc5 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -380,10 +380,11 @@ static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject o
android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
}
-static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
+static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid, jlongArray outUss)
{
char line[1024];
jlong pss = 0;
+ jlong uss = 0;
unsigned temp;
char tmp[128];
@@ -398,23 +399,42 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid)
break;
}
- if (strncmp(line, "Pss: ", 5) == 0) {
- char* c = line + 5;
- while (*c != 0 && (*c < '0' || *c > '9')) {
- c++;
+ if (line[0] == 'P') {
+ if (strncmp(line, "Pss:", 4) == 0) {
+ char* c = line + 4;
+ while (*c != 0 && (*c < '0' || *c > '9')) {
+ c++;
+ }
+ pss += atoi(c);
+ } else if (strncmp(line, "Private_Clean:", 14)
+ || strncmp(line, "Private_Dirty:", 14)) {
+ char* c = line + 14;
+ while (*c != 0 && (*c < '0' || *c > '9')) {
+ c++;
+ }
+ uss += atoi(c);
}
- pss += atoi(c);
}
}
fclose(fp);
+ if (outUss != NULL) {
+ if (env->GetArrayLength(outUss) >= 1) {
+ jlong* outUssArray = env->GetLongArrayElements(outUss, 0);
+ if (outUssArray != NULL) {
+ outUssArray[0] = uss;
+ }
+ env->ReleaseLongArrayElements(outUss, outUssArray, 0);
+ }
+ }
+
return pss;
}
static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
{
- return android_os_Debug_getPssPid(env, clazz, getpid());
+ return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
}
static jint read_binder_stat(const char* stat)
@@ -689,7 +709,7 @@ static JNINativeMethod gMethods[] = {
(void*) android_os_Debug_getDirtyPagesPid },
{ "getPss", "()J",
(void*) android_os_Debug_getPss },
- { "getPss", "(I)J",
+ { "getPss", "(I[J)J",
(void*) android_os_Debug_getPssPid },
{ "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V",
(void*) android_os_Debug_dumpNativeHeap },
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 1c1b0020b462..c0a521480528 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1210,7 +1210,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
if (bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE
- | Context.BIND_NOT_VISIBLE)) {
+ | Context.BIND_NOT_VISIBLE | Context.BIND_SHOWING_UI)) {
mLastBindTime = SystemClock.uptimeMillis();
mHaveConnection = true;
mCurId = info.getId();
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 6823f1363fc8..9a7390980405 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -885,7 +885,8 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
0, null, new UserHandle(serviceUserId)));
- if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE,
+ if (!mContext.bindServiceAsUser(intent, newConn,
+ Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI,
new UserHandle(serviceUserId))) {
String msg = "Unable to bind service: "
+ componentName;
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 5d721022990c..795e1424844c 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -421,7 +421,8 @@ public final class ActiveServices {
private void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
boolean anyForeground = false;
- for (ServiceRecord sr : proc.services) {
+ for (int i=proc.services.size()-1; i>=0; i--) {
+ ServiceRecord sr = proc.services.valueAt(i);
if (sr.isForeground) {
anyForeground = true;
break;
@@ -1670,78 +1671,72 @@ public final class ActiveServices {
}
// Clean up any connections this application has to other services.
- if (app.connections.size() > 0) {
- Iterator<ConnectionRecord> it = app.connections.iterator();
- while (it.hasNext()) {
- ConnectionRecord r = it.next();
- removeConnectionLocked(r, app, null);
- }
+ for (int i=app.connections.size()-1; i>=0; i--) {
+ ConnectionRecord r = app.connections.valueAt(i);
+ removeConnectionLocked(r, app, null);
}
app.connections.clear();
- if (app.services.size() != 0) {
+ for (int i=app.services.size()-1; i>=0; i--) {
// Any services running in the application need to be placed
// back in the pending list.
- Iterator<ServiceRecord> it = app.services.iterator();
- while (it.hasNext()) {
- ServiceRecord sr = it.next();
- synchronized (sr.stats.getBatteryStats()) {
- sr.stats.stopLaunchedLocked();
- }
- sr.app = null;
- sr.isolatedProc = null;
- sr.executeNesting = 0;
- if (sr.tracker != null) {
- sr.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(),
- SystemClock.uptimeMillis());
- }
- if (mStoppingServices.remove(sr)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
- }
-
- final int numClients = sr.bindings.size();
- for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
- IntentBindRecord b = sr.bindings.valueAt(bindingi);
- if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
- + ": shouldUnbind=" + b.hasBound);
- b.binder = null;
- b.requested = b.received = b.hasBound = false;
- }
-
- if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
- &ApplicationInfo.FLAG_PERSISTENT) == 0) {
- Slog.w(TAG, "Service crashed " + sr.crashCount
- + " times, stopping: " + sr);
- EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
- sr.userId, sr.crashCount, sr.shortName, app.pid);
- bringDownServiceLocked(sr);
- } else if (!allowRestart) {
- bringDownServiceLocked(sr);
- } else {
- boolean canceled = scheduleServiceRestartLocked(sr, true);
-
- // Should the service remain running? Note that in the
- // extreme case of so many attempts to deliver a command
- // that it failed we also will stop it here.
- if (sr.startRequested && (sr.stopIfKilled || canceled)) {
- if (sr.pendingStarts.size() == 0) {
- sr.startRequested = false;
- if (sr.tracker != null) {
- sr.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(),
- SystemClock.uptimeMillis());
- }
- if (!sr.hasAutoCreateConnections()) {
- // Whoops, no reason to restart!
- bringDownServiceLocked(sr);
- }
+ ServiceRecord sr = app.services.valueAt(i);
+ synchronized (sr.stats.getBatteryStats()) {
+ sr.stats.stopLaunchedLocked();
+ }
+ sr.app = null;
+ sr.isolatedProc = null;
+ sr.executeNesting = 0;
+ if (sr.tracker != null) {
+ sr.tracker.setExecuting(false, mAm.mProcessTracker.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
+ if (mStoppingServices.remove(sr)) {
+ if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
+ }
+
+ final int numClients = sr.bindings.size();
+ for (int bindingi=numClients-1; bindingi>=0; bindingi--) {
+ IntentBindRecord b = sr.bindings.valueAt(bindingi);
+ if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b
+ + ": shouldUnbind=" + b.hasBound);
+ b.binder = null;
+ b.requested = b.received = b.hasBound = false;
+ }
+
+ if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
+ &ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ Slog.w(TAG, "Service crashed " + sr.crashCount
+ + " times, stopping: " + sr);
+ EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
+ sr.userId, sr.crashCount, sr.shortName, app.pid);
+ bringDownServiceLocked(sr);
+ } else if (!allowRestart) {
+ bringDownServiceLocked(sr);
+ } else {
+ boolean canceled = scheduleServiceRestartLocked(sr, true);
+
+ // Should the service remain running? Note that in the
+ // extreme case of so many attempts to deliver a command
+ // that it failed we also will stop it here.
+ if (sr.startRequested && (sr.stopIfKilled || canceled)) {
+ if (sr.pendingStarts.size() == 0) {
+ sr.startRequested = false;
+ if (sr.tracker != null) {
+ sr.tracker.setStarted(false, mAm.mProcessTracker.getMemFactorLocked(),
+ SystemClock.uptimeMillis());
+ }
+ if (!sr.hasAutoCreateConnections()) {
+ // Whoops, no reason to restart!
+ bringDownServiceLocked(sr);
}
}
}
}
+ }
- if (!allowRestart) {
- app.services.clear();
- }
+ if (!allowRestart) {
+ app.services.clear();
}
// Make sure we have no more records on the stopping list.
@@ -1880,11 +1875,10 @@ public final class ActiveServices {
return;
}
long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
- Iterator<ServiceRecord> it = proc.executingServices.iterator();
ServiceRecord timeout = null;
long nextTime = 0;
- while (it.hasNext()) {
- ServiceRecord sr = it.next();
+ for (int i=proc.executingServices.size()-1; i>=0; i--) {
+ ServiceRecord sr = proc.executingServices.valueAt(i);
if (sr.executingStart < maxTime) {
timeout = sr;
break;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 90fb0037ffc1..b51415f5c655 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1505,6 +1505,7 @@ public final class ActivityManagerService extends ActivityManagerNative
case COLLECT_PSS_BG_MSG: {
int i=0;
long start = SystemClock.uptimeMillis();
+ long[] tmp = new long[1];
do {
ProcessRecord proc;
int oomAdj;
@@ -1528,10 +1529,10 @@ public final class ActivityManagerService extends ActivityManagerNative
i++;
}
if (proc != null) {
- long pss = Debug.getPss(pid);
+ long pss = Debug.getPss(pid, tmp);
synchronized (ActivityManagerService.this) {
if (proc.thread != null && proc.setAdj == oomAdj && proc.pid == pid) {
- proc.baseProcessTracker.addPss(pss, true);
+ proc.baseProcessTracker.addPss(pss, tmp[0], true);
}
}
}
@@ -2157,13 +2158,12 @@ public final class ActivityManagerService extends ActivityManagerNative
// If the app is currently using a content provider or service,
// bump those processes as well.
- if (app.connections.size() > 0) {
- for (ConnectionRecord cr : app.connections) {
- 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);
- }
+ for (int j=app.connections.size()-1; j>=0; j--) {
+ ConnectionRecord cr = app.connections.valueAt(j);
+ 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);
}
}
for (int j=app.conProviders.size()-1; j>=0; j--) {
@@ -4010,7 +4010,8 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
- proc.baseProcessTracker.addPss(infos[i].getTotalPss(), false);
+ proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
+ infos[i].getTotalUss(), false);
}
}
}
@@ -4031,12 +4032,13 @@ public final class ActivityManagerService extends ActivityManagerNative
oomAdj = proc != null ? proc.setAdj : 0;
}
}
- pss[i] = Debug.getPss(pids[i]);
+ long[] tmpUss = new long[1];
+ pss[i] = Debug.getPss(pids[i], tmpUss);
if (proc != null) {
synchronized (this) {
if (proc.thread != null && proc.setAdj == oomAdj) {
// Record this for posterity if the process has been stable.
- proc.baseProcessTracker.addPss(pss[i], false);
+ proc.baseProcessTracker.addPss(pss[i], tmpUss[0], false);
}
}
}
@@ -8802,14 +8804,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// Bump up the crash count of any services currently running in the proc.
- if (app.services.size() != 0) {
+ for (int i=app.services.size()-1; i>=0; i--) {
// Any services running in the application need to be placed
// back in the pending list.
- Iterator<ServiceRecord> it = app.services.iterator();
- while (it.hasNext()) {
- ServiceRecord sr = it.next();
- sr.crashCount++;
- }
+ ServiceRecord sr = app.services.valueAt(i);
+ sr.crashCount++;
}
// If the crashing process is what we consider to be the "home process" and it has been
@@ -10269,8 +10268,8 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(" FOREGROUND_APP_ADJ: "); pw.println(ProcessList.FOREGROUND_APP_ADJ);
pw.print(" VISIBLE_APP_ADJ: "); pw.println(ProcessList.VISIBLE_APP_ADJ);
pw.print(" PERCEPTIBLE_APP_ADJ: "); pw.println(ProcessList.PERCEPTIBLE_APP_ADJ);
- pw.print(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ);
pw.print(" BACKUP_APP_ADJ: "); pw.println(ProcessList.BACKUP_APP_ADJ);
+ pw.print(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(ProcessList.HEAVY_WEIGHT_APP_ADJ);
pw.print(" SERVICE_ADJ: "); pw.println(ProcessList.SERVICE_ADJ);
pw.print(" HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ);
pw.print(" PREVIOUS_APP_ADJ: "); pw.println(ProcessList.PREVIOUS_APP_ADJ);
@@ -10772,10 +10771,10 @@ public final class ActivityManagerService extends ActivityManagerNative
oomAdj = buildOomTag("home ", null, r.setAdj, ProcessList.HOME_APP_ADJ);
} else if (r.setAdj >= ProcessList.SERVICE_ADJ) {
oomAdj = buildOomTag("svc ", null, r.setAdj, ProcessList.SERVICE_ADJ);
- } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
- oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
} else if (r.setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
oomAdj = buildOomTag("hvy ", null, r.setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+ } else if (r.setAdj >= ProcessList.BACKUP_APP_ADJ) {
+ oomAdj = buildOomTag("bkup ", null, r.setAdj, ProcessList.BACKUP_APP_ADJ);
} else if (r.setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
oomAdj = buildOomTag("prcp ", null, r.setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
} else if (r.setAdj >= ProcessList.VISIBLE_APP_ADJ) {
@@ -10820,29 +10819,38 @@ public final class ActivityManagerService extends ActivityManagerNative
case ActivityManager.PROCESS_STATE_TOP:
procState = "T ";
break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE:
- procState = "IP";
+ case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+ procState = "IF";
break;
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
procState = "IB";
break;
- case ActivityManager.PROCESS_STATE_RECEIVER:
- procState = "R ";
- 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 = "H ";
+ procState = "HO";
break;
case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
procState = "LA";
break;
- case ActivityManager.PROCESS_STATE_CACHED:
- procState = "C ";
+ 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 = "??";
@@ -10895,9 +10903,6 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(prefix);
pw.print(" ");
pw.print("oom: max="); pw.print(r.maxAdj);
- pw.print(" cached="); pw.print(r.cachedAdj);
- pw.print(" client="); pw.print(r.clientCachedAdj);
- pw.print(" empty="); pw.print(r.emptyAdj);
pw.print(" curRaw="); pw.print(r.curRawAdj);
pw.print(" setRaw="); pw.print(r.setRawAdj);
pw.print(" cur="); pw.print(r.curAdj);
@@ -11139,21 +11144,24 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int[] DUMP_MEM_OOM_ADJ = new int[] {
ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
- ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
- ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
+ ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ,
+ ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
+ ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MAX_ADJ
};
static final String[] DUMP_MEM_OOM_LABEL = new String[] {
"System", "Persistent", "Foreground",
- "Visible", "Perceptible", "Heavy Weight",
- "Backup", "A Services", "Home", "Previous",
- "B Services", "Cached"
+ "Visible", "Perceptible",
+ "Heavy Weight", "Backup",
+ "A Services", "Home",
+ "Previous", "B Services", "Cached"
};
static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
"sys", "pers", "fore",
- "vis", "percept", "heavy",
- "backup", "servicea", "home", "prev",
- "serviceb", "cached"
+ "vis", "percept",
+ "heavy", "backup",
+ "servicea", "home",
+ "prev", "serviceb", "cached"
};
final void dumpApplicationMemoryUsage(FileDescriptor fd,
@@ -11225,6 +11233,7 @@ public final class ActivityManagerService extends ActivityManagerNative
long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])
new ArrayList[DUMP_MEM_OOM_LABEL.length];
+ final long[] tmpLong = new long[1];
long totalPss = 0;
long cachedPss = 0;
@@ -11264,16 +11273,18 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!brief && !oomOnly) {
Debug.getMemoryInfo(pid, mi);
} else {
- mi.dalvikPss = (int)Debug.getPss(pid);
+ mi.dalvikPss = (int)Debug.getPss(pid, tmpLong);
+ mi.dalvikPrivateDirty = (int)tmpLong[0];
}
}
final long myTotalPss = mi.getTotalPss();
+ final long myTotalUss = mi.getTotalUss();
synchronized (this) {
if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
// Record this for posterity if the process has been stable.
- r.baseProcessTracker.addPss(myTotalPss, true);
+ r.baseProcessTracker.addPss(myTotalPss, myTotalUss, true);
}
}
@@ -11642,14 +11653,11 @@ public final class ActivityManagerService extends ActivityManagerNative
skipCurrentReceiverLocked(app);
// Unregister any receivers.
- if (app.receivers.size() > 0) {
- Iterator<ReceiverList> it = app.receivers.iterator();
- while (it.hasNext()) {
- removeReceiverLocked(it.next());
- }
- app.receivers.clear();
+ for (int i=app.receivers.size()-1; i>=0; i--) {
+ removeReceiverLocked(app.receivers.valueAt(i));
}
-
+ app.receivers.clear();
+
// If the app is undergoing backup, tell the backup manager about it
if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG, "App "
@@ -13409,29 +13417,17 @@ public final class ActivityManagerService extends ActivityManagerNative
return null;
}
- private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, int clientCachedAdj,
- int emptyAdj, ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
+ private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
+ boolean doingAll, long now) {
if (mAdjSeq == app.adjSeq) {
- // This adjustment has already been computed. If we are calling
- // from the top, we may have already computed our adjustment with
- // an earlier cached adjustment that isn't really for us... if
- // so, use the new cached adjustment.
- if (!recursed && app.cached) {
- if (app.hasActivities) {
- app.curAdj = app.curRawAdj = app.nonStoppingAdj = cachedAdj;
- } else if (app.hasClientActivities) {
- app.curAdj = app.curRawAdj = app.nonStoppingAdj = clientCachedAdj;
- } else {
- app.curAdj = app.curRawAdj = app.nonStoppingAdj = emptyAdj;
- }
- }
+ // This adjustment has already been computed.
return app.curRawAdj;
}
if (app.thread == null) {
app.adjSeq = mAdjSeq;
app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.curProcState = ActivityManager.PROCESS_STATE_CACHED;
+ app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
}
@@ -13449,7 +13445,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.nonStoppingAdj = app.maxAdj;
+ app.curRawAdj = app.maxAdj;
app.hasActivities = false;
app.foregroundActivities = false;
app.keeping = true;
@@ -13507,7 +13503,7 @@ public final class ActivityManagerService extends ActivityManagerNative
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
interesting = true;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
} else if ((queue = isReceivingBroadcast(app)) != null) {
// An app that is currently receiving a broadcast also
// counts as being in the foreground for OOM killer purposes.
@@ -13526,33 +13522,39 @@ public final class ActivityManagerService extends ActivityManagerNative
app.adjType = "exec-service";
procState = ActivityManager.PROCESS_STATE_SERVICE;
} else {
- // Assume process is cached (has activities); we will correct
- // later if this is not the case.
- adj = cachedAdj;
+ // As far as we know the process is empty. We may change our mind later.
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ // At this point we don't actually know the adjustment. Use the cached adj
+ // value that the caller wants us to.
+ adj = cachedAdj;
+ procState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
app.cached = true;
- app.adjType = "cch-act";
- procState = ActivityManager.PROCESS_STATE_CACHED;
+ app.empty = true;
+ app.adjType = "cch-empty";
}
- boolean hasStoppingActivities = false;
-
// Examine all activities if not already foreground.
if (!foregroundActivities && activitiesSize > 0) {
for (int j = 0; j < activitiesSize; j++) {
final ActivityRecord r = app.activities.get(j);
+ if (r.app != app) {
+ Slog.w(TAG, "Wtf, activity " + r + " in proc activity list not using proc "
+ + app + "?!?");
+ continue;
+ }
+ app.hasActivities = true;
if (r.visible) {
// App has a visible activity; only upgrade adjustment.
if (adj > ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
app.adjType = "visible";
}
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ if (procState > ActivityManager.PROCESS_STATE_TOP) {
+ procState = ActivityManager.PROCESS_STATE_TOP;
}
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
- app.hasActivities = true;
+ app.empty = false;
foregroundActivities = true;
break;
} else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
@@ -13560,53 +13562,54 @@ public final class ActivityManagerService extends ActivityManagerNative
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "pausing";
}
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ if (procState > ActivityManager.PROCESS_STATE_TOP) {
+ procState = ActivityManager.PROCESS_STATE_TOP;
}
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
+ app.empty = false;
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.
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ app.adjType = "stopping";
+ }
+ // For the process state, we will at this point consider the
+ // process to be cached. It will be cached either as an activity
+ // or empty depending on whether the activity is finishing. We do
+ // this so that we can treat the process as cached for purposes of
+ // memory trimming (determing current memory level, trim command to
+ // send to process) since there can be an arbitrary number of stopping
+ // processes and they should soon all go into the cached state.
+ if (!r.finishing) {
+ if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+ }
}
app.cached = false;
+ app.empty = false;
foregroundActivities = true;
- hasStoppingActivities = true;
- }
- if (r.app == app) {
- app.hasActivities = true;
+ } else {
+ if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+ app.adjType = "cch-act";
+ }
}
}
}
- if (adj == cachedAdj && !app.hasActivities) {
- if (app.hasClientActivities) {
- adj = clientCachedAdj;
- app.adjType = "cch-client-act";
- } else {
- // Whoops, this process is completely empty as far as we know
- // at this point.
- adj = emptyAdj;
- app.empty = true;
- app.adjType = "cch-empty";
- }
- }
-
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
if (app.foregroundServices) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.cached = false;
app.adjType = "fg-service";
schedGroup = Process.THREAD_GROUP_DEFAULT;
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
app.cached = false;
app.adjType = "force-fg";
app.adjSource = app.forcingToForeground;
@@ -13618,12 +13621,17 @@ public final class ActivityManagerService extends ActivityManagerNative
interesting = true;
}
- if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) {
- // We don't want to kill the current heavy-weight process.
- adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- app.cached = false;
- app.adjType = "heavy";
+ if (app == mHeavyWeightProcess) {
+ if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ // We don't want to kill the current heavy-weight process.
+ adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
+ schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ app.cached = false;
+ app.adjType = "heavy";
+ }
+ if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
+ procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+ }
}
if (app == mHomeProcess) {
@@ -13663,7 +13671,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 = app.nonStoppingAdj = adj;
+ app.curRawAdj = adj;
app.hasStartedServices = false;
if (mBackupTarget != null && app == mBackupTarget.app) {
@@ -13682,243 +13690,220 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- if (app.services.size() != 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
- final long now = SystemClock.uptimeMillis();
- // This process is more important if the top activity is
- // bound to the service.
- Iterator<ServiceRecord> jt = app.services.iterator();
- while (jt.hasNext() && adj > ProcessList.FOREGROUND_APP_ADJ) {
- ServiceRecord s = jt.next();
- if (s.startRequested) {
- app.hasStartedServices = true;
- if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
- procState = ActivityManager.PROCESS_STATE_SERVICE;
- }
- if (app.hasShownUi && app != mHomeProcess) {
- // If this process has shown some UI, let it immediately
- // go to the LRU list because it may be pretty heavy with
- // UI stuff. We'll tag it with a label just to help
- // debug and understand what is going on.
- if (adj > ProcessList.SERVICE_ADJ) {
- app.adjType = "cch-started-ui-services";
- }
- } else {
- if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
- // This service has seen some activity within
- // recent memory, so we will keep its process ahead
- // of the background processes.
- if (adj > ProcessList.SERVICE_ADJ) {
- adj = ProcessList.SERVICE_ADJ;
- app.adjType = "started-services";
- app.cached = false;
- }
- }
- // If we have let the service slide into the background
- // state, still have some text describing what it is doing
- // even though the service no longer has an impact.
+ for (int is = app.services.size()-1;
+ is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ is--) {
+ ServiceRecord s = app.services.valueAt(is);
+ if (s.startRequested) {
+ app.hasStartedServices = true;
+ if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
+ procState = ActivityManager.PROCESS_STATE_SERVICE;
+ }
+ if (app.hasShownUi && app != mHomeProcess) {
+ // If this process has shown some UI, let it immediately
+ // go to the LRU list because it may be pretty heavy with
+ // UI stuff. We'll tag it with a label just to help
+ // debug and understand what is going on.
+ if (adj > ProcessList.SERVICE_ADJ) {
+ app.adjType = "cch-started-ui-services";
+ }
+ } else {
+ if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+ // This service has seen some activity within
+ // recent memory, so we will keep its process ahead
+ // of the background processes.
if (adj > ProcessList.SERVICE_ADJ) {
- app.adjType = "cch-started-services";
+ adj = ProcessList.SERVICE_ADJ;
+ app.adjType = "started-services";
+ app.cached = false;
}
}
- // Don't kill this process because it is doing work; it
- // has said it is doing work.
- app.keeping = true;
- }
- for (int conni = s.connections.size()-1;
- conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
- conni--) {
- ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
- for (int i = 0;
- i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
- i++) {
- // XXX should compute this based on the max of
- // all connected clients.
- ConnectionRecord cr = clist.get(i);
- if (cr.binding.client == app) {
- // Binding to ourself is not interesting.
- continue;
- }
- if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
- ProcessRecord client = cr.binding.client;
- int myCachedAdj = cachedAdj;
- if (myCachedAdj > client.cachedAdj) {
- if (client.cachedAdj >= ProcessList.VISIBLE_APP_ADJ) {
- myCachedAdj = client.cachedAdj;
- } else {
- myCachedAdj = ProcessList.VISIBLE_APP_ADJ;
- }
- }
- int myClientCachedAdj = clientCachedAdj;
- if (myClientCachedAdj > client.clientCachedAdj) {
- if (client.clientCachedAdj >= ProcessList.VISIBLE_APP_ADJ) {
- myClientCachedAdj = client.clientCachedAdj;
- } else {
- myClientCachedAdj = ProcessList.VISIBLE_APP_ADJ;
- }
- }
- int myEmptyAdj = emptyAdj;
- if (myEmptyAdj > client.emptyAdj) {
- if (client.emptyAdj >= ProcessList.VISIBLE_APP_ADJ) {
- myEmptyAdj = client.emptyAdj;
- } else {
- myEmptyAdj = ProcessList.VISIBLE_APP_ADJ;
+ // If we have let the service slide into the background
+ // state, still have some text describing what it is doing
+ // even though the service no longer has an impact.
+ if (adj > ProcessList.SERVICE_ADJ) {
+ app.adjType = "cch-started-services";
+ }
+ }
+ // Don't kill this process because it is doing work; it
+ // has said it is doing work.
+ app.keeping = true;
+ }
+ for (int conni = s.connections.size()-1;
+ conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ conni--) {
+ ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
+ for (int i = 0;
+ i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ i++) {
+ // XXX should compute this based on the max of
+ // all connected clients.
+ ConnectionRecord cr = clist.get(i);
+ if (cr.binding.client == app) {
+ // Binding to ourself is not interesting.
+ continue;
+ }
+ if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
+ ProcessRecord client = cr.binding.client;
+ int clientAdj = computeOomAdjLocked(client, cachedAdj,
+ TOP_APP, doingAll, now);
+ int clientProcState = client.curProcState;
+ String adjType = null;
+ if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
+ // Not doing bind OOM management, so treat
+ // this guy more like a started service.
+ if (app.hasShownUi && app != mHomeProcess) {
+ // If this process has shown some UI, let it immediately
+ // go to the LRU list because it may be pretty heavy with
+ // UI stuff. We'll tag it with a label just to help
+ // debug and understand what is going on.
+ if (adj > clientAdj) {
+ adjType = "cch-bound-ui-services";
}
- }
- int clientAdj = computeOomAdjLocked(client, myCachedAdj,
- myClientCachedAdj, myEmptyAdj, TOP_APP, true, doingAll);
- int clientProcState = client.curProcState;
- String adjType = null;
- if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
- // Not doing bind OOM management, so treat
- // this guy more like a started service.
- if (app.hasShownUi && app != mHomeProcess) {
- // If this process has shown some UI, let it immediately
- // go to the LRU list because it may be pretty heavy with
- // UI stuff. We'll tag it with a label just to help
- // debug and understand what is going on.
+ app.cached = false;
+ clientAdj = adj;
+ clientProcState = procState;
+ } else {
+ if (now >= (s.lastActivity
+ + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+ // This service has not seen activity within
+ // recent memory, so allow it to drop to the
+ // LRU list if there is no other reason to keep
+ // it around. We'll also tag it with a label just
+ // to help debug and undertand what is going on.
if (adj > clientAdj) {
- adjType = "cch-bound-ui-services";
+ adjType = "cch-bound-services";
}
- app.cached = false;
clientAdj = adj;
- clientProcState = procState;
- } else {
- if (now >= (s.lastActivity
- + ActiveServices.MAX_SERVICE_INACTIVITY)) {
- // This service has not seen activity within
- // recent memory, so allow it to drop to the
- // LRU list if there is no other reason to keep
- // it around. We'll also tag it with a label just
- // to help debug and undertand what is going on.
- if (adj > clientAdj) {
- adjType = "cch-bound-services";
- }
- clientAdj = adj;
- }
- }
- } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
- if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) {
- // If this connection is keeping the service
- // created, then we want to try to better follow
- // its memory management semantics for activities.
- // That is, if it is sitting in the background
- // LRU list as a cached process (with activities),
- // we don't want the service it is connected to
- // to go into the empty LRU and quickly get killed,
- // because all we'll do is just end up restarting
- // the service.
- app.hasClientActivities |= client.hasActivities;
}
}
- if (adj > clientAdj) {
- // 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 && app != mHomeProcess
- && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adjType = "cch-bound-ui-services";
- } else {
- if ((cr.flags&(Context.BIND_ABOVE_CLIENT
- |Context.BIND_IMPORTANT)) != 0) {
- adj = clientAdj;
- } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
- && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
- && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
- adj = clientAdj;
- } else {
- app.pendingUiClean = true;
- if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
- }
- }
- if (!client.cached) {
- app.cached = false;
- }
- if (client.keeping) {
- app.keeping = true;
+ } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
+ if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) {
+ // If this connection is keeping the service
+ // created, then we want to try to better follow
+ // its memory management semantics for activities.
+ // That is, if it is sitting in the background
+ // LRU list as a cached process (with activities),
+ // we don't want the service it is connected to
+ // to go into the empty LRU and quickly get killed,
+ // because all we'll do is just end up restarting
+ // the service.
+ if (client.hasActivities) {
+ if (procState >
+ ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT) {
+ procState =
+ ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+ app.adjType = "cch-client-act";
}
- adjType = "service";
}
+ app.hasClientActivities |= client.hasActivities;
}
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
+ if (adj > clientAdj) {
+ // 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 && app != mHomeProcess
+ && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adjType = "cch-bound-ui-services";
+ } else {
+ if ((cr.flags&(Context.BIND_ABOVE_CLIENT
+ |Context.BIND_IMPORTANT)) != 0) {
+ adj = clientAdj;
+ } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
+ && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
+ && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ } else if (clientAdj > ProcessList.VISIBLE_APP_ADJ) {
+ adj = clientAdj;
+ } else {
+ if (adj > ProcessList.VISIBLE_APP_ADJ) {
+ adj = ProcessList.VISIBLE_APP_ADJ;
+ }
}
- if (clientProcState <
- ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) {
- clientProcState =
- ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ if (!client.cached) {
+ app.cached = false;
}
- } else {
- if (clientProcState <
- ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
- clientProcState =
- ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ if (client.keeping) {
+ app.keeping = true;
}
+ adjType = "service";
+ }
+ }
+ if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
}
- if (procState > clientProcState) {
- procState = clientProcState;
+ if (clientProcState <
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ clientProcState =
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
- if (adjType != null) {
- app.adjType = adjType;
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = cr.binding.client;
- app.adjSourceOom = clientAdj;
- app.adjTarget = s.name;
+ } else {
+ if (clientProcState <
+ ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+ clientProcState =
+ ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
}
}
- final ActivityRecord a = cr.activity;
- if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
- if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
- (a.visible || a.state == ActivityState.RESUMED
- || a.state == ActivityState.PAUSING)) {
- adj = ProcessList.FOREGROUND_APP_ADJ;
- if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- }
- app.cached = false;
- app.adjType = "service";
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = a;
- app.adjSourceOom = adj;
- app.adjTarget = s.name;
+ if (procState > clientProcState) {
+ procState = clientProcState;
+ }
+ if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ && (cr.flags&Context.BIND_SHOWING_UI) != 0) {
+ app.pendingUiClean = true;
+ }
+ if (adjType != null) {
+ app.adjType = adjType;
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
+ app.adjSource = cr.binding.client;
+ app.adjSourceOom = clientAdj;
+ app.adjTarget = s.name;
+ }
+ }
+ final ActivityRecord a = cr.activity;
+ if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
+ if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
+ (a.visible || a.state == ActivityState.RESUMED
+ || a.state == ActivityState.PAUSING)) {
+ adj = ProcessList.FOREGROUND_APP_ADJ;
+ if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
}
+ app.cached = false;
+ app.adjType = "service";
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
+ app.adjSource = a;
+ app.adjSourceOom = adj;
+ app.adjTarget = s.name;
}
}
}
}
-
- // Finally, if this process has active services running in it, we
- // would like to avoid killing it unless it would prevent the current
- // application from running. By default we put the process in
- // with the rest of the background processes; as we scan through
- // its services we may bump it up from there.
- if (adj > cachedAdj) {
- adj = cachedAdj;
- app.cached = false;
- app.adjType = "cch-services";
- }
}
for (int provi = app.pubProviders.size()-1;
provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
provi--) {
ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
for (int i = cpr.connections.size()-1;
i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
- || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ || procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
i--) {
ContentProviderConnection conn = cpr.connections.get(i);
ProcessRecord client = conn.client;
@@ -13926,32 +13911,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Being our own client is not interesting.
continue;
}
- int myCachedAdj = cachedAdj;
- if (myCachedAdj > client.cachedAdj) {
- if (client.cachedAdj > ProcessList.FOREGROUND_APP_ADJ) {
- myCachedAdj = client.cachedAdj;
- } else {
- myCachedAdj = ProcessList.FOREGROUND_APP_ADJ;
- }
- }
- int myClientCachedAdj = clientCachedAdj;
- if (myClientCachedAdj > client.clientCachedAdj) {
- if (client.clientCachedAdj >= ProcessList.FOREGROUND_APP_ADJ) {
- myClientCachedAdj = client.clientCachedAdj;
- } else {
- myClientCachedAdj = ProcessList.FOREGROUND_APP_ADJ;
- }
- }
- int myEmptyAdj = emptyAdj;
- if (myEmptyAdj > client.emptyAdj) {
- if (client.emptyAdj > ProcessList.FOREGROUND_APP_ADJ) {
- myEmptyAdj = client.emptyAdj;
- } else {
- myEmptyAdj = ProcessList.FOREGROUND_APP_ADJ;
- }
- }
- int clientAdj = computeOomAdjLocked(client, myCachedAdj,
- myClientCachedAdj, myEmptyAdj, TOP_APP, true, doingAll);
+ int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
if (adj > clientAdj) {
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -13961,12 +13921,8 @@ public final class ActivityManagerService extends ActivityManagerNative
? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
app.adjType = "provider";
}
- if (!client.cached) {
- app.cached = false;
- }
- if (client.keeping) {
- app.keeping = true;
- }
+ app.cached &= client.cached;
+ app.keeping |= client.keeping;
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE;
app.adjSource = client;
@@ -13974,7 +13930,10 @@ public final class ActivityManagerService extends ActivityManagerNative
app.adjTarget = cpr.name;
}
if (procState > client.curProcState) {
- procState = client.curProcState;
+ procState = client.curProcState >
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ ? client.curProcState
+ : ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -13992,8 +13951,8 @@ public final class ActivityManagerService extends ActivityManagerNative
app.adjType = "provider";
app.adjTarget = cpr.name;
}
- if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE) {
- procState = ActivityManager.PROCESS_STATE_IMPORTANT_PERCEPTIBLE;
+ if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
}
}
}
@@ -14010,16 +13969,6 @@ public final class ActivityManagerService extends ActivityManagerNative
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 +
@@ -14034,24 +13983,12 @@ 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 < ProcessList.FOREGROUND_APP_ADJ) {
- // System process will not get dropped, ever
- } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
- adj = ProcessList.VISIBLE_APP_ADJ;
- } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
- adj = ProcessList.CACHED_APP_MIN_ADJ;
- } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
- adj++;
- }
- }
+ // Do final modification to adj. Everything we do between here and applying
+ // the final setAdj must be done in this function, because we will also use
+ // it when computing the final cached adj later. Note that we don't need to
+ // worry about this for max adj above, since max adj will always be used to
+ // keep it out of the cached vaues.
+ adj = app.modifyRawOomAdj(adj);
app.curProcState = procState;
@@ -14407,23 +14344,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
- int clientCachedAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll,
- boolean doingProcessState, long now) {
- app.cachedAdj = cachedAdj;
- app.clientCachedAdj = clientCachedAdj;
- app.emptyAdj = emptyAdj;
-
- if (app.thread == null) {
- return false;
- }
-
- final boolean wasKeeping = app.keeping;
-
+ private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping,
+ ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
boolean success = true;
- computeOomAdjLocked(app, cachedAdj, clientCachedAdj, emptyAdj, TOP_APP, false, doingAll);
-
if (app.curRawAdj != app.setRawAdj) {
if (wasKeeping && !app.keeping) {
// This app is no longer something we want to keep. Note
@@ -14467,11 +14391,6 @@ public final class ActivityManagerService extends ActivityManagerNative
requestPssLocked(app, now, true);
}
app.setAdj = app.curAdj;
- app.setAdjChanged = true;
- if (!doingAll) {
- app.setProcessTrackerState(TOP_APP, mProcessTracker.getMemFactorLocked(),
- now, mProcessList);
- }
} else {
success = false;
Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
@@ -14516,7 +14435,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (app.repProcState != app.curProcState) {
app.repProcState = app.curProcState;
- if (!doingProcessState && app.thread != null) {
+ if (!reportingProcessState && app.thread != null) {
try {
if (false) {
//RuntimeException h = new RuntimeException("here");
@@ -14528,9 +14447,33 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
+ if (app.setProcState != app.curProcState) {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Proc state change of " + app.processName
+ + " to " + app.curProcState);
+ app.setProcState = app.curProcState;
+ app.procStateChanged = true;
+ if (!doingAll) {
+ app.setProcessTrackerState(mProcessTracker.getMemFactorLocked(), now);
+ }
+ }
return success;
}
+ private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj,
+ ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
+ if (app.thread == null) {
+ return false;
+ }
+
+ final boolean wasKeeping = app.keeping;
+
+ computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
+
+ return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll,
+ reportingProcessState, now);
+ }
+
private final ActivityRecord resumedAppLocked() {
return mStackSupervisor.resumedAppLocked();
}
@@ -14542,17 +14485,19 @@ public final class ActivityManagerService extends ActivityManagerNative
final boolean updateOomAdjLocked(ProcessRecord app, boolean doingProcessState) {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
- int curAdj = app.curAdj;
- final boolean wasCached = curAdj >= ProcessList.CACHED_APP_MIN_ADJ
- && curAdj <= ProcessList.CACHED_APP_MAX_ADJ;
+ final boolean wasCached = app.cached;
mAdjSeq++;
- boolean success = updateOomAdjLocked(app, app.cachedAdj, app.clientCachedAdj,
- app.emptyAdj, TOP_APP, false, doingProcessState, SystemClock.uptimeMillis());
- final boolean nowCached = app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
- && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ;
- if (nowCached != wasCached) {
+ // This is the desired cached adjusment we want to tell it to use.
+ // If our app is currently cached, we know it, and that is it. Otherwise,
+ // we don't know it yet, and it needs to now be cached we will then
+ // need to do a complete oom adj.
+ final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ
+ ? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
+ boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, doingProcessState,
+ SystemClock.uptimeMillis());
+ if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
// Changed to/from cached state, so apps after it in the LRU
// list may also be changed.
updateOomAdjLocked();
@@ -14565,6 +14510,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
final long now = SystemClock.uptimeMillis();
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
+ final int N = mLruProcesses.size();
if (false) {
RuntimeException e = new RuntimeException();
@@ -14593,7 +14539,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// them.
int numSlots = (ProcessList.CACHED_APP_MAX_ADJ
- ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;
- int numEmptyProcs = mLruProcesses.size()- mNumNonCachedProcs - mNumCachedHiddenProcs;
+ int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;
if (numEmptyProcs > cachedProcessLimit) {
// If there are more empty processes than our limit on cached
// processes, then use the cached process limit for the factor.
@@ -14618,80 +14564,97 @@ public final class ActivityManagerService extends ActivityManagerNative
// First update the OOM adjustment for each of the
// application processes based on their current state.
- int i = mLruProcesses.size();
int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
int curClientCachedAdj = curEmptyAdj;
- boolean changed = false;
- while (i > 0) {
- i--;
+ for (int i=0; i<N; i++) {
ProcessRecord app = mLruProcesses.get(i);
- //Slog.i(TAG, "OOM " + app + ": cur cached=" + curCachedAdj);
- app.setAdjChanged = false;
- updateOomAdjLocked(app, curCachedAdj, curClientCachedAdj, curEmptyAdj, TOP_APP,
- true, false, now);
- changed |= app.setAdjChanged;
- if (!app.killedBackground) {
- if (app.curRawAdj == curCachedAdj && app.hasActivities) {
- // This process was assigned as a cached process... step the
- // cached level.
- mNumCachedHiddenProcs++;
- if (curCachedAdj != nextCachedAdj) {
- stepCached++;
- if (stepCached >= cachedFactor) {
- stepCached = 0;
- curCachedAdj = nextCachedAdj;
- nextCachedAdj += 2;
- if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
- nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
- }
- if (curClientCachedAdj <= curCachedAdj) {
- curClientCachedAdj = curCachedAdj + 1;
- if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
- curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ if (!app.killedBackground && app.thread != null) {
+ app.procStateChanged = false;
+ final boolean wasKeeping = app.keeping;
+ computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
+
+ // If we haven't yet assigned the final cached adj
+ // to the process, do that now.
+ if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
+ switch (app.curProcState) {
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ // This process is a cached process holding activities...
+ // assign it the next cached value for that type, and then
+ // step that cached level.
+ app.curRawAdj = curCachedAdj;
+ app.curAdj = app.modifyRawOomAdj(curCachedAdj);
+ if (curCachedAdj != nextCachedAdj) {
+ stepCached++;
+ if (stepCached >= cachedFactor) {
+ stepCached = 0;
+ curCachedAdj = nextCachedAdj;
+ nextCachedAdj += 2;
+ if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ }
+ if (curClientCachedAdj <= curCachedAdj) {
+ curClientCachedAdj = curCachedAdj + 1;
+ if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ }
+ }
}
}
- }
- }
- numCached++;
- if (numCached > cachedProcessLimit) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): cached #" + numCached);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
- }
- } else if (app.curRawAdj == curCachedAdj && app.hasClientActivities) {
- // This process has a client that has activities. We will have
- // given it the current cached adj; here we will just leave it
- // without stepping the cached adj.
- curClientCachedAdj++;
- if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
- curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
- }
- } else {
- if (app.curRawAdj == curEmptyAdj || app.curRawAdj == curCachedAdj) {
- // This process was assigned as an empty process... step the
- // empty level.
- if (curEmptyAdj != nextEmptyAdj) {
- stepEmpty++;
- if (stepEmpty >= emptyFactor) {
- stepEmpty = 0;
- curEmptyAdj = nextEmptyAdj;
- nextEmptyAdj += 2;
- if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
- nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ // Special case for cached client processes... just step
+ // down from after regular cached processes.
+ app.curRawAdj = curClientCachedAdj;
+ app.curAdj = app.modifyRawOomAdj(curClientCachedAdj);
+ curClientCachedAdj++;
+ if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ }
+ break;
+ default:
+ // For everything else, assign next empty cached process
+ // level and bump that up. Note that this means that
+ // long-running services that have dropped down to the
+ // cached level will be treated as empty (since their process
+ // state is still as a service), which is what we want.
+ app.curRawAdj = curEmptyAdj;
+ app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
+ if (curEmptyAdj != nextEmptyAdj) {
+ stepEmpty++;
+ if (stepEmpty >= emptyFactor) {
+ stepEmpty = 0;
+ curEmptyAdj = nextEmptyAdj;
+ nextEmptyAdj += 2;
+ if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {
+ nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ }
}
}
- }
- } else if (app.curRawAdj < ProcessList.CACHED_APP_MIN_ADJ) {
- mNumNonCachedProcs++;
+ break;
}
- if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
- && !app.hasClientActivities) {
+ }
+
+ applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now);
+
+ // Count the number of process types.
+ switch (app.curProcState) {
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ mNumCachedHiddenProcs++;
+ numCached++;
+ if (numCached > cachedProcessLimit) {
+ Slog.i(TAG, "No longer want " + app.processName
+ + " (pid " + app.pid + "): cached #" + numCached);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
+ app.processName, app.setAdj, "too many background");
+ app.killedBackground = true;
+ Process.killProcessQuiet(app.pid);
+ }
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
if (numEmpty > ProcessList.TRIM_EMPTY_APPS
&& app.lastActivityTime < oldTime) {
Slog.i(TAG, "No longer want " + app.processName
@@ -14713,8 +14676,12 @@ public final class ActivityManagerService extends ActivityManagerNative
Process.killProcessQuiet(app.pid);
}
}
- }
+ break;
+ default:
+ mNumNonCachedProcs++;
+ break;
}
+
if (app.isolated && app.services.size() <= 0) {
// If this is an isolated process, and there are no
// services running in it, then the process is no longer
@@ -14729,8 +14696,8 @@ 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
+
+ if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedBackground) {
numTrimming++;
}
@@ -14745,11 +14712,10 @@ public final class ActivityManagerService extends ActivityManagerNative
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we'll let them use whatever
// memory they want.
- int memFactor = ProcessTracker.ADJ_MEM_FACTOR_NORMAL;
+ boolean allChanged;
if (numCached <= ProcessList.TRIM_CACHED_APPS
&& numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
final int numCachedAndEmpty = numCached + numEmpty;
- final int N = mLruProcesses.size();
int factor = numTrimming/3;
int minFactor = 2;
if (mHomeProcess != null) minFactor++;
@@ -14757,6 +14723,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (factor < minFactor) factor = minFactor;
int step = 0;
int fgTrimLevel;
+ int memFactor;
if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
memFactor = ProcessTracker.ADJ_MEM_FACTOR_CRITICAL;
@@ -14768,13 +14735,19 @@ public final class ActivityManagerService extends ActivityManagerNative
memFactor = ProcessTracker.ADJ_MEM_FACTOR_MODERATE;
}
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
- for (i=0; i<N; i++) {
+ allChanged = mProcessTracker.setMemFactorLocked(memFactor, !mSleeping, now);
+ for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if (app.nonStoppingAdj >= ProcessList.HOME_APP_ADJ
- && app.nonStoppingAdj != ProcessList.SERVICE_B_ADJ
+ if (allChanged || app.procStateChanged) {
+ app.setProcessTrackerState(memFactor, now);
+ }
+ if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedBackground) {
if (app.trimMemoryLevel < curLevel && app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of " + app.processName
+ + " to " + curLevel);
app.thread.scheduleTrimMemory(curLevel);
} catch (RemoteException e) {
}
@@ -14805,10 +14778,13 @@ public final class ActivityManagerService extends ActivityManagerNative
break;
}
}
- } else if (app.nonStoppingAdj == ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ } else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of heavy-weight " + app.processName
+ + " to " + ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
app.thread.scheduleTrimMemory(
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
} catch (RemoteException e) {
@@ -14816,14 +14792,17 @@ public final class ActivityManagerService extends ActivityManagerNative
}
app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
} else {
- if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
- && app.pendingUiClean) {
+ if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ || 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
// have it free UI resources.
final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
if (app.trimMemoryLevel < level && app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of bg-ui " + app.processName
+ + " to " + level);
app.thread.scheduleTrimMemory(level);
} catch (RemoteException e) {
}
@@ -14832,6 +14811,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of fg " + app.processName
+ + " to " + fgTrimLevel);
app.thread.scheduleTrimMemory(fgTrimLevel);
} catch (RemoteException e) {
}
@@ -14840,14 +14822,21 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
} else {
- final int N = mLruProcesses.size();
- for (i=0; i<N; i++) {
+ allChanged = mProcessTracker.setMemFactorLocked(
+ ProcessTracker.ADJ_MEM_FACTOR_NORMAL, !mSleeping, now);
+ for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
- if ((app.nonStoppingAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
- && app.pendingUiClean) {
+ if (allChanged || app.procStateChanged) {
+ app.setProcessTrackerState(ProcessTracker.ADJ_MEM_FACTOR_NORMAL, now);
+ }
+ if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ || app.systemNoUi) && app.pendingUiClean) {
if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
&& app.thread != null) {
try {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Trimming memory of ui hidden " + app.processName
+ + " to " + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
app.thread.scheduleTrimMemory(
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
} catch (RemoteException e) {
@@ -14865,16 +14854,6 @@ public final class ActivityManagerService extends ActivityManagerNative
mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish");
}
- boolean allChanged = mProcessTracker.setMemFactorLocked(memFactor, !mSleeping, now);
- if (changed || allChanged) {
- memFactor = mProcessTracker.getMemFactorLocked();
- for (i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
- if (allChanged || app.setAdjChanged) {
- app.setProcessTrackerState(TOP_APP, memFactor, now, mProcessList);
- }
- }
- }
if (allChanged) {
requestPssAllProcsLocked(now, false);
}
diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java
index 6c84b9fb1ab6..21cf266c62b1 100644
--- a/services/java/com/android/server/am/IntentBindRecord.java
+++ b/services/java/com/android/server/am/IntentBindRecord.java
@@ -19,6 +19,7 @@ package com.android.server.am;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
+import android.util.ArrayMap;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -33,8 +34,8 @@ final class IntentBindRecord {
/** The intent that is bound.*/
final Intent.FilterComparison intent; //
/** All apps that have bound to this Intent. */
- final HashMap<ProcessRecord, AppBindRecord> apps
- = new HashMap<ProcessRecord, AppBindRecord>();
+ final ArrayMap<ProcessRecord, AppBindRecord> apps
+ = new ArrayMap<ProcessRecord, AppBindRecord>();
/** Binder published from service. */
IBinder binder;
/** Set when we have initiated a request for this binder. */
@@ -62,15 +63,12 @@ final class IntentBindRecord {
pw.print(" received="); pw.print(received);
pw.print(" hasBound="); pw.print(hasBound);
pw.print(" doRebind="); pw.println(doRebind);
- if (apps.size() > 0) {
- Iterator<AppBindRecord> it = apps.values().iterator();
- while (it.hasNext()) {
- AppBindRecord a = it.next();
- pw.print(prefix); pw.print("* Client AppBindRecord{");
- pw.print(Integer.toHexString(System.identityHashCode(a)));
- pw.print(' '); pw.print(a.client); pw.println('}');
- a.dumpInIntentBind(pw, prefix + " ");
- }
+ for (int i=0; i<apps.size(); i++) {
+ AppBindRecord a = apps.valueAt(i);
+ pw.print(prefix); pw.print("* Client AppBindRecord{");
+ pw.print(Integer.toHexString(System.identityHashCode(a)));
+ pw.print(' '); pw.print(a.client); pw.println('}');
+ a.dumpInIntentBind(pw, prefix + " ");
}
}
@@ -81,12 +79,11 @@ final class IntentBindRecord {
int collectFlags() {
int flags = 0;
- if (apps.size() > 0) {
- for (AppBindRecord app : apps.values()) {
- if (app.connections.size() > 0) {
- for (ConnectionRecord conn : app.connections) {
- flags |= conn.flags;
- }
+ for (int i=apps.size()-1; i>=0; i--) {
+ AppBindRecord app = apps.valueAt(i);
+ if (app.connections.size() > 0) {
+ for (ConnectionRecord conn : app.connections) {
+ flags |= conn.flags;
}
}
}
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index 6a72e44f71f4..8b0466f94797 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -36,6 +36,11 @@ final class ProcessList {
// OOM adjustments for processes in various states:
+ // Adjustment used in certain places where we don't know it yet.
+ // (Generally this is something that is going to be cached, but we
+ // don't know the exact value in the cached range to assign yet.)
+ static final int UNKNOWN_ADJ = 16;
+
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 15;
@@ -62,14 +67,14 @@ final class ProcessList {
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 5;
- // This is a process currently hosting a backup operation. Killing it
- // is not entirely fatal but is generally a bad idea.
- static final int BACKUP_APP_ADJ = 4;
-
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
- static final int HEAVY_WEIGHT_APP_ADJ = 3;
+ static final int HEAVY_WEIGHT_APP_ADJ = 4;
+
+ // This is a process currently hosting a backup operation. Killing it
+ // is not entirely fatal but is generally a bad idea.
+ static final int BACKUP_APP_ADJ = 3;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
@@ -163,34 +168,11 @@ final class ProcessList {
private boolean mHaveDisplaySize;
- private final int[] mAdjToTrackedState = new int[CACHED_APP_MAX_ADJ+1];
-
ProcessList() {
MemInfoReader minfo = new MemInfoReader();
minfo.readMemInfo();
mTotalMemMb = minfo.getTotalSize()/(1024*1024);
updateOomLevels(0, 0, false);
- for (int i=0; i<=CACHED_APP_MAX_ADJ; i++) {
- if (i <= FOREGROUND_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_FOREGROUND;
- } else if (i <= VISIBLE_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_VISIBLE;
- } else if (i <= PERCEPTIBLE_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_PERCEPTIBLE;
- } else if (i <= BACKUP_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_BACKUP;
- } else if (i <= SERVICE_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_SERVICE;
- } else if (i <= HOME_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_HOME;
- } else if (i <= PREVIOUS_APP_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_PREVIOUS;
- } else if (i <= SERVICE_B_ADJ) {
- mAdjToTrackedState[i] = ProcessTracker.STATE_SERVICE;
- } else {
- mAdjToTrackedState[i] = ProcessTracker.STATE_CACHED;
- }
- }
}
void applyDisplaySize(WindowManagerService wm) {
@@ -256,11 +238,6 @@ final class ProcessList {
return mOomMinFree[mOomAdj.length-1] * 1024;
}
- int adjToTrackedState(int adj) {
- return adj >= FOREGROUND_APP_ADJ
- ? mAdjToTrackedState[adj] : ProcessTracker.STATE_PERSISTENT;
- }
-
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 cb9a76dcfa3e..5c1b7f2405cf 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.util.ArraySet;
import com.android.internal.os.BatteryStatsImpl;
import android.app.ActivityManager;
@@ -64,12 +65,8 @@ final class ProcessRecord {
long lruWeight; // Weight for ordering in LRU list
long lastPssTime; // Last time we requested PSS data
int maxAdj; // Maximum OOM adjustment for this process
- int cachedAdj; // If cached, this is the adjustment to use
- int clientCachedAdj; // If empty but cached client, this is the adjustment to use
- int emptyAdj; // If empty, 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
@@ -78,6 +75,7 @@ final class ProcessRecord {
int memImportance; // Importance constant computed from curAdj
int curProcState = -1; // Currently computed process state: ActivityManager.PROCESS_STATE_*
int repProcState = -1; // Last reported process state
+ int setProcState = -1; // Last set process state in process tracker
boolean serviceb; // Process currently is on the service B list
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
@@ -92,7 +90,7 @@ final class ProcessRecord {
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
- boolean setAdjChanged; // Keep track of whether we changed 'setAdj'.
+ boolean procStateChanged; // Keep track of whether we changed 'setAdj'.
String waitingToKill; // Process is waiting to be killed when in the bg; reason
IBinder forcingToForeground;// Token that is forcing this process to be foreground
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
@@ -125,15 +123,15 @@ final class ProcessRecord {
// contains HistoryRecord objects
final ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
// all ServiceRecord running in this process
- final HashSet<ServiceRecord> services = new HashSet<ServiceRecord>();
+ final ArraySet<ServiceRecord> services = new ArraySet<ServiceRecord>();
// services that are currently executing code (need to remain foreground).
- final HashSet<ServiceRecord> executingServices
- = new HashSet<ServiceRecord>();
+ final ArraySet<ServiceRecord> executingServices
+ = new ArraySet<ServiceRecord>();
// All ConnectionRecord this process holds
- final HashSet<ConnectionRecord> connections
- = new HashSet<ConnectionRecord>();
+ final ArraySet<ConnectionRecord> connections
+ = new ArraySet<ConnectionRecord>();
// all IIntentReceivers that are registered from this process.
- final HashSet<ReceiverList> receivers = new HashSet<ReceiverList>();
+ final ArraySet<ReceiverList> receivers = new ArraySet<ReceiverList>();
// class (String) -> ContentProviderRecord
final ArrayMap<String, ContentProviderRecord> pubProviders
= new ArrayMap<String, ContentProviderRecord>();
@@ -215,12 +213,8 @@ final class ProcessRecord {
pw.print(" cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
- pw.print(" cached="); pw.print(cachedAdj);
- pw.print(" client="); pw.print(clientCachedAdj);
- pw.print(" empty="); pw.print(emptyAdj);
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);
@@ -228,7 +222,8 @@ final class ProcessRecord {
pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
- pw.print(" repProcState="); pw.println(repProcState);
+ pw.print(" repProcState="); pw.print(repProcState);
+ pw.print(" setProcState="); pw.println(setProcState);
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.print(lruSeq);
pw.print(" lastPssTime="); pw.println(lastPssTime);
@@ -301,20 +296,20 @@ final class ProcessRecord {
}
if (services.size() > 0) {
pw.print(prefix); pw.println("Services:");
- for (ServiceRecord sr : services) {
- pw.print(prefix); pw.print(" - "); pw.println(sr);
+ for (int i=0; i<services.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(services.valueAt(i));
}
}
if (executingServices.size() > 0) {
pw.print(prefix); pw.println("Executing Services:");
- for (ServiceRecord sr : executingServices) {
- pw.print(prefix); pw.print(" - "); pw.println(sr);
+ for (int i=0; i<executingServices.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(executingServices.valueAt(i));
}
}
if (connections.size() > 0) {
pw.print(prefix); pw.println("Connections:");
- for (ConnectionRecord cr : connections) {
- pw.print(prefix); pw.print(" - "); pw.println(cr);
+ for (int i=0; i<connections.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(connections.valueAt(i));
}
}
if (pubProviders.size() > 0) {
@@ -335,8 +330,8 @@ final class ProcessRecord {
}
if (receivers.size() > 0) {
pw.print(prefix); pw.println("Receivers:");
- for (ReceiverList rl : receivers) {
- pw.print(prefix); pw.print(" - "); pw.println(rl);
+ for (int i=0; i<receivers.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(receivers.valueAt(i));
}
}
}
@@ -353,8 +348,7 @@ final class ProcessRecord {
baseProcessTracker = tracker;
pkgList.put(_info.packageName, tracker);
thread = _thread;
- maxAdj = ProcessList.CACHED_APP_MAX_ADJ;
- cachedAdj = clientCachedAdj = emptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
+ maxAdj = ProcessList.UNKNOWN_ADJ;
curRawAdj = setRawAdj = -100;
curAdj = setAdj = -100;
persistent = false;
@@ -400,14 +394,35 @@ final class ProcessRecord {
void updateHasAboveClientLocked() {
hasAboveClient = false;
- if (connections.size() > 0) {
- for (ConnectionRecord cr : connections) {
- if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) {
- hasAboveClient = true;
- break;
- }
+ for (int i=connections.size()-1; i>=0; i--) {
+ ConnectionRecord cr = connections.valueAt(i);
+ if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ hasAboveClient = true;
+ break;
+ }
+ }
+ }
+
+ int modifyRawOomAdj(int adj) {
+ if (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 < ProcessList.FOREGROUND_APP_ADJ) {
+ // System process will not get dropped, ever
+ } else if (adj < ProcessList.VISIBLE_APP_ADJ) {
+ adj = ProcessList.VISIBLE_APP_ADJ;
+ } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
+ adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
+ adj = ProcessList.CACHED_APP_MIN_ADJ;
+ } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
+ adj++;
}
}
+ return adj;
}
public String toShortString() {
@@ -483,11 +498,8 @@ final class ProcessRecord {
}
}
- public void setProcessTrackerState(ProcessRecord TOP_APP, int memFactor, long now,
- ProcessList plist) {
- int state = this == TOP_APP ? ProcessTracker.STATE_TOP
- : plist.adjToTrackedState(getSetAdjWithServices());
- baseProcessTracker.setState(state, memFactor, now, pkgList);
+ public void setProcessTrackerState(int memFactor, long now) {
+ baseProcessTracker.setState(repProcState, memFactor, now, pkgList);
}
/*
diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java
index 0ea93e828a92..ef032ba51330 100644
--- a/services/java/com/android/server/am/ProcessTracker.java
+++ b/services/java/com/android/server/am/ProcessTracker.java
@@ -52,26 +52,34 @@ public final class ProcessTracker {
public static final int STATE_NOTHING = -1;
public static final int STATE_PERSISTENT = 0;
public static final int STATE_TOP = 1;
- public static final int STATE_FOREGROUND = 2;
- public static final int STATE_VISIBLE = 3;
- public static final int STATE_PERCEPTIBLE = 4;
- public static final int STATE_BACKUP = 5;
+ public static final int STATE_IMPORTANT_FOREGROUND = 2;
+ public static final int STATE_IMPORTANT_BACKGROUND = 3;
+ public static final int STATE_BACKUP = 4;
+ public static final int STATE_HEAVY_WEIGHT = 5;
public static final int STATE_SERVICE = 6;
- public static final int STATE_HOME = 7;
- public static final int STATE_PREVIOUS = 8;
- public static final int STATE_CACHED = 9;
- public static final int STATE_COUNT = STATE_CACHED+1;
-
- static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT, STATE_TOP,
- STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE, STATE_BACKUP,
- STATE_SERVICE, STATE_HOME, STATE_PREVIOUS, STATE_CACHED
+ public static final int STATE_RECEIVER = 7;
+ public static final int STATE_HOME = 8;
+ public static final int STATE_LAST_ACTIVITY = 9;
+ public static final int STATE_CACHED_ACTIVITY = 10;
+ public static final int STATE_CACHED_ACTIVITY_CLIENT = 11;
+ public static final int STATE_CACHED_EMPTY = 12;
+ public static final int STATE_COUNT = STATE_CACHED_EMPTY+1;
+
+ static final int[] ALL_PROC_STATES = new int[] { STATE_PERSISTENT,
+ STATE_TOP, STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND,
+ STATE_BACKUP, STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_RECEIVER,
+ STATE_HOME, STATE_LAST_ACTIVITY, STATE_CACHED_ACTIVITY,
+ STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
};
public static final int PSS_SAMPLE_COUNT = 0;
public static final int PSS_MINIMUM = 1;
public static final int PSS_AVERAGE = 2;
public static final int PSS_MAXIMUM = 3;
- public static final int PSS_COUNT = PSS_MAXIMUM+1;
+ public static final int PSS_USS_MINIMUM = 4;
+ public static final int PSS_USS_AVERAGE = 5;
+ public static final int PSS_USS_MAXIMUM = 6;
+ public static final int PSS_COUNT = PSS_USS_MAXIMUM+1;
public static final int ADJ_NOTHING = -1;
public static final int ADJ_MEM_FACTOR_NORMAL = 0;
@@ -106,8 +114,9 @@ public final class ProcessTracker {
static int OFFSET_INDEX_MASK = 0xffff;
static final String[] STATE_NAMES = new String[] {
- "Persistent ", "Top ", "Foreground ", "Visible ", "Perceptible",
- "Backup ", "Service ", "Home ", "Previous ", "Cached "
+ "Persistent", "Top ", "Imp Fg ", "Imp Bg ",
+ "Backup ", "Heavy Wght", "Service ", "Receiver ", "Home ",
+ "Last Act ", "Cch Actvty", "Cch Client", "Cch Empty "
};
static final String[] ADJ_SCREEN_NAMES_CSV = new String[] {
@@ -119,8 +128,9 @@ public final class ProcessTracker {
};
static final String[] STATE_NAMES_CSV = new String[] {
- "pers", "top", "fore", "vis", "percept",
- "backup", "service", "home", "prev", "cached"
+ "pers", "top", "impfg", "impbg", "backup", "heavy",
+ "service", "receiver", "home", "lastact",
+ "cch-activity", "cch-aclient", "cch-empty"
};
static final String[] ADJ_SCREEN_TAGS = new String[] {
@@ -132,8 +142,26 @@ public final class ProcessTracker {
};
static final String[] STATE_TAGS = new String[] {
- "y", "t", "f", "v", "r",
- "b", "s", "h", "p", "c"
+ "p", "t", "f", "b", "u", "w",
+ "s", "r", "h", "l", "a", "c", "e"
+ };
+
+ // Map from process states to the states we track.
+ static final int[] PROCESS_STATE_TO_STATE = new int[] {
+ STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
+ STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
+ STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
+ STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP
+ STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+ STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE
+ STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER
+ STATE_HOME, // ActivityManager.PROCESS_STATE_HOME
+ STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
+ STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
+ STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
+ STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY
};
static final String CSV_SEP = "\t";
@@ -322,10 +350,20 @@ public final class ProcessTracker {
return true;
}
+ /**
+ * Update the current state of the given list of processes.
+ *
+ * @param state Current ActivityManager.PROCESS_STATE_*
+ * @param memFactor Current mem factor constant.
+ * @param now Current time.
+ * @param pkgList Processes to update.
+ */
public void setState(int state, int memFactor, long now,
ArrayMap<String, ProcessTracker.ProcessState> pkgList) {
- if (state != STATE_NOTHING) {
- state += memFactor*STATE_COUNT;
+ if (state < 0) {
+ state = STATE_NOTHING;
+ } else {
+ state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
}
// First update the common process.
@@ -370,7 +408,7 @@ public final class ProcessTracker {
mStartTime = now;
}
- public void addPss(long pss, boolean always) {
+ public void addPss(long pss, long uss, boolean always) {
if (!always) {
if (mLastPssState == mCurState && SystemClock.uptimeMillis()
< (mLastPssTime+(30*1000))) {
@@ -399,16 +437,27 @@ public final class ProcessTracker {
longs[idx+PSS_MINIMUM] = pss;
longs[idx+PSS_AVERAGE] = pss;
longs[idx+PSS_MAXIMUM] = pss;
+ longs[idx+PSS_USS_MINIMUM] = uss;
+ longs[idx+PSS_USS_AVERAGE] = uss;
+ longs[idx+PSS_USS_MAXIMUM] = uss;
} else {
longs[idx+PSS_SAMPLE_COUNT] = count+1;
if (longs[idx+PSS_MINIMUM] > pss) {
longs[idx+PSS_MINIMUM] = pss;
}
- longs[idx+PSS_AVERAGE] = (long)( ((longs[idx+PSS_AVERAGE]*(double)count)+pss)
- / (count+1) );
+ longs[idx+PSS_AVERAGE] = (long)(
+ ((longs[idx+PSS_AVERAGE]*(double)count)+pss) / (count+1) );
if (longs[idx+PSS_MAXIMUM] < pss) {
longs[idx+PSS_MAXIMUM] = pss;
}
+ if (longs[idx+PSS_USS_MINIMUM] > uss) {
+ longs[idx+PSS_USS_MINIMUM] = uss;
+ }
+ longs[idx+PSS_USS_AVERAGE] = (long)(
+ ((longs[idx+PSS_USS_AVERAGE]*(double)count)+uss) / (count+1) );
+ if (longs[idx+PSS_USS_MAXIMUM] < uss) {
+ longs[idx+PSS_USS_MAXIMUM] = uss;
+ }
}
}
}
@@ -480,6 +529,21 @@ public final class ProcessTracker {
int idx = State.binarySearch(mPssTable, mPssTableSize, state);
return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
}
+
+ long getPssUssMinimum(int state) {
+ int idx = State.binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
+ }
+
+ long getPssUssAverage(int state) {
+ int idx = State.binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
+ }
+
+ long getPssUssMaximum(int state) {
+ int idx = State.binarySearch(mPssTable, mPssTableSize, state);
+ return idx >= 0 ? mState.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
+ }
}
public static final class ServiceState {
@@ -589,10 +653,13 @@ public final class ProcessTracker {
static final class State {
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 3;
+ private static final int PARCEL_VERSION = 6;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535453;
+ static final int FLAG_COMPLETE = 1<<0;
+ static final int FLAG_SHUTDOWN = 1<<1;
+
final File mBaseDir;
final ProcessTracker mProcessTracker;
AtomicFile mFile;
@@ -603,6 +670,7 @@ public final class ProcessTracker {
long mTimePeriodStartRealtime;
long mTimePeriodEndRealtime;
boolean mRunning;
+ int mFlags;
final ProcessMap<PackageState> mPackages = new ProcessMap<PackageState>();
final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
@@ -690,6 +758,7 @@ public final class ProcessTracker {
Arrays.fill(mMemFactorDurations, 0);
mMemFactor = STATE_NOTHING;
mStartTime = 0;
+ mReadError = null;
}
private void buildTimePeriodStartClockStr() {
@@ -724,7 +793,7 @@ public final class ProcessTracker {
}
}
- void readLocked() {
+ boolean readLocked() {
try {
FileInputStream stream = mFile.openRead();
@@ -770,11 +839,14 @@ public final class ProcessTracker {
}
}
}
+ return false;
}
} catch (Throwable e) {
- mReadError = "error reading: " + e;
+ mReadError = "caught exception: " + e;
Slog.e(TAG, "Error reading process statistics", e);
+ return false;
}
+ return true;
}
private void writeStateLocked(boolean sync, final boolean commit) {
@@ -848,6 +920,7 @@ public final class ProcessTracker {
out.writeLong(mTimePeriodStartClock);
out.writeLong(mTimePeriodStartRealtime);
out.writeLong(mTimePeriodEndRealtime);
+ out.writeInt(mFlags);
out.writeInt(mLongs.size());
out.writeInt(mNextLong);
@@ -920,7 +993,7 @@ public final class ProcessTracker {
private boolean readCheckedInt(Parcel in, int val, String what) {
int got;
if ((got=in.readInt()) != val) {
- mReadError = "bad " + ": " + got;
+ mReadError = "bad " + what + ": " + got;
return false;
}
return true;
@@ -956,6 +1029,7 @@ public final class ProcessTracker {
buildTimePeriodStartClockStr();
mTimePeriodStartRealtime = in.readLong();
mTimePeriodEndRealtime = in.readLong();
+ mFlags = in.readInt();
final int NLONGS = in.readInt();
final int NEXTLONG = in.readInt();
@@ -1365,8 +1439,9 @@ public final class ProcessTracker {
void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) {
dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
- new int[] { STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS },
+ new int[] { STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+ STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
+ STATE_SERVICE, STATE_RECEIVER, STATE_HOME, STATE_LAST_ACTIVITY },
now, reqPackage);
pw.println();
pw.println("Run time Stats:");
@@ -1379,6 +1454,9 @@ public final class ProcessTracker {
TimeUtils.formatDuration(
(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
- mTimePeriodStartRealtime, pw);
+ if ((mFlags&FLAG_COMPLETE) != 0) pw.print(" (complete)");
+ else if ((mFlags&FLAG_SHUTDOWN) != 0) pw.print(" (shutdown)");
+ else pw.print(" (partial)");
pw.println();
}
@@ -1452,10 +1530,13 @@ public final class ProcessTracker {
void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
final long now = SystemClock.uptimeMillis();
ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
- pw.println("vers,1");
+ pw.println("vers,2");
pw.print("period,"); pw.print(mTimePeriodStartClockStr);
pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
pw.print(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
+ if ((mFlags&FLAG_COMPLETE) != 0) pw.print(",complete");
+ else if ((mFlags&FLAG_SHUTDOWN) != 0) pw.print(",shutdown");
+ else pw.print(",partial");
pw.println();
for (int ip=0; ip<pkgMap.size(); ip++) {
String pkgName = pkgMap.keyAt(ip);
@@ -1629,6 +1710,7 @@ public final class ProcessTracker {
if (now > (mState.mLastWriteTime+WRITE_PERIOD)) {
if (SystemClock.elapsedRealtime() > (mState.mTimePeriodStartRealtime+COMMIT_PERIOD)) {
mCommitPending = true;
+ mState.mFlags |= State.FLAG_COMPLETE;
}
return true;
}
@@ -1637,6 +1719,7 @@ public final class ProcessTracker {
public void shutdownLocked() {
Slog.w(TAG, "Writing process stats before shutdown...");
+ mState.mFlags |= State.FLAG_SHUTDOWN;
writeStateSyncLocked();
mShuttingDown = true;
}
@@ -1841,6 +1924,9 @@ public final class ProcessTracker {
long minPss;
long avgPss;
long maxPss;
+ long minUss;
+ long avgUss;
+ long maxUss;
ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
screenStates = _screenStates;
@@ -1857,6 +1943,12 @@ public final class ProcessTracker {
printSizeValue(pw, avgPss * 1024);
pw.print("-");
printSizeValue(pw, maxPss * 1024);
+ pw.print("/");
+ printSizeValue(pw, minUss * 1024);
+ pw.print("-");
+ printSizeValue(pw, avgUss * 1024);
+ pw.print("-");
+ printSizeValue(pw, maxUss * 1024);
if (full) {
pw.print(" over ");
pw.print(numPss);
@@ -1868,7 +1960,8 @@ public final class ProcessTracker {
static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
data.totalTime = 0;
- data.numPss = data.minPss = data.avgPss = data.maxPss = 0;
+ data.numPss = data.minPss = data.avgPss = data.maxPss =
+ data.minUss = data.avgUss = data.maxUss = 0;
for (int is=0; is<data.screenStates.length; is++) {
for (int im=0; im<data.memStates.length; im++) {
for (int ip=0; ip<data.procStates.length; ip++) {
@@ -1880,10 +1973,16 @@ public final class ProcessTracker {
long minPss = proc.getPssMinimum(bucket);
long avgPss = proc.getPssAverage(bucket);
long maxPss = proc.getPssMaximum(bucket);
+ long minUss = proc.getPssUssMinimum(bucket);
+ long avgUss = proc.getPssUssAverage(bucket);
+ long maxUss = proc.getPssUssMaximum(bucket);
if (data.numPss == 0) {
data.minPss = minPss;
data.avgPss = avgPss;
data.maxPss = maxPss;
+ data.minUss = minUss;
+ data.avgUss = avgUss;
+ data.maxUss = maxUss;
} else {
if (minPss < data.minPss) {
data.minPss = minPss;
@@ -1893,6 +1992,14 @@ public final class ProcessTracker {
if (maxPss > data.maxPss) {
data.maxPss = maxPss;
}
+ if (minUss < data.minUss) {
+ data.minUss = minUss;
+ }
+ data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
+ + (avgUss*(double)samples)) / (data.numPss+samples) );
+ if (maxUss > data.maxUss) {
+ data.maxUss = maxUss;
+ }
}
data.numPss += samples;
}
@@ -1989,7 +2096,7 @@ public final class ProcessTracker {
if (count > 0) {
if (!printedHeader) {
pw.print(prefix);
- pw.print("PSS (");
+ pw.print("PSS/USS (");
pw.print(proc.mPssTableSize);
pw.println(" entries):");
printedHeader = true;
@@ -2013,6 +2120,12 @@ public final class ProcessTracker {
printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
pw.print(" ");
printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
+ pw.print(" / ");
+ printSizeValue(pw, proc.getPssUssMinimum(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssUssAverage(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssUssMaximum(bucket) * 1024);
pw.println();
}
}
@@ -2148,21 +2261,28 @@ public final class ProcessTracker {
dumpProcessSummaryDetails(pw, proc, prefix, " TOTAL: ", screenStates, memStates,
procStates, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Persistent: ", screenStates, memStates,
- new int[] {STATE_PERSISTENT}, now, true);
+ new int[] { STATE_PERSISTENT }, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Top: ", screenStates, memStates,
new int[] {STATE_TOP}, now, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Foreground: ", screenStates, memStates,
- new int[] {STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Imp Fg: ", screenStates, memStates,
+ new int[] { STATE_IMPORTANT_FOREGROUND }, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Imp Bg: ", screenStates, memStates,
+ new int[] {STATE_IMPORTANT_BACKGROUND}, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Backup: ", screenStates, memStates,
new int[] {STATE_BACKUP}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Heavy Wgt: ", screenStates, memStates,
+ new int[] {STATE_HEAVY_WEIGHT}, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Service: ", screenStates, memStates,
new int[] {STATE_SERVICE}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Receiver: ", screenStates, memStates,
+ new int[] {STATE_RECEIVER}, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " Home: ", screenStates, memStates,
new int[] {STATE_HOME}, now, true);
- dumpProcessSummaryDetails(pw, proc, prefix, " Previous: ", screenStates, memStates,
- new int[] {STATE_PREVIOUS}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Last Act: ", screenStates, memStates,
+ new int[] {STATE_LAST_ACTIVITY}, now, true);
dumpProcessSummaryDetails(pw, proc, prefix, " (Cached): ", screenStates, memStates,
- new int[] {STATE_CACHED}, now, true);
+ new int[] {STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_ACTIVITY_CLIENT,
+ STATE_CACHED_EMPTY}, now, true);
}
}
@@ -2193,9 +2313,9 @@ public final class ProcessTracker {
if (result < 1) {
value = String.format("%.2f", result);
} else if (result < 10) {
- value = String.format("%.2f", result);
+ value = String.format("%.1f", result);
} else if (result < 100) {
- value = String.format("%.2f", result);
+ value = String.format("%.0f", result);
} else {
value = String.format("%.0f", result);
}
@@ -2300,6 +2420,9 @@ public final class ProcessTracker {
long min = proc.mState.getLong(off, PSS_MINIMUM);
long avg = proc.mState.getLong(off, PSS_AVERAGE);
long max = proc.mState.getLong(off, PSS_MAXIMUM);
+ long umin = proc.mState.getLong(off, PSS_USS_MINIMUM);
+ long uavg = proc.mState.getLong(off, PSS_USS_AVERAGE);
+ long umax = proc.mState.getLong(off, PSS_USS_MAXIMUM);
pw.print(',');
printProcStateTag(pw, type);
pw.print(':');
@@ -2310,6 +2433,12 @@ public final class ProcessTracker {
pw.print(avg);
pw.print(':');
pw.print(max);
+ pw.print(':');
+ pw.print(umin);
+ pw.print(':');
+ pw.print(uavg);
+ pw.print(':');
+ pw.print(umax);
}
}
@@ -2391,9 +2520,10 @@ public final class ProcessTracker {
int[] csvMemStats = new int[] {ADJ_MEM_FACTOR_CRITICAL};
boolean csvSepProcStats = true;
int[] csvProcStats = new int[] {
- STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
- STATE_PREVIOUS, STATE_CACHED };
+ STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+ STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT, STATE_SERVICE,
+ STATE_RECEIVER, STATE_HOME, STATE_LAST_ACTIVITY,
+ STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY };
if (args != null) {
for (int i=0; i<args.length; i++) {
String arg = args[i];
@@ -2457,6 +2587,7 @@ public final class ProcessTracker {
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
+ mState.mFlags |= State.FLAG_COMPLETE;
mState.writeStateLocked(true, true);
pw.println("Process stats committed.");
return;
@@ -2557,6 +2688,13 @@ public final class ProcessTracker {
if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
try {
State state = new State(files.get(i));
+ if (state.mReadError != null) {
+ pw.print("Failure reading "); pw.print(files.get(i));
+ pw.print("; "); pw.println(state.mReadError);
+ if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
+ (new File(files.get(i))).delete();
+ continue;
+ }
String fileStr = state.mFile.getBaseFile().getPath();
boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
if (isCheckin || isCompact) {
@@ -2588,7 +2726,6 @@ public final class ProcessTracker {
pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
e.printStackTrace(pw);
}
- if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
}
}
} finally {