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/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