am a7e3a1e0: Merge "Include important native processes in watchdog stacks." into jb-dev
* commit 'a7e3a1e0e7d308e7e78a1992038a34485d04ab29': Include important native processes in watchdog stacks.
This commit is contained in:
@@ -1325,6 +1325,13 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Have the stack traces of the given native process dumped to the
|
||||
* specified file. Will be appended to the file.
|
||||
* @hide
|
||||
*/
|
||||
public static native void dumpNativeBacktraceToFile(int pid, String file);
|
||||
|
||||
/**
|
||||
* Return a String describing the calling method and location at a particular stack depth.
|
||||
* @param callStack the Thread stack
|
||||
|
||||
@@ -933,6 +933,9 @@ public class Process {
|
||||
public static final native boolean parseProcLine(byte[] buffer, int startIndex,
|
||||
int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats);
|
||||
|
||||
/** @hide */
|
||||
public static final native int[] getPidsForCommands(String[] cmds);
|
||||
|
||||
/**
|
||||
* Gets the total Pss value for a given process, in bytes.
|
||||
*
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
#define LOG_TAG "android.os.Debug"
|
||||
#include "JNIHelp.h"
|
||||
#include "jni.h"
|
||||
#include <utils/String8.h>
|
||||
#include "utils/misc.h"
|
||||
#include "cutils/debugger.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -538,6 +541,35 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz,
|
||||
}
|
||||
|
||||
|
||||
static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz,
|
||||
jint pid, jstring fileName)
|
||||
{
|
||||
if (fileName == NULL) {
|
||||
jniThrowNullPointerException(env, NULL);
|
||||
return;
|
||||
}
|
||||
const jchar* str = env->GetStringCritical(fileName, 0);
|
||||
String8 fileName8;
|
||||
if (str) {
|
||||
fileName8 = String8(str, env->GetStringLength(fileName));
|
||||
env->ReleaseStringCritical(fileName, str);
|
||||
}
|
||||
|
||||
int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (lseek(fd, 0, SEEK_END) < 0) {
|
||||
fprintf(stderr, "lseek: %s\n", strerror(errno));
|
||||
} else {
|
||||
dump_backtrace_to_file(pid, fd);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* JNI registration.
|
||||
*/
|
||||
@@ -569,6 +601,8 @@ static JNINativeMethod gMethods[] = {
|
||||
(void*)android_os_Debug_getProxyObjectCount },
|
||||
{ "getBinderDeathObjectCount", "()I",
|
||||
(void*)android_os_Debug_getDeathObjectCount },
|
||||
{ "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
|
||||
(void*)android_os_Debug_dumpNativeBacktraceToFile },
|
||||
};
|
||||
|
||||
int register_android_os_Debug(JNIEnv *env)
|
||||
|
||||
@@ -892,6 +892,93 @@ static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
|
||||
return pss * 1024;
|
||||
}
|
||||
|
||||
jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz,
|
||||
jobjectArray commandNames)
|
||||
{
|
||||
if (commandNames == NULL) {
|
||||
jniThrowNullPointerException(env, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Vector<String8> commands;
|
||||
|
||||
jsize count = env->GetArrayLength(commandNames);
|
||||
|
||||
for (int i=0; i<count; i++) {
|
||||
jobject obj = env->GetObjectArrayElement(commandNames, i);
|
||||
if (obj != NULL) {
|
||||
const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
|
||||
if (str8 == NULL) {
|
||||
jniThrowNullPointerException(env, "Element in commandNames");
|
||||
return NULL;
|
||||
}
|
||||
commands.add(String8(str8));
|
||||
env->ReleaseStringUTFChars((jstring)obj, str8);
|
||||
} else {
|
||||
jniThrowNullPointerException(env, "Element in commandNames");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<jint> pids;
|
||||
|
||||
DIR *proc = opendir("/proc");
|
||||
if (proc == NULL) {
|
||||
fprintf(stderr, "/proc: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dirent *d;
|
||||
while ((d = readdir(proc))) {
|
||||
int pid = atoi(d->d_name);
|
||||
if (pid <= 0) continue;
|
||||
|
||||
char path[PATH_MAX];
|
||||
char data[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
|
||||
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
continue;
|
||||
}
|
||||
const int len = read(fd, data, sizeof(data)-1);
|
||||
close(fd);
|
||||
|
||||
if (len < 0) {
|
||||
continue;
|
||||
}
|
||||
data[len] = 0;
|
||||
|
||||
for (int i=0; i<len; i++) {
|
||||
if (data[i] == ' ') {
|
||||
data[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i=0; i<commands.size(); i++) {
|
||||
if (commands[i] == data) {
|
||||
pids.add(pid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(proc);
|
||||
|
||||
jintArray pidArray = env->NewIntArray(pids.size());
|
||||
if (pidArray == NULL) {
|
||||
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pids.size() > 0) {
|
||||
env->SetIntArrayRegion(pidArray, 0, pids.size(), pids.array());
|
||||
}
|
||||
|
||||
return pidArray;
|
||||
}
|
||||
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"myPid", "()I", (void*)android_os_Process_myPid},
|
||||
{"myTid", "()I", (void*)android_os_Process_myTid},
|
||||
@@ -919,6 +1006,7 @@ static const JNINativeMethod methods[] = {
|
||||
{"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
|
||||
{"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
|
||||
{"getPss", "(I)J", (void*)android_os_Process_getPss},
|
||||
{"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands},
|
||||
//{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
|
||||
};
|
||||
|
||||
|
||||
@@ -67,6 +67,12 @@ public class Watchdog extends Thread {
|
||||
|
||||
static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
|
||||
|
||||
static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
|
||||
"/system/bin/mediaserver",
|
||||
"/system/bin/sdcard",
|
||||
"/system/bin/surfaceflinger"
|
||||
};
|
||||
|
||||
static Watchdog sWatchdog;
|
||||
|
||||
/* This handler will be used to post message back onto the main thread */
|
||||
@@ -414,7 +420,8 @@ public class Watchdog extends Thread {
|
||||
// trace and wait another half.
|
||||
ArrayList<Integer> pids = new ArrayList<Integer>();
|
||||
pids.add(Process.myPid());
|
||||
ActivityManagerService.dumpStackTraces(true, pids, null, null);
|
||||
ActivityManagerService.dumpStackTraces(true, pids, null, null,
|
||||
NATIVE_STACKS_OF_INTEREST);
|
||||
waitedHalf = true;
|
||||
continue;
|
||||
}
|
||||
@@ -434,7 +441,7 @@ public class Watchdog extends Thread {
|
||||
// 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.
|
||||
final File stack = ActivityManagerService.dumpStackTraces(
|
||||
!waitedHalf, pids, null, null);
|
||||
!waitedHalf, pids, null, null, NATIVE_STACKS_OF_INTEREST);
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -3019,10 +3019,11 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
* appended to any existing file content.
|
||||
* @param firstPids of dalvik VM processes to dump stack traces for first
|
||||
* @param lastPids of dalvik VM processes to dump stack traces for last
|
||||
* @param nativeProcs optional list of native process names to dump stack crawls
|
||||
* @return file containing stack traces, or null if no dump file is configured
|
||||
*/
|
||||
public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> firstPids,
|
||||
ProcessStats processStats, SparseArray<Boolean> lastPids) {
|
||||
ProcessStats processStats, SparseArray<Boolean> lastPids, String[] nativeProcs) {
|
||||
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
|
||||
if (tracesPath == null || tracesPath.length() == 0) {
|
||||
return null;
|
||||
@@ -3042,12 +3043,12 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
return null;
|
||||
}
|
||||
|
||||
dumpStackTraces(tracesPath, firstPids, processStats, lastPids);
|
||||
dumpStackTraces(tracesPath, firstPids, processStats, lastPids, nativeProcs);
|
||||
return tracesFile;
|
||||
}
|
||||
|
||||
private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
|
||||
ProcessStats processStats, SparseArray<Boolean> lastPids) {
|
||||
ProcessStats processStats, SparseArray<Boolean> lastPids, String[] nativeProcs) {
|
||||
// Use a FileObserver to detect when traces finish writing.
|
||||
// The order of traces is considered important to maintain for legibility.
|
||||
FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
|
||||
@@ -3108,6 +3109,15 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
} finally {
|
||||
observer.stopWatching();
|
||||
}
|
||||
|
||||
if (nativeProcs != null) {
|
||||
int[] pids = Process.getPidsForCommands(nativeProcs);
|
||||
if (pids != null) {
|
||||
for (int pid : pids) {
|
||||
Debug.dumpNativeBacktraceToFile(pid, tracesPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void logAppTooSlow(ProcessRecord app, long startTime, String msg) {
|
||||
@@ -3156,7 +3166,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
if (app != null) {
|
||||
ArrayList<Integer> firstPids = new ArrayList<Integer>();
|
||||
firstPids.add(app.pid);
|
||||
dumpStackTraces(tracesPath, firstPids, null, null);
|
||||
dumpStackTraces(tracesPath, firstPids, null, null, null);
|
||||
}
|
||||
|
||||
File lastTracesFile = null;
|
||||
@@ -3264,7 +3274,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
final ProcessStats processStats = new ProcessStats(true);
|
||||
|
||||
File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids);
|
||||
File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids, null);
|
||||
|
||||
String cpuInfo = null;
|
||||
if (MONITOR_CPU_USAGE) {
|
||||
|
||||
Reference in New Issue
Block a user