Home | History | Annotate | Download | only in jni
      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/stat.h>
     21 #include <sys/types.h>
     22 #include <fcntl.h>
     23 #include <dirent.h>
     24 #include <string.h>
     25 #include <errno.h>
     26 
     27 #include "jni.h"
     28 #include "JNIHelp.h"
     29 #include <android_runtime/AndroidRuntime.h>
     30 
     31 static void dumpOneStack(int tid, int outFd) {
     32     char buf[64];
     33 
     34     snprintf(buf, sizeof(buf), "/proc/%d/stack", tid);
     35     int stackFd = open(buf, O_RDONLY);
     36     if (stackFd >= 0) {
     37         // header for readability
     38         strncat(buf, ":\n", sizeof(buf) - strlen(buf) - 1);
     39         write(outFd, buf, strlen(buf));
     40 
     41         // copy the stack dump text
     42         int nBytes;
     43         while ((nBytes = read(stackFd, buf, sizeof(buf))) > 0) {
     44             write(outFd, buf, nBytes);
     45         }
     46 
     47         // footer and done
     48         write(outFd, "\n", 1);
     49         close(stackFd);
     50     } else {
     51         ALOGE("Unable to open stack of tid %d : %d (%s)", tid, errno, strerror(errno));
     52     }
     53 }
     54 
     55 static void dumpKernelStacks(JNIEnv* env, jobject clazz, jstring pathStr) {
     56     char buf[128];
     57     DIR* taskdir;
     58 
     59     ALOGI("dumpKernelStacks");
     60     if (!pathStr) {
     61         jniThrowException(env, "java/lang/IllegalArgumentException", "Null path");
     62         return;
     63     }
     64 
     65     const char *path = env->GetStringUTFChars(pathStr, NULL);
     66 
     67     int outFd = open(path, O_WRONLY | O_APPEND | O_CREAT,
     68         S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
     69     if (outFd < 0) {
     70         ALOGE("Unable to open stack dump file: %d (%s)", errno, strerror(errno));
     71         goto done;
     72     }
     73 
     74     snprintf(buf, sizeof(buf), "\n----- begin pid %d kernel stacks -----\n", getpid());
     75     write(outFd, buf, strlen(buf));
     76 
     77     // look up the list of all threads in this process
     78     snprintf(buf, sizeof(buf), "/proc/%d/task", getpid());
     79     taskdir = opendir(buf);
     80     if (taskdir != NULL) {
     81         struct dirent * ent;
     82         while ((ent = readdir(taskdir)) != NULL) {
     83             int tid = atoi(ent->d_name);
     84             if (tid > 0 && tid <= 65535) {
     85                 // dump each stack trace
     86                 dumpOneStack(tid, outFd);
     87             }
     88         }
     89         closedir(taskdir);
     90     }
     91 
     92     snprintf(buf, sizeof(buf), "----- end pid %d kernel stacks -----\n", getpid());
     93     write(outFd, buf, strlen(buf));
     94 
     95     close(outFd);
     96 done:
     97     env->ReleaseStringUTFChars(pathStr, path);
     98 }
     99 
    100 // ----------------------------------------
    101 
    102 namespace android {
    103 
    104 static const JNINativeMethod g_methods[] = {
    105     { "native_dumpKernelStacks", "(Ljava/lang/String;)V", (void*)dumpKernelStacks },
    106 };
    107 
    108 int register_android_server_Watchdog(JNIEnv* env) {
    109     return AndroidRuntime::registerNativeMethods(env, "com/android/server/Watchdog",
    110                                                  g_methods, NELEM(g_methods));
    111 }
    112 
    113 }
    114