am f34fa3e7: Merge "Improve low on RAM reporting." into lmp-mr1-dev
* commit 'f34fa3e7aa9be9bf24c955a9ebf34022e4b88c25': Improve low on RAM reporting.
This commit is contained in:
@@ -106,4 +106,8 @@ public final class MemInfoReader {
|
|||||||
public long getZramTotalSizeKb() {
|
public long getZramTotalSizeKb() {
|
||||||
return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
|
return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long[] getRawInfo() {
|
||||||
|
return mInfos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1606,197 +1606,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
|
final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
|
||||||
Thread thread = new Thread() {
|
Thread thread = new Thread() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
final SparseArray<ProcessMemInfo> infoMap
|
reportMemUsage(memInfos);
|
||||||
= 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 (mProcessCpuTracker) {
|
|
||||||
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_VM_ALLOC_USED]).append(" kB vm alloc, ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n");
|
|
||||||
logBuilder.append(" ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
|
|
||||||
if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
|
|
||||||
logBuilder.append(" ZRAM: ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
|
|
||||||
logBuilder.append(" kB RAM, ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
|
|
||||||
logBuilder.append(" kB swap total, ");
|
|
||||||
logBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
|
|
||||||
logBuilder.append(" kB swap 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[] { };
|
|
||||||
dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw);
|
|
||||||
oomPw.flush();
|
|
||||||
String oomString = oomSw.toString();
|
|
||||||
*/
|
|
||||||
dropBuilder.append(stack);
|
|
||||||
dropBuilder.append('\n');
|
|
||||||
dropBuilder.append('\n');
|
|
||||||
dropBuilder.append(logBuilder);
|
|
||||||
dropBuilder.append('\n');
|
|
||||||
/*
|
|
||||||
dropBuilder.append(oomString);
|
|
||||||
dropBuilder.append('\n');
|
|
||||||
*/
|
|
||||||
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();
|
|
||||||
mServices.dumpServicesLocked(null, catPw, emptyArgs, 0,
|
|
||||||
false, false, null);
|
|
||||||
catPw.println();
|
|
||||||
dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
|
|
||||||
catPw.flush();
|
|
||||||
}
|
|
||||||
dropBuilder.append(catSw.toString());
|
|
||||||
addErrorToDropBox("lowmem", null, "system_server", null,
|
|
||||||
null, tag.toString(), dropBuilder.toString(), null, null);
|
|
||||||
//Slog.i(TAG, "Sent to dropbox:");
|
|
||||||
//Slog.i(TAG, dropBuilder.toString());
|
|
||||||
synchronized (ActivityManagerService.this) {
|
|
||||||
long now = SystemClock.uptimeMillis();
|
|
||||||
if (mLastMemUsageReportTime < now) {
|
|
||||||
mLastMemUsageReportTime = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
thread.start();
|
thread.start();
|
||||||
@@ -13927,6 +13737,35 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final int KSM_SHARED = 0;
|
||||||
|
private static final int KSM_SHARING = 1;
|
||||||
|
private static final int KSM_UNSHARED = 2;
|
||||||
|
private static final int KSM_VOLATILE = 3;
|
||||||
|
|
||||||
|
private final long[] getKsmInfo() {
|
||||||
|
long[] longOut = new long[4];
|
||||||
|
final int[] SINGLE_LONG_FORMAT = new int[] {
|
||||||
|
Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
|
||||||
|
};
|
||||||
|
long[] longTmp = new long[1];
|
||||||
|
Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
|
||||||
|
SINGLE_LONG_FORMAT, null, longTmp, null);
|
||||||
|
longOut[KSM_SHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
|
||||||
|
longTmp[0] = 0;
|
||||||
|
Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
|
||||||
|
SINGLE_LONG_FORMAT, null, longTmp, null);
|
||||||
|
longOut[KSM_SHARING] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
|
||||||
|
longTmp[0] = 0;
|
||||||
|
Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
|
||||||
|
SINGLE_LONG_FORMAT, null, longTmp, null);
|
||||||
|
longOut[KSM_UNSHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
|
||||||
|
longTmp[0] = 0;
|
||||||
|
Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
|
||||||
|
SINGLE_LONG_FORMAT, null, longTmp, null);
|
||||||
|
longOut[KSM_VOLATILE] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
|
||||||
|
return longOut;
|
||||||
|
}
|
||||||
|
|
||||||
final void dumpApplicationMemoryUsage(FileDescriptor fd,
|
final void dumpApplicationMemoryUsage(FileDescriptor fd,
|
||||||
PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
|
PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
|
||||||
boolean dumpDetails = false;
|
boolean dumpDetails = false;
|
||||||
@@ -14272,7 +14111,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
|
pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
|
||||||
+ memInfo.getFreeSizeKb()); pw.print(" kB (");
|
+ memInfo.getFreeSizeKb()); pw.print(" kB (");
|
||||||
pw.print(cachedPss); pw.print(" cached pss + ");
|
pw.print(cachedPss); pw.print(" cached pss + ");
|
||||||
pw.print(memInfo.getCachedSizeKb()); pw.print(" cached + ");
|
pw.print(memInfo.getCachedSizeKb()); pw.print(" cached kernel + ");
|
||||||
pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
|
pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
|
||||||
} else {
|
} else {
|
||||||
pw.print("ram,"); pw.print(memInfo.getTotalSizeKb()); pw.print(",");
|
pw.print("ram,"); pw.print(memInfo.getTotalSizeKb()); pw.print(",");
|
||||||
@@ -14306,32 +14145,16 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
pw.println(memInfo.getSwapFreeSizeKb());
|
pw.println(memInfo.getSwapFreeSizeKb());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final int[] SINGLE_LONG_FORMAT = new int[] {
|
final long[] ksm = getKsmInfo();
|
||||||
Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
|
|
||||||
};
|
|
||||||
long[] longOut = new long[1];
|
|
||||||
Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
|
|
||||||
SINGLE_LONG_FORMAT, null, longOut, null);
|
|
||||||
long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
|
|
||||||
longOut[0] = 0;
|
|
||||||
Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
|
|
||||||
SINGLE_LONG_FORMAT, null, longOut, null);
|
|
||||||
long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024;
|
|
||||||
longOut[0] = 0;
|
|
||||||
Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
|
|
||||||
SINGLE_LONG_FORMAT, null, longOut, null);
|
|
||||||
long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
|
|
||||||
longOut[0] = 0;
|
|
||||||
Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
|
|
||||||
SINGLE_LONG_FORMAT, null, longOut, null);
|
|
||||||
long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024;
|
|
||||||
if (!isCompact) {
|
if (!isCompact) {
|
||||||
if (sharing != 0 || shared != 0 || unshared != 0 || voltile != 0) {
|
if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
|
||||||
pw.print(" KSM: "); pw.print(sharing);
|
|| ksm[KSM_VOLATILE] != 0) {
|
||||||
|
pw.print(" KSM: "); pw.print(ksm[KSM_SHARING]);
|
||||||
pw.print(" kB saved from shared ");
|
pw.print(" kB saved from shared ");
|
||||||
pw.print(shared); pw.println(" kB");
|
pw.print(ksm[KSM_SHARED]); pw.println(" kB");
|
||||||
pw.print(" "); pw.print(unshared); pw.print(" kB unshared; ");
|
pw.print(" "); pw.print(ksm[KSM_UNSHARED]);
|
||||||
pw.print(voltile); pw.println(" kB volatile");
|
pw.print(" kB unshared; ");
|
||||||
|
pw.print(ksm[KSM_VOLATILE]); pw.println(" kB volatile");
|
||||||
}
|
}
|
||||||
pw.print(" Tuning: ");
|
pw.print(" Tuning: ");
|
||||||
pw.print(ActivityManager.staticGetMemoryClass());
|
pw.print(ActivityManager.staticGetMemoryClass());
|
||||||
@@ -14351,9 +14174,9 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
}
|
}
|
||||||
pw.println();
|
pw.println();
|
||||||
} else {
|
} else {
|
||||||
pw.print("ksm,"); pw.print(sharing); pw.print(",");
|
pw.print("ksm,"); pw.print(ksm[KSM_SHARING]); pw.print(",");
|
||||||
pw.print(shared); pw.print(","); pw.print(unshared); pw.print(",");
|
pw.print(ksm[KSM_SHARED]); pw.print(","); pw.print(ksm[KSM_UNSHARED]);
|
||||||
pw.println(voltile);
|
pw.print(","); pw.println(ksm[KSM_VOLATILE]);
|
||||||
pw.print("tuning,");
|
pw.print("tuning,");
|
||||||
pw.print(ActivityManager.staticGetMemoryClass());
|
pw.print(ActivityManager.staticGetMemoryClass());
|
||||||
pw.print(',');
|
pw.print(',');
|
||||||
@@ -14372,6 +14195,265 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
|
||||||
|
String name) {
|
||||||
|
sb.append(" ");
|
||||||
|
sb.append(ProcessList.makeOomAdjString(oomAdj));
|
||||||
|
sb.append(' ');
|
||||||
|
sb.append(ProcessList.makeProcStateString(procState));
|
||||||
|
sb.append(' ');
|
||||||
|
ProcessList.appendRamKb(sb, pss);
|
||||||
|
sb.append(" kB: ");
|
||||||
|
sb.append(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
|
||||||
|
appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.name);
|
||||||
|
sb.append(" (");
|
||||||
|
sb.append(mi.pid);
|
||||||
|
sb.append(") ");
|
||||||
|
sb.append(mi.adjType);
|
||||||
|
sb.append('\n');
|
||||||
|
if (mi.adjReason != null) {
|
||||||
|
sb.append(" ");
|
||||||
|
sb.append(mi.adjReason);
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
|
||||||
|
final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
|
||||||
|
for (int i=0, N=memInfos.size(); i<N; i++) {
|
||||||
|
ProcessMemInfo mi = memInfos.get(i);
|
||||||
|
infoMap.put(mi.pid, mi);
|
||||||
|
}
|
||||||
|
updateCpuStatsNow();
|
||||||
|
synchronized (mProcessCpuTracker) {
|
||||||
|
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 fullNativeBuilder = new StringBuilder(1024);
|
||||||
|
StringBuilder shortNativeBuilder = new StringBuilder(1024);
|
||||||
|
StringBuilder fullJavaBuilder = new StringBuilder(1024);
|
||||||
|
|
||||||
|
boolean firstLine = true;
|
||||||
|
int lastOomAdj = Integer.MIN_VALUE;
|
||||||
|
long extraNativeRam = 0;
|
||||||
|
long cachedPss = 0;
|
||||||
|
for (int i=0, N=memInfos.size(); i<N; i++) {
|
||||||
|
ProcessMemInfo mi = memInfos.get(i);
|
||||||
|
|
||||||
|
if (mi.oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
|
||||||
|
cachedPss += mi.pss;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendMemInfo(fullNativeBuilder, mi);
|
||||||
|
if (mi.oomAdj == ProcessList.NATIVE_ADJ) {
|
||||||
|
// The short form only has native processes that are >= 1MB.
|
||||||
|
if (mi.pss >= 1000) {
|
||||||
|
appendMemInfo(shortNativeBuilder, mi);
|
||||||
|
} else {
|
||||||
|
extraNativeRam += mi.pss;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Short form has all other details, but if we have collected RAM
|
||||||
|
// from smaller native processes let's dump a summary of that.
|
||||||
|
if (extraNativeRam > 0) {
|
||||||
|
appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ,
|
||||||
|
-1, extraNativeRam, "(Other native)");
|
||||||
|
shortNativeBuilder.append('\n');
|
||||||
|
extraNativeRam = 0;
|
||||||
|
}
|
||||||
|
appendMemInfo(fullJavaBuilder, mi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fullJavaBuilder.append(" ");
|
||||||
|
ProcessList.appendRamKb(fullJavaBuilder, totalPss);
|
||||||
|
fullJavaBuilder.append(" kB: TOTAL\n");
|
||||||
|
|
||||||
|
MemInfoReader memInfo = new MemInfoReader();
|
||||||
|
memInfo.readMemInfo();
|
||||||
|
final long[] infos = memInfo.getRawInfo();
|
||||||
|
|
||||||
|
StringBuilder memInfoBuilder = new StringBuilder(1024);
|
||||||
|
Debug.getMemInfo(infos);
|
||||||
|
memInfoBuilder.append(" MemInfo: ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_VM_ALLOC_USED]).append(" kB vm alloc, ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n");
|
||||||
|
memInfoBuilder.append(" ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
|
||||||
|
if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
|
||||||
|
memInfoBuilder.append(" ZRAM: ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
|
||||||
|
memInfoBuilder.append(" kB RAM, ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
|
||||||
|
memInfoBuilder.append(" kB swap total, ");
|
||||||
|
memInfoBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
|
||||||
|
memInfoBuilder.append(" kB swap free\n");
|
||||||
|
}
|
||||||
|
final long[] ksm = getKsmInfo();
|
||||||
|
if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
|
||||||
|
|| ksm[KSM_VOLATILE] != 0) {
|
||||||
|
memInfoBuilder.append(" KSM: "); memInfoBuilder.append(ksm[KSM_SHARING]);
|
||||||
|
memInfoBuilder.append(" kB saved from shared ");
|
||||||
|
memInfoBuilder.append(ksm[KSM_SHARED]); memInfoBuilder.append(" kB\n");
|
||||||
|
memInfoBuilder.append(" "); memInfoBuilder.append(ksm[KSM_UNSHARED]);
|
||||||
|
memInfoBuilder.append(" kB unshared; ");
|
||||||
|
memInfoBuilder.append(ksm[KSM_VOLATILE]); memInfoBuilder.append(" kB volatile\n");
|
||||||
|
}
|
||||||
|
memInfoBuilder.append(" Free RAM: ");
|
||||||
|
memInfoBuilder.append(cachedPss + memInfo.getCachedSizeKb()
|
||||||
|
+ memInfo.getFreeSizeKb());
|
||||||
|
memInfoBuilder.append(" kB\n");
|
||||||
|
memInfoBuilder.append(" Used RAM: ");
|
||||||
|
memInfoBuilder.append(totalPss - cachedPss + memInfo.getKernelUsedSizeKb());
|
||||||
|
memInfoBuilder.append(" kB\n");
|
||||||
|
memInfoBuilder.append(" Lost RAM: ");
|
||||||
|
memInfoBuilder.append(memInfo.getTotalSizeKb()
|
||||||
|
- totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
|
||||||
|
- memInfo.getKernelUsedSizeKb());
|
||||||
|
memInfoBuilder.append(" kB\n");
|
||||||
|
Slog.i(TAG, "Low on memory:");
|
||||||
|
Slog.i(TAG, shortNativeBuilder.toString());
|
||||||
|
Slog.i(TAG, fullJavaBuilder.toString());
|
||||||
|
Slog.i(TAG, memInfoBuilder.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[] { };
|
||||||
|
dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw);
|
||||||
|
oomPw.flush();
|
||||||
|
String oomString = oomSw.toString();
|
||||||
|
*/
|
||||||
|
dropBuilder.append("Low on memory:");
|
||||||
|
dropBuilder.append(stack);
|
||||||
|
dropBuilder.append('\n');
|
||||||
|
dropBuilder.append(fullNativeBuilder);
|
||||||
|
dropBuilder.append(fullJavaBuilder);
|
||||||
|
dropBuilder.append('\n');
|
||||||
|
dropBuilder.append(memInfoBuilder);
|
||||||
|
dropBuilder.append('\n');
|
||||||
|
/*
|
||||||
|
dropBuilder.append(oomString);
|
||||||
|
dropBuilder.append('\n');
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
mServices.dumpServicesLocked(null, catPw, emptyArgs, 0,
|
||||||
|
false, false, null);
|
||||||
|
catPw.println();
|
||||||
|
dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
|
||||||
|
catPw.flush();
|
||||||
|
}
|
||||||
|
dropBuilder.append(catSw.toString());
|
||||||
|
addErrorToDropBox("lowmem", null, "system_server", null,
|
||||||
|
null, tag.toString(), dropBuilder.toString(), null, null);
|
||||||
|
//Slog.i(TAG, "Sent to dropbox:");
|
||||||
|
//Slog.i(TAG, dropBuilder.toString());
|
||||||
|
synchronized (ActivityManagerService.this) {
|
||||||
|
long now = SystemClock.uptimeMillis();
|
||||||
|
if (mLastMemUsageReportTime < now) {
|
||||||
|
mLastMemUsageReportTime = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches array of arguments for the specified string
|
* Searches array of arguments for the specified string
|
||||||
* @param args array of argument strings
|
* @param args array of argument strings
|
||||||
|
|||||||
Reference in New Issue
Block a user