summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2013-09-13 17:30:31 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2013-09-13 17:30:31 -0700
commit1cd9a73ac020bfb2db32da3c8e853c4a514be858 (patch)
tree819064ab194582cce792c5f93a6262db6ce1f5ae /services
parent078c1f3606c3327e604bf2ccd775a9410684d192 (diff)
parentf3b4cf7d01b68418dd652e201868d140de081bd8 (diff)
downloadframeworks_base-1cd9a73ac020bfb2db32da3c8e853c4a514be858.zip
frameworks_base-1cd9a73ac020bfb2db32da3c8e853c4a514be858.tar.gz
frameworks_base-1cd9a73ac020bfb2db32da3c8e853c4a514be858.tar.bz2
am f3b4cf7d: am 28eeb420: Merge "Implement #10749688: Improve low memory reporting" into klp-dev
* commit 'f3b4cf7d01b68418dd652e201868d140de081bd8': Implement #10749688: Improve low memory reporting
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/am/ActiveServices.java13
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java497
-rw-r--r--services/java/com/android/server/am/ProcessList.java109
-rw-r--r--services/java/com/android/server/am/ProcessMemInfo.java37
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java6
5 files changed, 425 insertions, 237 deletions
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 4521037..b4d9da0 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -328,8 +328,17 @@ public final class ActiveServices {
addToStarting = true;
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STATS) {
- Slog.v(TAG, "Not potential delay (state=" + proc.curProcState
- + " " + proc.makeAdjReason() + "): " + r);
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Not potential delay (state=").append(proc.curProcState)
+ .append(' ').append(proc.adjType);
+ String reason = proc.makeAdjReason();
+ if (reason != null) {
+ sb.append(' ');
+ sb.append(reason);
+ }
+ sb.append("): ");
+ sb.append(r.toString());
+ Slog.v(TAG, sb.toString());
}
} else if (DEBUG_DELAYED_STATS) {
if (callerFg) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 66ca19d..3e7b7d1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1370,64 +1370,167 @@ public final class ActivityManagerService extends ActivityManagerNative
break;
}
case REPORT_MEM_USAGE: {
- boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
- if (!isDebuggable) {
- return;
- }
- synchronized (ActivityManagerService.this) {
- long now = SystemClock.uptimeMillis();
- if (now < (mLastMemUsageReportTime+5*60*1000)) {
- // Don't report more than every 5 minutes to somewhat
- // avoid spamming.
- return;
- }
- mLastMemUsageReportTime = now;
- }
+ final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
Thread thread = new Thread() {
@Override public void run() {
- StringBuilder dropBuilder = new StringBuilder(1024);
+ final SparseArray<ProcessMemInfo> infoMap
+ = new SparseArray<ProcessMemInfo>(memInfos.size());
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ infoMap.put(mi.pid, mi);
+ }
+ updateCpuStatsNow();
+ synchronized (mProcessCpuThread) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.vsize > 0) {
+ long pss = Debug.getPss(st.pid, null);
+ if (pss > 0) {
+ if (infoMap.indexOfKey(st.pid) < 0) {
+ ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+ ProcessList.NATIVE_ADJ, -1, "native", null);
+ mi.pss = pss;
+ memInfos.add(mi);
+ }
+ }
+ }
+ }
+ }
+
+ long totalPss = 0;
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ if (mi.pss == 0) {
+ mi.pss = Debug.getPss(mi.pid, null);
+ }
+ totalPss += mi.pss;
+ }
+ Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
+ @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
+ if (lhs.oomAdj != rhs.oomAdj) {
+ return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
+ }
+ if (lhs.pss != rhs.pss) {
+ return lhs.pss < rhs.pss ? 1 : -1;
+ }
+ return 0;
+ }
+ });
+
+ StringBuilder tag = new StringBuilder(128);
+ StringBuilder stack = new StringBuilder(128);
+ tag.append("Low on memory -- ");
+ appendMemBucket(tag, totalPss, "total", false);
+ appendMemBucket(stack, totalPss, "total", true);
+
StringBuilder logBuilder = new StringBuilder(1024);
+ logBuilder.append("Low on memory:\n");
+
+ boolean firstLine = true;
+ int lastOomAdj = Integer.MIN_VALUE;
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+
+ if (mi.oomAdj != ProcessList.NATIVE_ADJ
+ && (mi.oomAdj < ProcessList.SERVICE_ADJ
+ || mi.oomAdj == ProcessList.HOME_APP_ADJ
+ || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
+ if (lastOomAdj != mi.oomAdj) {
+ lastOomAdj = mi.oomAdj;
+ if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ tag.append(" / ");
+ }
+ if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+ if (firstLine) {
+ stack.append(":");
+ firstLine = false;
+ }
+ stack.append("\n\t at ");
+ } else {
+ stack.append("$");
+ }
+ } else {
+ tag.append(" ");
+ stack.append("$");
+ }
+ if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ appendMemBucket(tag, mi.pss, mi.name, false);
+ }
+ appendMemBucket(stack, mi.pss, mi.name, true);
+ if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
+ && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
+ stack.append("(");
+ for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
+ if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
+ stack.append(DUMP_MEM_OOM_LABEL[k]);
+ stack.append(":");
+ stack.append(DUMP_MEM_OOM_ADJ[k]);
+ }
+ }
+ stack.append(")");
+ }
+ }
+
+ logBuilder.append(" ");
+ logBuilder.append(ProcessList.makeOomAdjString(mi.oomAdj));
+ logBuilder.append(' ');
+ logBuilder.append(ProcessList.makeProcStateString(mi.procState));
+ logBuilder.append(' ');
+ ProcessList.appendRamKb(logBuilder, mi.pss);
+ logBuilder.append(" kB: ");
+ logBuilder.append(mi.name);
+ logBuilder.append(" (");
+ logBuilder.append(mi.pid);
+ logBuilder.append(") ");
+ logBuilder.append(mi.adjType);
+ logBuilder.append('\n');
+ if (mi.adjReason != null) {
+ logBuilder.append(" ");
+ logBuilder.append(mi.adjReason);
+ logBuilder.append('\n');
+ }
+ }
+
+ logBuilder.append(" ");
+ ProcessList.appendRamKb(logBuilder, totalPss);
+ logBuilder.append(" kB: TOTAL\n");
+
+ long[] infos = new long[Debug.MEMINFO_COUNT];
+ Debug.getMemInfo(infos);
+ logBuilder.append(" MemInfo: ");
+ logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
+ logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
+ logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
+ logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
+ logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
+
+ Slog.i(TAG, logBuilder.toString());
+
+ StringBuilder dropBuilder = new StringBuilder(1024);
+ /*
StringWriter oomSw = new StringWriter();
PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
StringWriter catSw = new StringWriter();
PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
String[] emptyArgs = new String[] { };
- StringBuilder tag = new StringBuilder(128);
- StringBuilder stack = new StringBuilder(128);
- tag.append("Low on memory -- ");
- dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw,
- tag, stack);
+ dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw);
+ oomPw.flush();
+ String oomString = oomSw.toString();
+ */
dropBuilder.append(stack);
dropBuilder.append('\n');
dropBuilder.append('\n');
- oomPw.flush();
- String oomString = oomSw.toString();
+ dropBuilder.append(logBuilder);
+ dropBuilder.append('\n');
+ /*
dropBuilder.append(oomString);
dropBuilder.append('\n');
- logBuilder.append(oomString);
- try {
- java.lang.Process proc = Runtime.getRuntime().exec(new String[] {
- "procrank", });
- final InputStreamReader converter = new InputStreamReader(
- proc.getInputStream());
- BufferedReader in = new BufferedReader(converter);
- String line;
- while (true) {
- line = in.readLine();
- if (line == null) {
- break;
- }
- if (line.length() > 0) {
- logBuilder.append(line);
- logBuilder.append('\n');
- }
- dropBuilder.append(line);
- dropBuilder.append('\n');
- }
- converter.close();
- } catch (IOException e) {
- }
+ */
+ StringWriter catSw = new StringWriter();
synchronized (ActivityManagerService.this) {
+ PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+ String[] emptyArgs = new String[] { };
catPw.println();
dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
catPw.println();
@@ -1435,12 +1538,13 @@ public final class ActivityManagerService extends ActivityManagerNative
false, false, null);
catPw.println();
dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
+ catPw.flush();
}
- catPw.flush();
dropBuilder.append(catSw.toString());
addErrorToDropBox("lowmem", null, "system_server", null,
null, tag.toString(), dropBuilder.toString(), null, null);
- Slog.i(TAG, logBuilder.toString());
+ //Slog.i(TAG, "Sent to dropbox:");
+ //Slog.i(TAG, dropBuilder.toString());
synchronized (ActivityManagerService.this) {
long now = SystemClock.uptimeMillis();
if (mLastMemUsageReportTime < now) {
@@ -1691,8 +1795,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args,
- false, null, null, null);
+ mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
}
}
@@ -3276,6 +3379,66 @@ public final class ActivityManagerService extends ActivityManagerNative
return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
}
+ final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
+ // If there are no longer any background processes running,
+ // and the app that died was not running instrumentation,
+ // then tell everyone we are now low on memory.
+ boolean haveBg = false;
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord rec = mLruProcesses.get(i);
+ if (rec.thread != null
+ && rec.setProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+ haveBg = true;
+ break;
+ }
+ }
+
+ if (!haveBg) {
+ boolean doReport = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (doReport) {
+ long now = SystemClock.uptimeMillis();
+ if (now < (mLastMemUsageReportTime+5*60*1000)) {
+ doReport = false;
+ } else {
+ mLastMemUsageReportTime = now;
+ }
+ }
+ final ArrayList<ProcessMemInfo> memInfos
+ = doReport ? new ArrayList<ProcessMemInfo>(mLruProcesses.size()) : null;
+ EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
+ long now = SystemClock.uptimeMillis();
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord rec = mLruProcesses.get(i);
+ if (rec == dyingProc || rec.thread == null) {
+ continue;
+ }
+ if (doReport) {
+ memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
+ rec.setProcState, rec.adjType, rec.makeAdjReason()));
+ }
+ if ((rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
+ // The low memory report is overriding any current
+ // state for a GC request. Make sure to do
+ // heavy/important/visible/foreground processes first.
+ if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ rec.lastRequestedGc = 0;
+ } else {
+ rec.lastRequestedGc = rec.lastLowMemory;
+ }
+ rec.reportLowMemory = true;
+ rec.lastLowMemory = now;
+ mProcessesToGc.remove(rec);
+ addProcessToGcListLocked(rec);
+ }
+ }
+ if (doReport) {
+ Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE, memInfos);
+ mHandler.sendMessage(msg);
+ }
+ scheduleAppGcsLocked();
+ }
+ }
+
final void appDiedLocked(ProcessRecord app, int pid,
IApplicationThread thread) {
@@ -3301,42 +3464,7 @@ public final class ActivityManagerService extends ActivityManagerNative
handleAppDiedLocked(app, false, true);
if (doLowMem) {
- // If there are no longer any background processes running,
- // and the app that died was not running instrumentation,
- // then tell everyone we are now low on memory.
- boolean haveBg = false;
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord rec = mLruProcesses.get(i);
- if (rec.thread != null && rec.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
- haveBg = true;
- break;
- }
- }
-
- if (!haveBg) {
- EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
- long now = SystemClock.uptimeMillis();
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord rec = mLruProcesses.get(i);
- if (rec != app && rec.thread != null &&
- (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
- // The low memory report is overriding any current
- // state for a GC request. Make sure to do
- // heavy/important/visible/foreground processes first.
- if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
- rec.lastRequestedGc = 0;
- } else {
- rec.lastRequestedGc = rec.lastLowMemory;
- }
- rec.reportLowMemory = true;
- rec.lastLowMemory = now;
- mProcessesToGc.remove(rec);
- addProcessToGcListLocked(rec);
- }
- }
- mHandler.sendEmptyMessage(REPORT_MEM_USAGE);
- scheduleAppGcsLocked();
- }
+ doLowMemReportIfNeededLocked(app);
}
} else if (app.pid != pid) {
// A new process has already been started.
@@ -3855,6 +3983,8 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), false, true, "kill all background");
}
+ updateOomAdjLocked();
+ doLowMemReportIfNeededLocked(null);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -4164,6 +4294,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
}
+ updateOomAdjLocked();
return N > 0;
}
@@ -10796,14 +10927,6 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private static String buildOomTag(String prefix, String space, int val, int base) {
- if (val == base) {
- if (space == null) return prefix;
- return prefix + " ";
- }
- return prefix + "+" + Integer.toString(val-base);
- }
-
private static final int dumpProcessList(PrintWriter pw,
ActivityManagerService service, List list,
String prefix, String normalLabel, String persistentLabel,
@@ -10875,34 +10998,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int i=list.size()-1; i>=0; i--) {
ProcessRecord r = list.get(i).first;
- String oomAdj;
- if (r.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
- oomAdj = buildOomTag("cch", " ", r.setAdj, ProcessList.CACHED_APP_MIN_ADJ);
- } else if (r.setAdj >= ProcessList.SERVICE_B_ADJ) {
- oomAdj = buildOomTag("svcb ", null, r.setAdj, ProcessList.SERVICE_B_ADJ);
- } else if (r.setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
- oomAdj = buildOomTag("prev ", null, r.setAdj, ProcessList.PREVIOUS_APP_ADJ);
- } else if (r.setAdj >= ProcessList.HOME_APP_ADJ) {
- 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.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) {
- oomAdj = buildOomTag("vis ", null, r.setAdj, ProcessList.VISIBLE_APP_ADJ);
- } else if (r.setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
- oomAdj = buildOomTag("fore ", null, r.setAdj, ProcessList.FOREGROUND_APP_ADJ);
- } else if (r.setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
- oomAdj = buildOomTag("pers ", null, r.setAdj, ProcessList.PERSISTENT_PROC_ADJ);
- } else if (r.setAdj >= ProcessList.SYSTEM_ADJ) {
- oomAdj = buildOomTag("sys ", null, r.setAdj, ProcessList.SYSTEM_ADJ);
- } else {
- oomAdj = Integer.toString(r.setAdj);
- }
+ String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
char schedGroup;
switch (r.setSchedGroup) {
case Process.THREAD_GROUP_BG_NONINTERACTIVE:
@@ -10923,54 +11019,7 @@ public final class ActivityManagerService extends ActivityManagerNative
} else {
foreground = ' ';
}
- String procState;
- switch (r.curProcState) {
- case ActivityManager.PROCESS_STATE_PERSISTENT:
- procState = "P ";
- break;
- case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
- procState = "PU";
- break;
- case ActivityManager.PROCESS_STATE_TOP:
- procState = "T ";
- break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
- procState = "IF";
- break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
- procState = "IB";
- 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 = "HO";
- break;
- case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
- procState = "LA";
- break;
- 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 = "??";
- break;
- }
+ String procState = ProcessList.makeProcStateString(r.curProcState);
pw.print(prefix);
pw.print(r.persistent ? persistentLabel : normalLabel);
pw.print(" #");
@@ -11258,6 +11307,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
static final int[] DUMP_MEM_OOM_ADJ = new int[] {
+ ProcessList.NATIVE_ADJ,
ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ,
ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ,
ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
@@ -11265,6 +11315,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MAX_ADJ
};
static final String[] DUMP_MEM_OOM_LABEL = new String[] {
+ "Native",
"System", "Persistent", "Foreground",
"Visible", "Perceptible",
"Heavy Weight", "Backup",
@@ -11272,6 +11323,7 @@ public final class ActivityManagerService extends ActivityManagerNative
"Previous", "B Services", "Cached"
};
static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
+ "native",
"sys", "pers", "fore",
"vis", "percept",
"heavy", "backup",
@@ -11280,8 +11332,7 @@ public final class ActivityManagerService extends ActivityManagerNative
};
final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, String prefix, String[] args, boolean brief,
- PrintWriter categoryPw, StringBuilder outTag, StringBuilder outStack) {
+ PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
boolean dumpDetails = false;
boolean dumpDalvik = false;
boolean oomOnly = false;
@@ -11342,6 +11393,7 @@ public final class ActivityManagerService extends ActivityManagerNative
System.arraycopy(args, opti, innerArgs, 0, args.length-opti);
ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+ final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
long nativePss=0, dalvikPss=0, otherPss=0;
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
@@ -11409,6 +11461,7 @@ public final class ActivityManagerService extends ActivityManagerNative
(hasActivities ? " / activities)" : ")"),
r.processName, myTotalPss, pid, hasActivities);
procMems.add(pssItem);
+ procMemsMap.put(pid, pssItem);
nativePss += mi.nativePss;
dalvikPss += mi.dalvikPss;
@@ -11439,6 +11492,48 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (!isCheckinRequest && procs.size() > 1) {
+ // If we are showing aggregations, also look for native processes to
+ // include so that our aggregations are more accurate.
+ updateCpuStatsNow();
+ synchronized (mProcessCpuThread) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ if (!brief && !oomOnly) {
+ Debug.getMemoryInfo(st.pid, mi);
+ } else {
+ mi.nativePss = (int)Debug.getPss(st.pid, tmpLong);
+ mi.nativePrivateDirty = (int)tmpLong[0];
+ }
+
+ final long myTotalPss = mi.getTotalPss();
+ totalPss += myTotalPss;
+
+ MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
+ st.name, myTotalPss, st.pid, false);
+ procMems.add(pssItem);
+
+ nativePss += mi.nativePss;
+ dalvikPss += mi.dalvikPss;
+ otherPss += mi.otherPss;
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ long mem = mi.getOtherPss(j);
+ miscPss[j] += mem;
+ otherPss -= mem;
+ }
+ oomPss[0] += myTotalPss;
+ if (oomProcs[0] == null) {
+ oomProcs[0] = new ArrayList<MemItem>();
+ }
+ oomProcs[0].add(pssItem);
+ }
+ }
+ }
+
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
catMems.add(new MemItem("Native", "Native", nativePss, -1));
@@ -11461,68 +11556,6 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- if (outTag != null || outStack != null) {
- if (outTag != null) {
- appendMemBucket(outTag, totalPss, "total", false);
- }
- if (outStack != null) {
- appendMemBucket(outStack, totalPss, "total", true);
- }
- boolean firstLine = true;
- for (int i=0; i<oomMems.size(); i++) {
- MemItem miCat = oomMems.get(i);
- if (miCat.subitems == null || miCat.subitems.size() < 1) {
- continue;
- }
- if (miCat.id < ProcessList.SERVICE_ADJ
- || miCat.id == ProcessList.HOME_APP_ADJ
- || miCat.id == ProcessList.PREVIOUS_APP_ADJ) {
- if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
- outTag.append(" / ");
- }
- if (outStack != null) {
- if (miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
- if (firstLine) {
- outStack.append(":");
- firstLine = false;
- }
- outStack.append("\n\t at ");
- } else {
- outStack.append("$");
- }
- }
- for (int j=0; j<miCat.subitems.size(); j++) {
- MemItem memi = miCat.subitems.get(j);
- if (j > 0) {
- if (outTag != null) {
- outTag.append(" ");
- }
- if (outStack != null) {
- outStack.append("$");
- }
- }
- if (outTag != null && miCat.id <= ProcessList.FOREGROUND_APP_ADJ) {
- appendMemBucket(outTag, memi.pss, memi.shortLabel, false);
- }
- if (outStack != null) {
- appendMemBucket(outStack, memi.pss, memi.shortLabel, true);
- }
- }
- if (outStack != null && miCat.id >= ProcessList.FOREGROUND_APP_ADJ) {
- outStack.append("(");
- for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
- if (DUMP_MEM_OOM_ADJ[k] == miCat.id) {
- outStack.append(DUMP_MEM_OOM_LABEL[k]);
- outStack.append(":");
- outStack.append(DUMP_MEM_OOM_ADJ[k]);
- }
- }
- outStack.append(")");
- }
- }
- }
- }
-
if (!brief && !oomOnly && !isCompact) {
pw.println();
pw.println("Total PSS by process:");
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index d4db144..c65b6ec 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -21,6 +21,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
+import android.app.ActivityManager;
import com.android.internal.util.MemInfoReader;
import com.android.server.wm.WindowManagerService;
@@ -102,6 +103,10 @@ final class ProcessList {
// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -16;
+ // Special code for native processes that are not being managed by the system (so
+ // don't have an oom adj assigned by the system).
+ static final int NATIVE_ADJ = -17;
+
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
@@ -288,6 +293,46 @@ final class ProcessList {
return (totalProcessLimit*2)/3;
}
+ private static String buildOomTag(String prefix, String space, int val, int base) {
+ if (val == base) {
+ if (space == null) return prefix;
+ return prefix + " ";
+ }
+ return prefix + "+" + Integer.toString(val-base);
+ }
+
+ public static String makeOomAdjString(int setAdj) {
+ if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+ return buildOomTag("cch", " ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
+ } else if (setAdj >= ProcessList.SERVICE_B_ADJ) {
+ return buildOomTag("svcb ", null, setAdj, ProcessList.SERVICE_B_ADJ);
+ } else if (setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
+ return buildOomTag("prev ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
+ } else if (setAdj >= ProcessList.HOME_APP_ADJ) {
+ return buildOomTag("home ", null, setAdj, ProcessList.HOME_APP_ADJ);
+ } else if (setAdj >= ProcessList.SERVICE_ADJ) {
+ return buildOomTag("svc ", null, setAdj, ProcessList.SERVICE_ADJ);
+ } else if (setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
+ return buildOomTag("hvy ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+ } else if (setAdj >= ProcessList.BACKUP_APP_ADJ) {
+ return buildOomTag("bkup ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
+ } else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
+ return buildOomTag("prcp ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+ } else if (setAdj >= ProcessList.VISIBLE_APP_ADJ) {
+ return buildOomTag("vis ", null, setAdj, ProcessList.VISIBLE_APP_ADJ);
+ } else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+ return buildOomTag("fore ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
+ } else if (setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
+ return buildOomTag("pers ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
+ } else if (setAdj >= ProcessList.SYSTEM_ADJ) {
+ return buildOomTag("sys ", null, setAdj, ProcessList.SYSTEM_ADJ);
+ } else if (setAdj >= ProcessList.NATIVE_ADJ) {
+ return buildOomTag("ntv ", null, setAdj, ProcessList.NATIVE_ADJ);
+ } else {
+ return Integer.toString(setAdj);
+ }
+ }
+
// The minimum amount of time after a state change it is safe ro collect PSS.
public static final int PSS_MIN_TIME_FROM_STATE_CHANGE = 15*1000;
@@ -376,6 +421,70 @@ final class ProcessList {
return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2];
}
+ public static String makeProcStateString(int curProcState) {
+ String procState;
+ switch (curProcState) {
+ case -1:
+ procState = "N ";
+ break;
+ case ActivityManager.PROCESS_STATE_PERSISTENT:
+ procState = "P ";
+ break;
+ case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+ procState = "PU";
+ break;
+ case ActivityManager.PROCESS_STATE_TOP:
+ procState = "T ";
+ break;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+ procState = "IF";
+ break;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+ procState = "IB";
+ 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 = "HO";
+ break;
+ case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
+ procState = "LA";
+ break;
+ 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 = "??";
+ break;
+ }
+ return procState;
+ }
+
+ public static void appendRamKb(StringBuilder sb, long ramKb) {
+ for (int j=0, fact=10; j<6; j++, fact*=10) {
+ if (ramKb < fact) {
+ sb.append(' ');
+ }
+ }
+ sb.append(ramKb);
+ }
+
public static long computeNextPssTime(int procState, boolean first, boolean sleeping,
long now) {
final long[] table = sleeping
diff --git a/services/java/com/android/server/am/ProcessMemInfo.java b/services/java/com/android/server/am/ProcessMemInfo.java
new file mode 100644
index 0000000..c94694e
--- /dev/null
+++ b/services/java/com/android/server/am/ProcessMemInfo.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+public class ProcessMemInfo {
+ final String name;
+ final int pid;
+ final int oomAdj;
+ final int procState;
+ final String adjType;
+ final String adjReason;
+ long pss;
+
+ public ProcessMemInfo(String _name, int _pid, int _oomAdj, int _procState,
+ String _adjType, String _adjReason) {
+ name = _name;
+ pid = _pid;
+ oomAdj = _oomAdj;
+ procState = _procState;
+ adjType = _adjType;
+ adjReason = _adjReason;
+ }
+}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 892271f..35e06b6 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -529,9 +529,8 @@ final class ProcessRecord {
}
public String makeAdjReason() {
- StringBuilder sb = new StringBuilder(128);
- sb.append('(').append(adjType).append(')');
if (adjSource != null || adjTarget != null) {
+ StringBuilder sb = new StringBuilder(128);
sb.append(' ');
if (adjTarget instanceof ComponentName) {
sb.append(((ComponentName)adjTarget).flattenToShortString());
@@ -550,8 +549,9 @@ final class ProcessRecord {
} else {
sb.append("{null}");
}
+ return sb.toString();
}
- return sb.toString();
+ return null;
}
/*