diff options
author | Dianne Hackborn <hackbod@google.com> | 2013-09-13 17:30:31 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2013-09-13 17:30:31 -0700 |
commit | 1cd9a73ac020bfb2db32da3c8e853c4a514be858 (patch) | |
tree | 819064ab194582cce792c5f93a6262db6ce1f5ae /services | |
parent | 078c1f3606c3327e604bf2ccd775a9410684d192 (diff) | |
parent | f3b4cf7d01b68418dd652e201868d140de081bd8 (diff) | |
download | frameworks_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')
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; } /* |