diff options
author | Dianne Hackborn <hackbod@google.com> | 2012-06-11 10:37:51 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-06-11 10:37:51 -0700 |
commit | a7e3a1e0e7d308e7e78a1992038a34485d04ab29 (patch) | |
tree | 5714a6058e534f2c136eb146eb074ec8d2a54eb6 | |
parent | 913bf80416a81f2783376939e7ad0b956975b05c (diff) | |
parent | f72467ad9843bf5d4b75fb308386e77ebb5c3447 (diff) | |
download | frameworks_base-a7e3a1e0e7d308e7e78a1992038a34485d04ab29.zip frameworks_base-a7e3a1e0e7d308e7e78a1992038a34485d04ab29.tar.gz frameworks_base-a7e3a1e0e7d308e7e78a1992038a34485d04ab29.tar.bz2 |
Merge "Include important native processes in watchdog stacks." into jb-dev
-rw-r--r-- | core/java/android/os/Debug.java | 7 | ||||
-rw-r--r-- | core/java/android/os/Process.java | 3 | ||||
-rw-r--r-- | core/jni/android_os_Debug.cpp | 34 | ||||
-rw-r--r-- | core/jni/android_util_Process.cpp | 88 | ||||
-rw-r--r-- | services/java/com/android/server/Watchdog.java | 11 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 20 |
6 files changed, 156 insertions, 7 deletions
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 98fe06a..591cd0e 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -1326,6 +1326,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 * @param depth the depth of stack to return information for. diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 18fd3cb..8eaeb1d 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -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. * diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 9586717..6724f36 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -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) diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 027ed16..0290857 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -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}, }; diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java index 728fb26..c239382 100644 --- a/services/java/com/android/server/Watchdog.java +++ b/services/java/com/android/server/Watchdog.java @@ -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. diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 63d6fa3..63455ee 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -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) { |