* commit '28eeb42012018bfa3cffc77e9a970e8f5c13f70b': Implement #10749688: Improve low memory reporting
This commit is contained in:
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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<len && count < 3; i++) {
|
||||
if (matchText(mBuffer, i, "MemTotal")) {
|
||||
i += 8;
|
||||
mTotalSize = extractMemValue(mBuffer, i);
|
||||
count++;
|
||||
} else if (matchText(mBuffer, i, "MemFree")) {
|
||||
i += 7;
|
||||
mFreeSize = extractMemValue(mBuffer, i);
|
||||
count++;
|
||||
} else if (matchText(mBuffer, i, "Cached")) {
|
||||
i += 6;
|
||||
mCachedSize = extractMemValue(mBuffer, i);
|
||||
count++;
|
||||
}
|
||||
while (i < BUFLEN && mBuffer[i] != '\n') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} catch (java.io.FileNotFoundException e) {
|
||||
} catch (java.io.IOException e) {
|
||||
long[] infos = new long[Debug.MEMINFO_COUNT];
|
||||
Debug.getMemInfo(infos);
|
||||
mTotalSize = infos[Debug.MEMINFO_TOTAL] * 1024;
|
||||
mFreeSize = infos[Debug.MEMINFO_FREE] * 1024;
|
||||
mCachedSize = infos[Debug.MEMINFO_CACHED] * 1024;
|
||||
} finally {
|
||||
StrictMode.setThreadPolicy(savedPolicy);
|
||||
}
|
||||
|
@ -516,6 +516,87 @@ static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
|
||||
return android_os_Debug_getPssPid(env, clazz, getpid(), NULL);
|
||||
}
|
||||
|
||||
static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
|
||||
{
|
||||
char buffer[1024];
|
||||
int numFound = 0;
|
||||
|
||||
if (out == NULL) {
|
||||
jniThrowNullPointerException(env, "out == null");
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = open("/proc/meminfo", O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
printf("Unable to open /proc/meminfo: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
const int len = read(fd, buffer, sizeof(buffer)-1);
|
||||
close(fd);
|
||||
|
||||
if (len < 0) {
|
||||
printf("Empty /proc/meminfo");
|
||||
return;
|
||||
}
|
||||
buffer[len] = 0;
|
||||
|
||||
static const char* const tags[] = {
|
||||
"MemTotal:",
|
||||
"MemFree:",
|
||||
"Buffers:",
|
||||
"Cached:",
|
||||
"Shmem:",
|
||||
"Slab:",
|
||||
NULL
|
||||
};
|
||||
static const int tagsLen[] = {
|
||||
9,
|
||||
8,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
0
|
||||
};
|
||||
long mem[] = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
char* p = buffer;
|
||||
while (*p && numFound < 6) {
|
||||
int i = 0;
|
||||
while (tags[i]) {
|
||||
if (strncmp(p, tags[i], tagsLen[i]) == 0) {
|
||||
p += tagsLen[i];
|
||||
while (*p == ' ') p++;
|
||||
char* num = p;
|
||||
while (*p >= '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; i<maxNum && tags[i]; i++) {
|
||||
outArray[i] = mem[i];
|
||||
}
|
||||
}
|
||||
env->ReleaseLongArrayElements(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",
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<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) {
|
||||
|
||||
@ -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<N; i++) {
|
||||
removeProcessLocked(procs.get(i), false, true, "kill all background");
|
||||
}
|
||||
updateOomAdjLocked();
|
||||
doLowMemReportIfNeededLocked(null);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingId);
|
||||
@ -4160,6 +4290,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;
|
||||
}
|
||||
|
||||
@ -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<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];
|
||||
|
||||
@ -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<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));
|
||||
@ -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<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:");
|
||||
|
@ -19,6 +19,7 @@ package com.android.server.am;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import com.android.internal.util.MemInfoReader;
|
||||
import com.android.server.wm.WindowManagerService;
|
||||
|
||||
@ -98,6 +99,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;
|
||||
|
||||
@ -278,6 +283,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;
|
||||
|
||||
@ -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
|
||||
|
37
services/java/com/android/server/am/ProcessMemInfo.java
Normal file
37
services/java/com/android/server/am/ProcessMemInfo.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user