diff options
author | Christopher Tate <ctate@google.com> | 2010-06-04 14:55:02 -0700 |
---|---|---|
committer | Christopher Tate <ctate@google.com> | 2010-06-04 14:55:02 -0700 |
commit | ecaa7b41ca49154ceaa9a7504eb0a86b89a96026 (patch) | |
tree | a598349af5efb1e2a57e92862cf4a9b68d33f284 /core | |
parent | de56c27dab020bf85187c8bcfc6842cb31006c59 (diff) | |
download | frameworks_base-ecaa7b41ca49154ceaa9a7504eb0a86b89a96026.zip frameworks_base-ecaa7b41ca49154ceaa9a7504eb0a86b89a96026.tar.gz frameworks_base-ecaa7b41ca49154ceaa9a7504eb0a86b89a96026.tar.bz2 |
Watchdog now records kernel stacks when it fires
The kernel threads are appended to the usual /data/anr/traces.txt file
and dropboxed along with the usual Dalvik stack dumps.
Change-Id: I120f1f5ee54c965efe9ac0c7f40fdef56385f1fa
NOTE: this change depends on the kernel publishing /proc/$PID/stack
Diffstat (limited to 'core')
-rw-r--r-- | core/jni/Android.mk | 1 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
-rw-r--r-- | core/jni/android_server_Watchdog.cpp | 111 |
3 files changed, 114 insertions, 0 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a39d06b..df1ab9e 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -120,6 +120,7 @@ LOCAL_SRC_FILES:= \ android_server_BluetoothService.cpp \ android_server_BluetoothEventLoop.cpp \ android_server_BluetoothA2dpService.cpp \ + android_server_Watchdog.cpp \ android_message_digest_sha1.cpp \ android_ddm_DdmHandleNativeHeap.cpp \ android_location_GpsLocationProvider.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 9fbf171..d38d748 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -153,6 +153,7 @@ extern int register_android_bluetooth_ScoSocket(JNIEnv *env); extern int register_android_server_BluetoothService(JNIEnv* env); extern int register_android_server_BluetoothEventLoop(JNIEnv *env); extern int register_android_server_BluetoothA2dpService(JNIEnv* env); +extern int register_android_server_Watchdog(JNIEnv* env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env); extern int register_android_location_GpsLocationProvider(JNIEnv* env); @@ -1276,6 +1277,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_server_BluetoothService), REG_JNI(register_android_server_BluetoothEventLoop), REG_JNI(register_android_server_BluetoothA2dpService), + REG_JNI(register_android_server_Watchdog), REG_JNI(register_android_message_digest_sha1), REG_JNI(register_android_ddm_DdmHandleNativeHeap), REG_JNI(register_android_location_GpsLocationProvider), diff --git a/core/jni/android_server_Watchdog.cpp b/core/jni/android_server_Watchdog.cpp new file mode 100644 index 0000000..2a90db7 --- /dev/null +++ b/core/jni/android_server_Watchdog.cpp @@ -0,0 +1,111 @@ +/* + ** Copyright 2010, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#define LOG_TAG "Watchdog_N" +#include <utils/Log.h> + +#include <sys/types.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> +#include <errno.h> + +#include "jni.h" +#include "JNIHelp.h" +#include <android_runtime/AndroidRuntime.h> + +static void dumpOneStack(int tid, int outFd) { + char buf[64]; + + snprintf(buf, sizeof(buf), "/proc/%d/stack", tid); + int stackFd = open(buf, O_RDONLY); + if (stackFd >= 0) { + // header for readability + strncat(buf, ":\n", sizeof(buf) - strlen(buf) - 1); + write(outFd, buf, strlen(buf)); + + // copy the stack dump text + int nBytes; + while ((nBytes = read(stackFd, buf, sizeof(buf))) > 0) { + write(outFd, buf, nBytes); + } + + // footer and done + write(outFd, "\n", 1); + close(stackFd); + } else { + LOGE("Unable to open stack of tid %d : %d (%s)", tid, errno, strerror(errno)); + } +} + +static void dumpKernelStacks(JNIEnv* env, jobject clazz, jstring pathStr) { + char buf[128]; + DIR* taskdir; + + LOGI("dumpKernelStacks"); + if (!pathStr) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Null path"); + return; + } + + const char *path = env->GetStringUTFChars(pathStr, NULL); + + int outFd = open(path, O_WRONLY | O_APPEND | O_CREAT); + if (outFd < 0) { + LOGE("Unable to open stack dump file: %d (%s)", errno, strerror(errno)); + goto done; + } + + snprintf(buf, sizeof(buf), "\n----- begin pid %d kernel stacks -----\n", getpid()); + write(outFd, buf, strlen(buf)); + + // look up the list of all threads in this process + snprintf(buf, sizeof(buf), "/proc/%d/task", getpid()); + taskdir = opendir(buf); + if (taskdir != NULL) { + struct dirent * ent; + while ((ent = readdir(taskdir)) != NULL) { + int tid = atoi(ent->d_name); + if (tid > 0 && tid <= 65535) { + // dump each stack trace + dumpOneStack(tid, outFd); + } + } + closedir(taskdir); + } + + snprintf(buf, sizeof(buf), "----- end pid %d kernel stacks -----\n", getpid()); + write(outFd, buf, strlen(buf)); + + close(outFd); +done: + env->ReleaseStringUTFChars(pathStr, path); +} + +// ---------------------------------------- + +namespace android { + +static const JNINativeMethod g_methods[] = { + { "native_dumpKernelStacks", "(Ljava/lang/String;)V", (void*)dumpKernelStacks }, +}; + +int register_android_server_Watchdog(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, "com/android/server/Watchdog", + g_methods, NELEM(g_methods)); +} + +} |