diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 8f68fc1a3cbcd..eb91238451e7d 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -1018,6 +1018,28 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo */ public static native long getPss(int pid, long[] outUss); + /** @hide */ + public static final int MEMINFO_TOTAL = 0; + /** @hide */ + public static final int MEMINFO_FREE = 1; + /** @hide */ + public static final int MEMINFO_BUFFERS = 2; + /** @hide */ + public static final int MEMINFO_CACHED = 3; + /** @hide */ + public static final int MEMINFO_SHMEM = 4; + /** @hide */ + public static final int MEMINFO_SLAB = 5; + /** @hide */ + public static final int MEMINFO_COUNT = 6; + + /** + * Retrieves /proc/meminfo. outSizes is filled with fields + * as defined by MEMINFO_* offsets. + * @hide + */ + public static native void getMemInfo(long[] outSizes); + /** * Establish an object allocation limit in the current thread. * This feature was never enabled in release builds. The diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java index 30ca73efb42b8..58cd60dc465e4 100644 --- a/core/java/com/android/internal/os/ProcessCpuTracker.java +++ b/core/java/com/android/internal/os/ProcessCpuTracker.java @@ -49,12 +49,12 @@ public class ProcessCpuTracker { PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults + PROC_SPACE_TERM|PROC_OUT_LONG, // 10: minor faults PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults + PROC_SPACE_TERM|PROC_OUT_LONG, // 12: major faults PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime + PROC_SPACE_TERM|PROC_OUT_LONG, // 14: utime + PROC_SPACE_TERM|PROC_OUT_LONG, // 15: stime }; static final int PROCESS_STAT_MINOR_FAULTS = 0; @@ -69,7 +69,7 @@ public class ProcessCpuTracker { private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] { PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 1: name + PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 2: name PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, @@ -77,19 +77,20 @@ public class ProcessCpuTracker { PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults + PROC_SPACE_TERM|PROC_OUT_LONG, // 10: minor faults PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults + PROC_SPACE_TERM|PROC_OUT_LONG, // 12: major faults PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime - PROC_SPACE_TERM|PROC_OUT_LONG, // 14: stime + PROC_SPACE_TERM|PROC_OUT_LONG, // 14: utime + PROC_SPACE_TERM|PROC_OUT_LONG, // 15: stime PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, PROC_SPACE_TERM, - PROC_SPACE_TERM|PROC_OUT_LONG, // 21: vsize + PROC_SPACE_TERM, + PROC_SPACE_TERM|PROC_OUT_LONG, // 23: vsize }; static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1; @@ -190,6 +191,10 @@ public class ProcessCpuTracker { public String name; public int nameWidth; + // vsize capture when process first detected; can be used to + // filter out kernel processes. + public long vsize; + public long base_uptime; public long rel_uptime; @@ -444,6 +449,7 @@ public class ProcessCpuTracker { // are actually kernel threads... do we want to? Some // of them do use CPU, but there can be a *lot* that are // not doing anything. + st.vsize = procStats[PROCESS_FULL_STAT_VSIZE]; if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) { st.interesting = true; st.baseName = procStatsString[0]; diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java index 850e1f0860f4f..ad6543305b599 100644 --- a/core/java/com/android/internal/util/MemInfoReader.java +++ b/core/java/com/android/internal/util/MemInfoReader.java @@ -18,6 +18,7 @@ package com.android.internal.util; import java.io.FileInputStream; +import android.os.Debug; import android.os.StrictMode; public class MemInfoReader { @@ -63,34 +64,11 @@ public class MemInfoReader { // /proc/ and /sys/ files perhaps? StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); try { - mTotalSize = 0; - mFreeSize = 0; - mCachedSize = 0; - FileInputStream is = new FileInputStream("/proc/meminfo"); - int len = is.read(mBuffer); - is.close(); - final int BUFLEN = mBuffer.length; - int count = 0; - for (int i=0; i= '0' && *p <= '9') p++; + if (*p != 0) { + *p = 0; + p++; + } + mem[i] = atoll(num); + numFound++; + break; + } + i++; + } + while (*p && *p != '\n') { + p++; + } + if (*p) p++; + } + + int maxNum = env->GetArrayLength(out); + jlong* outArray = env->GetLongArrayElements(out, 0); + if (outArray != NULL) { + for (int i=0; iReleaseLongArrayElements(out, outArray, 0); +} + static jint read_binder_stat(const char* stat) { FILE* fp = fopen(BINDER_STATS, "r"); @@ -790,6 +871,8 @@ static JNINativeMethod gMethods[] = { (void*) android_os_Debug_getPss }, { "getPss", "(I[J)J", (void*) android_os_Debug_getPssPid }, + { "getMemInfo", "([J)V", + (void*) android_os_Debug_getMemInfo }, { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V", (void*) android_os_Debug_dumpNativeHeap }, { "getBinderSentTransactions", "()I", diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index 4521037e117ef..b4d9da012845d 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 4f22a575d3172..3331bccd926f2 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 memInfos = (ArrayList)msg.obj; Thread thread = new Thread() { @Override public void run() { - StringBuilder dropBuilder = new StringBuilder(1024); + final SparseArray infoMap + = new SparseArray(memInfos.size()); + for (int i=0, N=memInfos.size(); i 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() { + @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= 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 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); } } @@ -3272,6 +3375,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 memInfos + = doReport ? new ArrayList(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) { @@ -3297,42 +3460,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. @@ -3851,6 +3979,8 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i 0; } @@ -10792,14 +10923,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, @@ -10871,34 +10994,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: @@ -10919,54 +11015,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(" #"); @@ -11254,6 +11303,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, @@ -11261,6 +11311,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", @@ -11268,6 +11319,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", @@ -11276,8 +11328,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; @@ -11338,6 +11389,7 @@ public final class ActivityManagerService extends ActivityManagerNative System.arraycopy(args, opti, innerArgs, 0, args.length-opti); ArrayList procMems = new ArrayList(); + final SparseArray procMemsMap = new SparseArray(); long nativePss=0, dalvikPss=0, otherPss=0; long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS]; @@ -11405,6 +11457,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; @@ -11435,6 +11488,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 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(); + } + oomProcs[0].add(pssItem); + } + } + } + ArrayList catMems = new ArrayList(); catMems.add(new MemItem("Native", "Native", nativePss, -1)); @@ -11457,68 +11552,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= ProcessList.FOREGROUND_APP_ADJ) { - if (firstLine) { - outStack.append(":"); - firstLine = false; - } - outStack.append("\n\t at "); - } else { - outStack.append("$"); - } - } - for (int j=0; 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= 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; @@ -366,6 +411,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 0000000000000..c94694e7c4b1c --- /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 892271fb239d3..35e06b655d984 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; } /*