1 /* 2 ** Copyright 2010, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 #define LOG_TAG "Watchdog_N" 18 #include <utils/Log.h> 19 20 #include <sys/types.h> 21 #include <fcntl.h> 22 #include <dirent.h> 23 #include <string.h> 24 #include <errno.h> 25 26 #include "jni.h" 27 #include "JNIHelp.h" 28 #include <android_runtime/AndroidRuntime.h> 29 30 static void dumpOneStack(int tid, int outFd) { 31 char buf[64]; 32 33 snprintf(buf, sizeof(buf), "/proc/%d/stack", tid); 34 int stackFd = open(buf, O_RDONLY); 35 if (stackFd >= 0) { 36 // header for readability 37 strncat(buf, ":\n", sizeof(buf) - strlen(buf) - 1); 38 write(outFd, buf, strlen(buf)); 39 40 // copy the stack dump text 41 int nBytes; 42 while ((nBytes = read(stackFd, buf, sizeof(buf))) > 0) { 43 write(outFd, buf, nBytes); 44 } 45 46 // footer and done 47 write(outFd, "\n", 1); 48 close(stackFd); 49 } else { 50 LOGE("Unable to open stack of tid %d : %d (%s)", tid, errno, strerror(errno)); 51 } 52 } 53 54 static void dumpKernelStacks(JNIEnv* env, jobject clazz, jstring pathStr) { 55 char buf[128]; 56 DIR* taskdir; 57 58 LOGI("dumpKernelStacks"); 59 if (!pathStr) { 60 jniThrowException(env, "java/lang/IllegalArgumentException", "Null path"); 61 return; 62 } 63 64 const char *path = env->GetStringUTFChars(pathStr, NULL); 65 66 int outFd = open(path, O_WRONLY | O_APPEND | O_CREAT); 67 if (outFd < 0) { 68 LOGE("Unable to open stack dump file: %d (%s)", errno, strerror(errno)); 69 goto done; 70 } 71 72 snprintf(buf, sizeof(buf), "\n----- begin pid %d kernel stacks -----\n", getpid()); 73 write(outFd, buf, strlen(buf)); 74 75 // look up the list of all threads in this process 76 snprintf(buf, sizeof(buf), "/proc/%d/task", getpid()); 77 taskdir = opendir(buf); 78 if (taskdir != NULL) { 79 struct dirent * ent; 80 while ((ent = readdir(taskdir)) != NULL) { 81 int tid = atoi(ent->d_name); 82 if (tid > 0 && tid <= 65535) { 83 // dump each stack trace 84 dumpOneStack(tid, outFd); 85 } 86 } 87 closedir(taskdir); 88 } 89 90 snprintf(buf, sizeof(buf), "----- end pid %d kernel stacks -----\n", getpid()); 91 write(outFd, buf, strlen(buf)); 92 93 close(outFd); 94 done: 95 env->ReleaseStringUTFChars(pathStr, path); 96 } 97 98 // ---------------------------------------- 99 100 namespace android { 101 102 static const JNINativeMethod g_methods[] = { 103 { "native_dumpKernelStacks", "(Ljava/lang/String;)V", (void*)dumpKernelStacks }, 104 }; 105 106 int register_android_server_Watchdog(JNIEnv* env) { 107 return AndroidRuntime::registerNativeMethods(env, "com/android/server/Watchdog", 108 g_methods, NELEM(g_methods)); 109 } 110 111 } 112