Loading core/java/android/os/Debug.java +7 −0 Original line number Diff line number Diff line Loading @@ -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 Loading core/java/android/os/Process.java +3 −0 Original line number Diff line number Diff line Loading @@ -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. * Loading core/jni/android_os_Debug.cpp +34 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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. */ Loading Loading @@ -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) Loading core/jni/android_util_Process.cpp +88 −0 Original line number Diff line number Diff line Loading @@ -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}, Loading Loading @@ -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}, }; Loading services/java/com/android/server/Watchdog.java +9 −2 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; } Loading @@ -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. Loading Loading
core/java/android/os/Debug.java +7 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
core/java/android/os/Process.java +3 −0 Original line number Diff line number Diff line Loading @@ -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. * Loading
core/jni/android_os_Debug.cpp +34 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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. */ Loading Loading @@ -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) Loading
core/jni/android_util_Process.cpp +88 −0 Original line number Diff line number Diff line Loading @@ -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}, Loading Loading @@ -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}, }; Loading
services/java/com/android/server/Watchdog.java +9 −2 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; } Loading @@ -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. Loading