Merge "Improve debug output when an ANR happens." into gingerbread

This commit is contained in:
Dianne Hackborn
2010-08-31 18:56:30 -07:00
committed by Android (Google) Code Review
3 changed files with 260 additions and 111 deletions

View File

@ -39,7 +39,7 @@ public class ProcessStats {
private static final int[] PROCESS_STATS_FORMAT = new int[] {
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM|PROC_PARENS,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
@ -75,16 +75,21 @@ public class ProcessStats {
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM,
PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults
PROC_SPACE_TERM,
PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime
PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime
};
private final String[] mProcessFullStatsStringData = new String[3];
private final long[] mProcessFullStatsData = new long[3];
static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
static final int PROCESS_FULL_STAT_UTIME = 3;
static final int PROCESS_FULL_STAT_STIME = 4;
private final String[] mProcessFullStatsStringData = new String[5];
private final long[] mProcessFullStatsData = new long[5];
private static final int[] SYSTEM_CPU_FORMAT = new int[] {
PROC_SPACE_TERM|PROC_COMBINE,
@ -116,6 +121,9 @@ public class ProcessStats {
private long mCurrentSampleTime;
private long mLastSampleTime;
private long mCurrentSampleRealTime;
private long mLastSampleRealTime;
private long mBaseUserTime;
private long mBaseSystemTime;
private long mBaseIoWaitTime;
@ -167,6 +175,9 @@ public class ProcessStats {
public String name;
int nameWidth;
public long base_uptime;
public long rel_uptime;
public long base_utime;
public long base_stime;
public int rel_utime;
@ -178,6 +189,7 @@ public class ProcessStats {
public int rel_majfaults;
public boolean active;
public boolean working;
public boolean added;
public boolean removed;
@ -211,8 +223,7 @@ public class ProcessStats {
private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
public final int
compare(Stats sta, Stats stb)
{
compare(Stats sta, Stats stb) {
int ta = sta.rel_utime + sta.rel_stime;
int tb = stb.rel_utime + stb.rel_stime;
if (ta != tb) {
@ -241,31 +252,17 @@ public class ProcessStats {
}
public void init() {
if (DEBUG) Slog.v(TAG, "Init: " + this);
mFirst = true;
update();
}
public void update() {
if (DEBUG) Slog.v(TAG, "Update: " + this);
mLastSampleTime = mCurrentSampleTime;
mCurrentSampleTime = SystemClock.uptimeMillis();
final float[] loadAverages = mLoadAverageData;
if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
null, null, loadAverages)) {
float load1 = loadAverages[0];
float load5 = loadAverages[1];
float load15 = loadAverages[2];
if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
mLoad1 = load1;
mLoad5 = load5;
mLoad15 = load15;
onLoadChanged(load1, load5, load15);
}
}
mCurPids = collectStats("/proc", -1, mFirst, mCurPids,
mProcStats, mWorkingProcs);
mFirst = false;
mLastSampleRealTime = mCurrentSampleRealTime;
mCurrentSampleRealTime = SystemClock.elapsedRealtime();
final long[] sysCpu = mSystemCpuData;
if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
@ -288,7 +285,7 @@ public class ProcessStats {
mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
mRelIdleTime = (int)(idletime - mBaseIdleTime);
if (false) {
if (DEBUG) {
Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
+ " S:" + sysCpu[2] + " I:" + sysCpu[3]
+ " W:" + sysCpu[4] + " Q:" + sysCpu[5]
@ -305,16 +302,32 @@ public class ProcessStats {
mBaseIdleTime = idletime;
}
mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
final float[] loadAverages = mLoadAverageData;
if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
null, null, loadAverages)) {
float load1 = loadAverages[0];
float load5 = loadAverages[1];
float load15 = loadAverages[2];
if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
mLoad1 = load1;
mLoad5 = load5;
mLoad15 = load15;
onLoadChanged(load1, load5, load15);
}
}
if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
+ (SystemClock.uptimeMillis()-mCurrentSampleTime));
mWorkingProcsSorted = false;
mFirst = false;
}
private int[] collectStats(String statsFile, int parentPid, boolean first,
int[] curPids, ArrayList<Stats> allProcs,
ArrayList<Stats> workingProcs) {
int[] curPids, ArrayList<Stats> allProcs) {
workingProcs.clear();
int[] pids = Process.getPids(statsFile, curPids);
int NP = (pids == null) ? 0 : pids.length;
int NS = allProcs.size();
@ -330,8 +343,13 @@ public class ProcessStats {
if (st != null && st.pid == pid) {
// Update an existing process...
st.added = false;
st.working = false;
curStatsIndex++;
if (localLOGV) Slog.v(TAG, "Existing pid " + pid + ": " + st);
if (DEBUG) Slog.v(TAG, "Existing "
+ (parentPid < 0 ? "process" : "thread")
+ " pid " + pid + ": " + st);
final long uptime = SystemClock.uptimeMillis();
final long[] procStats = mProcessStatsData;
if (!Process.readProcFile(st.statFile.toString(),
@ -363,11 +381,18 @@ public class ProcessStats {
getName(st, st.cmdlineFile);
if (st.threadStats != null) {
mCurThreadPids = collectStats(st.threadsDir, pid, false,
mCurThreadPids, st.threadStats,
st.workingThreads);
mCurThreadPids, st.threadStats);
}
}
if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
+ " utime=" + utime + "-" + st.base_utime
+ " stime=" + stime + "-" + st.base_stime
+ " minfaults=" + minfaults + "-" + st.base_minfaults
+ " majfaults=" + majfaults + "-" + st.base_majfaults);
st.rel_uptime = uptime - st.base_uptime;
st.base_uptime = uptime;
st.rel_utime = (int)(utime - st.base_utime);
st.rel_stime = (int)(stime - st.base_stime);
st.base_utime = utime;
@ -376,10 +401,7 @@ public class ProcessStats {
st.rel_majfaults = (int)(majfaults - st.base_majfaults);
st.base_minfaults = minfaults;
st.base_majfaults = majfaults;
//Slog.i("Load", "Stats changed " + name + " pid=" + st.pid
// + " name=" + st.name + " utime=" + utime
// + " stime=" + stime);
workingProcs.add(st);
st.working = true;
continue;
}
@ -389,18 +411,21 @@ public class ProcessStats {
allProcs.add(curStatsIndex, st);
curStatsIndex++;
NS++;
if (localLOGV) Slog.v(TAG, "New pid " + pid + ": " + st);
if (DEBUG) Slog.v(TAG, "New "
+ (parentPid < 0 ? "process" : "thread")
+ " pid " + pid + ": " + st);
final String[] procStatsString = mProcessFullStatsStringData;
final long[] procStats = mProcessFullStatsData;
st.base_uptime = SystemClock.uptimeMillis();
if (Process.readProcFile(st.statFile.toString(),
PROCESS_FULL_STATS_FORMAT, procStatsString,
procStats, null)) {
st.baseName = parentPid < 0
? procStatsString[0] : Integer.toString(pid);
st.base_utime = 0; //procStats[1];
st.base_stime = 0; //procStats[2];
st.base_minfaults = st.base_majfaults = 0;
st.baseName = procStatsString[0];
st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
} else {
st.baseName = "<unknown>";
st.base_utime = st.base_stime = 0;
@ -409,24 +434,26 @@ public class ProcessStats {
if (parentPid < 0) {
getName(st, st.cmdlineFile);
if (st.threadStats != null) {
mCurThreadPids = collectStats(st.threadsDir, pid, true,
mCurThreadPids, st.threadStats);
}
} else {
st.name = st.baseName;
st.nameWidth = onMeasureProcessName(st.name);
if (st.threadStats != null) {
mCurThreadPids = collectStats(st.threadsDir, pid, true,
mCurThreadPids, st.threadStats,
st.workingThreads);
}
}
if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
+ " utime=" + st.base_utime + " stime=" + st.base_stime
+ " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
//Slog.i("Load", "New process: " + st.pid + " " + st.name);
st.rel_utime = 0;
st.rel_stime = 0;
st.rel_minfaults = 0;
st.rel_majfaults = 0;
st.added = true;
if (!first) {
workingProcs.add(st);
st.working = true;
}
continue;
}
@ -437,10 +464,12 @@ public class ProcessStats {
st.rel_minfaults = 0;
st.rel_majfaults = 0;
st.removed = true;
workingProcs.add(st);
st.working = true;
allProcs.remove(curStatsIndex);
NS--;
if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
if (DEBUG) Slog.v(TAG, "Removed "
+ (parentPid < 0 ? "process" : "thread")
+ " pid " + pid + ": " + st);
// Decrement the loop counter so that we process the current pid
// again the next time through the loop.
i--;
@ -455,7 +484,7 @@ public class ProcessStats {
st.rel_minfaults = 0;
st.rel_majfaults = 0;
st.removed = true;
workingProcs.add(st);
st.working = true;
allProcs.remove(curStatsIndex);
NS--;
if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
@ -569,11 +598,34 @@ public class ProcessStats {
/ (mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime);
}
final public int countWorkingStats() {
final void buildWorkingProcs() {
if (!mWorkingProcsSorted) {
mWorkingProcs.clear();
final int N = mProcStats.size();
for (int i=0; i<N; i++) {
Stats stats = mProcStats.get(i);
if (stats.working) {
mWorkingProcs.add(stats);
if (stats.threadStats != null && stats.threadStats.size() > 1) {
stats.workingThreads.clear();
final int M = stats.threadStats.size();
for (int j=0; j<M; j++) {
Stats tstats = stats.threadStats.get(j);
if (tstats.working) {
stats.workingThreads.add(tstats);
}
}
Collections.sort(stats.workingThreads, sLoadComparator);
}
}
}
Collections.sort(mWorkingProcs, sLoadComparator);
mWorkingProcsSorted = true;
}
}
final public int countWorkingStats() {
buildWorkingProcs();
return mWorkingProcs.size();
}
@ -581,12 +633,7 @@ public class ProcessStats {
return mWorkingProcs.get(index);
}
final public String printCurrentState() {
if (!mWorkingProcsSorted) {
Collections.sort(mWorkingProcs, sLoadComparator);
mWorkingProcsSorted = true;
}
final public String printCurrentLoad() {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.print("Load: ");
@ -595,67 +642,111 @@ public class ProcessStats {
pw.print(mLoad5);
pw.print(" / ");
pw.println(mLoad15);
return sw.toString();
}
final public String printCurrentState(long now) {
buildWorkingProcs();
long now = SystemClock.uptimeMillis();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.print("CPU usage from ");
pw.print(now-mLastSampleTime);
pw.print("ms to ");
pw.print(now-mCurrentSampleTime);
pw.println("ms ago:");
if (now > mLastSampleTime) {
pw.print(now-mLastSampleTime);
pw.print("ms to ");
pw.print(now-mCurrentSampleTime);
pw.print("ms ago");
} else {
pw.print(mLastSampleTime-now);
pw.print("ms to ");
pw.print(mCurrentSampleTime-now);
pw.print("ms later");
}
long sampleTime = mCurrentSampleTime - mLastSampleTime;
long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
long percAwake = (sampleTime*100) / sampleRealTime;
if (percAwake != 100) {
pw.print(" with ");
pw.print(percAwake);
pw.print("% awake");
}
pw.println(":");
final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
+ mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
+ (mCurrentSampleTime-mLastSampleTime));
int N = mWorkingProcs.size();
for (int i=0; i<N; i++) {
Stats st = mWorkingProcs.get(i);
printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "),
st.name, totalTime, st.rel_utime, st.rel_stime, 0, 0, 0,
st.rel_minfaults, st.rel_majfaults);
st.pid, st.name, (int)(st.rel_uptime+5)/10,
st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults);
if (!st.removed && st.workingThreads != null) {
int M = st.workingThreads.size();
for (int j=0; j<M; j++) {
Stats tst = st.workingThreads.get(j);
printProcessCPU(pw,
tst.added ? " +" : (tst.removed ? " -": " "),
tst.name, totalTime, tst.rel_utime, tst.rel_stime,
0, 0, 0, 0, 0);
tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
}
}
}
printProcessCPU(pw, "", "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
return sw.toString();
}
private void printProcessCPU(PrintWriter pw, String prefix, String label, int totalTime,
int user, int system, int iowait, int irq, int softIrq, int minFaults, int majFaults) {
private void printRatio(PrintWriter pw, long numerator, long denominator) {
long thousands = (numerator*1000)/denominator;
long hundreds = thousands/10;
pw.print(hundreds);
if (hundreds < 10) {
long remainder = thousands - (hundreds*10);
if (remainder != 0) {
pw.print('.');
pw.print(remainder);
}
}
}
private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
int totalTime, int user, int system, int iowait, int irq, int softIrq,
int minFaults, int majFaults) {
pw.print(prefix);
if (totalTime == 0) totalTime = 1;
printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
pw.print("% ");
if (pid >= 0) {
pw.print(pid);
pw.print("/");
}
pw.print(label);
pw.print(": ");
if (totalTime == 0) totalTime = 1;
pw.print(((user+system+iowait+irq+softIrq)*100)/totalTime);
pw.print("% = ");
pw.print((user*100)/totalTime);
printRatio(pw, user, totalTime);
pw.print("% user + ");
pw.print((system*100)/totalTime);
printRatio(pw, system, totalTime);
pw.print("% kernel");
if (iowait > 0) {
pw.print(" + ");
pw.print((iowait*100)/totalTime);
printRatio(pw, iowait, totalTime);
pw.print("% iowait");
}
if (irq > 0) {
pw.print(" + ");
pw.print((irq*100)/totalTime);
printRatio(pw, irq, totalTime);
pw.print("% irq");
}
if (softIrq > 0) {
pw.print(" + ");
pw.print((softIrq*100)/totalTime);
printRatio(pw, softIrq, totalTime);
pw.print("% softirq");
}
if (minFaults > 0 || majFaults > 0) {
@ -696,8 +787,8 @@ public class ProcessStats {
}
private void getName(Stats st, String cmdlineFile) {
String newName = st.baseName;
if (st.baseName == null || st.baseName.equals("app_process")) {
String newName = st.name;
if (st.name == null || st.name.equals("app_process")) {
String cmdName = readFile(cmdlineFile, '\0');
if (cmdName != null && cmdName.length() > 1) {
newName = cmdName;
@ -706,6 +797,9 @@ public class ProcessStats {
newName = newName.substring(i+1);
}
}
if (newName == null) {
newName = st.baseName;
}
}
if (st.name == null || !newName.equals(st.name)) {
st.name = newName;

View File

@ -39,9 +39,6 @@ import android.util.Log;
import android.util.Slog;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
@ -113,8 +110,6 @@ public class Watchdog extends Thread {
public void handleMessage(Message msg) {
switch (msg.what) {
case MONITOR: {
long now = SystemClock.uptimeMillis();
// See if we should force a reboot.
int rebootInterval = mReqRebootInterval >= 0
? mReqRebootInterval : Settings.Secure.getInt(
@ -418,9 +413,9 @@ public class Watchdog extends Thread {
if (!waitedHalf) {
// We've waited half the deadlock-detection interval. Pull a stack
// trace and wait another half.
ArrayList pids = new ArrayList();
ArrayList<Integer> pids = new ArrayList<Integer>();
pids.add(Process.myPid());
File stack = ActivityManagerService.dumpStackTraces(true, pids);
ActivityManagerService.dumpStackTraces(true, pids, null, null);
waitedHalf = true;
continue;
}
@ -430,15 +425,16 @@ public class Watchdog extends Thread {
// First collect stack traces from all threads of the system process.
// Then kill this process so that the system will restart.
String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null";
String name = (mCurrentMonitor != null) ?
mCurrentMonitor.getClass().getName() : "null";
EventLog.writeEvent(EventLogTags.WATCHDOG, name);
ArrayList pids = new ArrayList();
ArrayList<Integer> pids = new ArrayList<Integer>();
pids.add(Process.myPid());
if (mPhonePid > 0) pids.add(mPhonePid);
// Pass !waitedHalf so that just in case we somehow wind up here without having
// dumped the halfway stacks, we properly re-initialize the trace file.
File stack = ActivityManagerService.dumpStackTraces(!waitedHalf, pids);
File stack = ActivityManagerService.dumpStackTraces(!waitedHalf, pids, null, null);
// Give some extra time to make sure the stack traces get written.
// The system's been hanging for a minute, another second or two won't hurt much.

View File

@ -1355,7 +1355,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mActivityManagerService.mProcessStatsThread) {
pw.print(mActivityManagerService.mProcessStats.printCurrentState());
pw.print(mActivityManagerService.mProcessStats.printCurrentLoad());
pw.print(mActivityManagerService.mProcessStats.printCurrentState(
SystemClock.uptimeMillis()));
}
}
}
@ -2644,10 +2646,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* @param clearTraces causes the dump file to be erased prior to the new
* traces being written, if true; when false, the new traces will be
* appended to any existing file content.
* @param pids of dalvik VM processes to dump stack traces for
* @param firstPids of dalvik VM processes to dump stack traces for first
* @param lastPids of dalvik VM processes to dump stack traces for last
* @return file containing stack traces, or null if no dump file is configured
*/
public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> pids) {
public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> firstPids,
ProcessStats processStats, SparseArray<Boolean> lastPids) {
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
if (tracesPath == null || tracesPath.length() == 0) {
return null;
@ -2675,25 +2679,69 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
observer.startWatching();
int num = pids.size();
for (int i = 0; i < num; i++) {
synchronized (observer) {
Process.sendSignal(pids.get(i), Process.SIGNAL_QUIT);
observer.wait(200); // Wait for write-close, give up after 200msec
// First collect all of the stacks of the most important pids.
try {
int num = firstPids.size();
for (int i = 0; i < num; i++) {
synchronized (observer) {
Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
observer.wait(200); // Wait for write-close, give up after 200msec
}
}
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
// Next measure CPU usage.
if (processStats != null) {
processStats.init();
System.gc();
processStats.update();
try {
synchronized (processStats) {
processStats.wait(500); // measure over 1/2 second.
}
} catch (InterruptedException e) {
}
processStats.update();
// We'll take the stack crawls of just the top apps using CPU.
final int N = processStats.countWorkingStats();
int numProcs = 0;
for (int i=0; i<N && numProcs<5; i++) {
ProcessStats.Stats stats = processStats.getWorkingStats(i);
if (lastPids.indexOfKey(stats.pid) >= 0) {
numProcs++;
try {
synchronized (observer) {
Process.sendSignal(stats.pid, Process.SIGNAL_QUIT);
observer.wait(200); // Wait for write-close, give up after 200msec
}
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
}
}
}
} catch (InterruptedException e) {
Log.wtf(TAG, e);
return tracesFile;
} finally {
observer.stopWatching();
}
return tracesFile;
}
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, final String annotation) {
ArrayList<Integer> pids = new ArrayList<Integer>(20);
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
long anrTime = SystemClock.uptimeMillis();
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
}
synchronized (this) {
// PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
@ -2717,24 +2765,32 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
annotation);
// Dump thread traces as quickly as we can, starting with "interesting" processes.
pids.add(app.pid);
firstPids.add(app.pid);
int parentPid = app.pid;
if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
if (parentPid != app.pid) pids.add(parentPid);
if (parentPid != app.pid) firstPids.add(parentPid);
if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord r = mLruProcesses.get(i);
if (r != null && r.thread != null) {
int pid = r.pid;
if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
if (r.persistent) {
firstPids.add(pid);
} else {
lastPids.put(pid, Boolean.TRUE);
}
}
}
}
}
File tracesFile = dumpStackTraces(true, pids);
final ProcessStats processStats = new ProcessStats(true);
File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids);
// Log the ANR to the main log.
StringBuilder info = mStringBuilder;
@ -2755,11 +2811,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
synchronized (mProcessStatsThread) {
cpuInfo = mProcessStats.printCurrentState();
cpuInfo = mProcessStats.printCurrentState(anrTime);
}
info.append(processStats.printCurrentLoad());
info.append(cpuInfo);
}
info.append(processStats.printCurrentState(anrTime));
Slog.e(TAG, info.toString());
if (tracesFile == null) {
// There is no trace file, so dump (only) the alleged culprit's threads to the log