Home | History | Annotate | Download | only in dumpstate
      1 /*
      2  * Copyright (C) 2008 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 #include <dirent.h>
     18 #include <errno.h>
     19 #include <fcntl.h>
     20 #include <limits.h>
     21 #include <poll.h>
     22 #include <signal.h>
     23 #include <stdarg.h>
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <sys/inotify.h>
     28 #include <sys/stat.h>
     29 #include <sys/time.h>
     30 #include <sys/wait.h>
     31 #include <sys/klog.h>
     32 #include <time.h>
     33 #include <unistd.h>
     34 #include <sys/prctl.h>
     35 
     36 #include <cutils/debugger.h>
     37 #include <cutils/properties.h>
     38 #include <cutils/sockets.h>
     39 #include <private/android_filesystem_config.h>
     40 
     41 #include <selinux/android.h>
     42 
     43 #include "dumpstate.h"
     44 
     45 /* list of native processes to include in the native dumps */
     46 static const char* native_processes_to_dump[] = {
     47         "/system/bin/drmserver",
     48         "/system/bin/mediaserver",
     49         "/system/bin/sdcard",
     50         "/system/bin/surfaceflinger",
     51         NULL,
     52 };
     53 
     54 static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
     55     DIR *d;
     56     struct dirent *de;
     57 
     58     if (!(d = opendir("/proc"))) {
     59         printf("Failed to open /proc (%s)\n", strerror(errno));
     60         return;
     61     }
     62 
     63     printf("\n------ %s ------\n", header);
     64     while ((de = readdir(d))) {
     65         int pid;
     66         int fd;
     67         char cmdpath[255];
     68         char cmdline[255];
     69 
     70         if (!(pid = atoi(de->d_name))) {
     71             continue;
     72         }
     73 
     74         sprintf(cmdpath,"/proc/%d/cmdline", pid);
     75         memset(cmdline, 0, sizeof(cmdline));
     76         if ((fd = open(cmdpath, O_RDONLY)) < 0) {
     77             strcpy(cmdline, "N/A");
     78         } else {
     79             read(fd, cmdline, sizeof(cmdline) - 1);
     80             close(fd);
     81         }
     82         helper(pid, cmdline, arg);
     83     }
     84 
     85     closedir(d);
     86 }
     87 
     88 static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
     89     for_each_pid_func *func = arg;
     90     func(pid, cmdline);
     91 }
     92 
     93 void for_each_pid(for_each_pid_func func, const char *header) {
     94     __for_each_pid(for_each_pid_helper, header, func);
     95 }
     96 
     97 static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
     98     DIR *d;
     99     struct dirent *de;
    100     char taskpath[255];
    101     for_each_tid_func *func = arg;
    102 
    103     sprintf(taskpath, "/proc/%d/task", pid);
    104 
    105     if (!(d = opendir(taskpath))) {
    106         printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
    107         return;
    108     }
    109 
    110     func(pid, pid, cmdline);
    111 
    112     while ((de = readdir(d))) {
    113         int tid;
    114         int fd;
    115         char commpath[255];
    116         char comm[255];
    117 
    118         if (!(tid = atoi(de->d_name))) {
    119             continue;
    120         }
    121 
    122         if (tid == pid)
    123             continue;
    124 
    125         sprintf(commpath,"/proc/%d/comm", tid);
    126         memset(comm, 0, sizeof(comm));
    127         if ((fd = open(commpath, O_RDONLY)) < 0) {
    128             strcpy(comm, "N/A");
    129         } else {
    130             char *c;
    131             read(fd, comm, sizeof(comm) - 1);
    132             close(fd);
    133 
    134             c = strrchr(comm, '\n');
    135             if (c) {
    136                 *c = '\0';
    137             }
    138         }
    139         func(pid, tid, comm);
    140     }
    141 
    142     closedir(d);
    143 }
    144 
    145 void for_each_tid(for_each_tid_func func, const char *header) {
    146     __for_each_pid(for_each_tid_helper, header, func);
    147 }
    148 
    149 void show_wchan(int pid, int tid, const char *name) {
    150     char path[255];
    151     char buffer[255];
    152     int fd;
    153     char name_buffer[255];
    154 
    155     memset(buffer, 0, sizeof(buffer));
    156 
    157     sprintf(path, "/proc/%d/wchan", tid);
    158     if ((fd = open(path, O_RDONLY)) < 0) {
    159         printf("Failed to open '%s' (%s)\n", path, strerror(errno));
    160         return;
    161     }
    162 
    163     if (read(fd, buffer, sizeof(buffer)) < 0) {
    164         printf("Failed to read '%s' (%s)\n", path, strerror(errno));
    165         goto out_close;
    166     }
    167 
    168     snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
    169              pid == tid ? 0 : 3, "", name);
    170 
    171     printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
    172 
    173 out_close:
    174     close(fd);
    175     return;
    176 }
    177 
    178 void do_dmesg() {
    179     printf("------ KERNEL LOG (dmesg) ------\n");
    180     /* Get size of kernel buffer */
    181     int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
    182     if (size <= 0) {
    183         printf("Unexpected klogctl return value: %d\n\n", size);
    184         return;
    185     }
    186     char *buf = (char *) malloc(size + 1);
    187     if (buf == NULL) {
    188         printf("memory allocation failed\n\n");
    189         return;
    190     }
    191     int retval = klogctl(KLOG_READ_ALL, buf, size);
    192     if (retval < 0) {
    193         printf("klogctl failure\n\n");
    194         free(buf);
    195         return;
    196     }
    197     buf[retval] = '\0';
    198     printf("%s\n\n", buf);
    199     free(buf);
    200     return;
    201 }
    202 
    203 void do_showmap(int pid, const char *name) {
    204     char title[255];
    205     char arg[255];
    206 
    207     sprintf(title, "SHOW MAP %d (%s)", pid, name);
    208     sprintf(arg, "%d", pid);
    209     run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL);
    210 }
    211 
    212 /* prints the contents of a file */
    213 int dump_file(const char *title, const char* path) {
    214     char buffer[32768];
    215     int fd = open(path, O_RDONLY);
    216     if (fd < 0) {
    217         int err = errno;
    218         if (title) printf("------ %s (%s) ------\n", title, path);
    219         printf("*** %s: %s\n", path, strerror(err));
    220         if (title) printf("\n");
    221         return -1;
    222     }
    223 
    224     if (title) printf("------ %s (%s", title, path);
    225 
    226     if (title) {
    227         struct stat st;
    228         if (memcmp(path, "/proc/", 6) && memcmp(path, "/sys/", 5) && !fstat(fd, &st)) {
    229             char stamp[80];
    230             time_t mtime = st.st_mtime;
    231             strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
    232             printf(": %s", stamp);
    233         }
    234         printf(") ------\n");
    235     }
    236 
    237     int newline = 0;
    238     for (;;) {
    239         int ret = read(fd, buffer, sizeof(buffer));
    240         if (ret > 0) {
    241             newline = (buffer[ret - 1] == '\n');
    242             ret = fwrite(buffer, ret, 1, stdout);
    243         }
    244         if (ret <= 0) break;
    245     }
    246 
    247     close(fd);
    248     if (!newline) printf("\n");
    249     if (title) printf("\n");
    250     return 0;
    251 }
    252 
    253 /* forks a command and waits for it to finish */
    254 int run_command(const char *title, int timeout_seconds, const char *command, ...) {
    255     fflush(stdout);
    256     clock_t start = clock();
    257     pid_t pid = fork();
    258 
    259     /* handle error case */
    260     if (pid < 0) {
    261         printf("*** fork: %s\n", strerror(errno));
    262         return pid;
    263     }
    264 
    265     /* handle child case */
    266     if (pid == 0) {
    267         const char *args[1024] = {command};
    268         size_t arg;
    269 
    270         /* make sure the child dies when dumpstate dies */
    271         prctl(PR_SET_PDEATHSIG, SIGKILL);
    272 
    273         va_list ap;
    274         va_start(ap, command);
    275         if (title) printf("------ %s (%s", title, command);
    276         for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
    277             args[arg] = va_arg(ap, const char *);
    278             if (args[arg] == NULL) break;
    279             if (title) printf(" %s", args[arg]);
    280         }
    281         if (title) printf(") ------\n");
    282         fflush(stdout);
    283 
    284         execvp(command, (char**) args);
    285         printf("*** exec(%s): %s\n", command, strerror(errno));
    286         fflush(stdout);
    287         _exit(-1);
    288     }
    289 
    290     /* handle parent case */
    291     for (;;) {
    292         int status;
    293         pid_t p = waitpid(pid, &status, WNOHANG);
    294         float elapsed = (float) (clock() - start) / CLOCKS_PER_SEC;
    295         if (p == pid) {
    296             if (WIFSIGNALED(status)) {
    297                 printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
    298             } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
    299                 printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
    300             }
    301             if (title) printf("[%s: %.1fs elapsed]\n\n", command, elapsed);
    302             return status;
    303         }
    304 
    305         if (timeout_seconds && elapsed > timeout_seconds) {
    306             printf("*** %s: Timed out after %.1fs (killing pid %d)\n", command, elapsed, pid);
    307             kill(pid, SIGTERM);
    308             return -1;
    309         }
    310 
    311         usleep(100000);  // poll every 0.1 sec
    312     }
    313 }
    314 
    315 size_t num_props = 0;
    316 static char* props[2000];
    317 
    318 static void print_prop(const char *key, const char *name, void *user) {
    319     (void) user;
    320     if (num_props < sizeof(props) / sizeof(props[0])) {
    321         char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10];
    322         snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name);
    323         props[num_props++] = strdup(buf);
    324     }
    325 }
    326 
    327 static int compare_prop(const void *a, const void *b) {
    328     return strcmp(*(char * const *) a, *(char * const *) b);
    329 }
    330 
    331 /* prints all the system properties */
    332 void print_properties() {
    333     size_t i;
    334     num_props = 0;
    335     property_list(print_prop, NULL);
    336     qsort(&props, num_props, sizeof(props[0]), compare_prop);
    337 
    338     printf("------ SYSTEM PROPERTIES ------\n");
    339     for (i = 0; i < num_props; ++i) {
    340         fputs(props[i], stdout);
    341         free(props[i]);
    342     }
    343     printf("\n");
    344 }
    345 
    346 /* redirect output to a service control socket */
    347 void redirect_to_socket(FILE *redirect, const char *service) {
    348     int s = android_get_control_socket(service);
    349     if (s < 0) {
    350         fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno));
    351         exit(1);
    352     }
    353     if (listen(s, 4) < 0) {
    354         fprintf(stderr, "listen(control socket): %s\n", strerror(errno));
    355         exit(1);
    356     }
    357 
    358     struct sockaddr addr;
    359     socklen_t alen = sizeof(addr);
    360     int fd = accept(s, &addr, &alen);
    361     if (fd < 0) {
    362         fprintf(stderr, "accept(control socket): %s\n", strerror(errno));
    363         exit(1);
    364     }
    365 
    366     fflush(redirect);
    367     dup2(fd, fileno(redirect));
    368     close(fd);
    369 }
    370 
    371 /* redirect output to a file, optionally gzipping; returns gzip pid (or -1) */
    372 pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) {
    373     char *chp = path;
    374 
    375     /* skip initial slash */
    376     if (chp[0] == '/')
    377         chp++;
    378 
    379     /* create leading directories, if necessary */
    380     while (chp && chp[0]) {
    381         chp = strchr(chp, '/');
    382         if (chp) {
    383             *chp = 0;
    384             mkdir(path, 0770);  /* drwxrwx--- */
    385             *chp++ = '/';
    386         }
    387     }
    388 
    389     int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    390     if (fd < 0) {
    391         fprintf(stderr, "%s: %s\n", path, strerror(errno));
    392         exit(1);
    393     }
    394 
    395     pid_t gzip_pid = -1;
    396     if (gzip_level > 0) {
    397         int fds[2];
    398         if (pipe(fds)) {
    399             fprintf(stderr, "pipe: %s\n", strerror(errno));
    400             exit(1);
    401         }
    402 
    403         fflush(redirect);
    404         fflush(stdout);
    405 
    406         gzip_pid = fork();
    407         if (gzip_pid < 0) {
    408             fprintf(stderr, "fork: %s\n", strerror(errno));
    409             exit(1);
    410         }
    411 
    412         if (gzip_pid == 0) {
    413             dup2(fds[0], STDIN_FILENO);
    414             dup2(fd, STDOUT_FILENO);
    415 
    416             close(fd);
    417             close(fds[0]);
    418             close(fds[1]);
    419 
    420             char level[10];
    421             snprintf(level, sizeof(level), "-%d", gzip_level);
    422             execlp("gzip", "gzip", level, NULL);
    423             fprintf(stderr, "exec(gzip): %s\n", strerror(errno));
    424             _exit(-1);
    425         }
    426 
    427         close(fd);
    428         close(fds[0]);
    429         fd = fds[1];
    430     }
    431 
    432     dup2(fd, fileno(redirect));
    433     close(fd);
    434     return gzip_pid;
    435 }
    436 
    437 static bool should_dump_native_traces(const char* path) {
    438     for (const char** p = native_processes_to_dump; *p; p++) {
    439         if (!strcmp(*p, path)) {
    440             return true;
    441         }
    442     }
    443     return false;
    444 }
    445 
    446 /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
    447 const char *dump_traces() {
    448     const char* result = NULL;
    449 
    450     char traces_path[PROPERTY_VALUE_MAX] = "";
    451     property_get("dalvik.vm.stack-trace-file", traces_path, "");
    452     if (!traces_path[0]) return NULL;
    453 
    454     /* move the old traces.txt (if any) out of the way temporarily */
    455     char anr_traces_path[PATH_MAX];
    456     strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path));
    457     strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path));
    458     if (rename(traces_path, anr_traces_path) && errno != ENOENT) {
    459         fprintf(stderr, "rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno));
    460         return NULL;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
    461     }
    462 
    463     /* make the directory if necessary */
    464     char anr_traces_dir[PATH_MAX];
    465     strlcpy(anr_traces_dir, traces_path, sizeof(anr_traces_dir));
    466     char *slash = strrchr(anr_traces_dir, '/');
    467     if (slash != NULL) {
    468         *slash = '\0';
    469         if (!mkdir(anr_traces_dir, 0775)) {
    470             chown(anr_traces_dir, AID_SYSTEM, AID_SYSTEM);
    471             chmod(anr_traces_dir, 0775);
    472             if (selinux_android_restorecon(anr_traces_dir) == -1) {
    473                 fprintf(stderr, "restorecon failed for %s: %s\n", anr_traces_dir, strerror(errno));
    474             }
    475         } else if (errno != EEXIST) {
    476             fprintf(stderr, "mkdir(%s): %s\n", anr_traces_dir, strerror(errno));
    477             return NULL;
    478         }
    479     }
    480 
    481     /* create a new, empty traces.txt file to receive stack dumps */
    482     int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666);  /* -rw-rw-rw- */
    483     if (fd < 0) {
    484         fprintf(stderr, "%s: %s\n", traces_path, strerror(errno));
    485         return NULL;
    486     }
    487     int chmod_ret = fchmod(fd, 0666);
    488     if (chmod_ret < 0) {
    489         fprintf(stderr, "fchmod on %s failed: %s\n", traces_path, strerror(errno));
    490         close(fd);
    491         return NULL;
    492     }
    493 
    494     /* walk /proc and kill -QUIT all Dalvik processes */
    495     DIR *proc = opendir("/proc");
    496     if (proc == NULL) {
    497         fprintf(stderr, "/proc: %s\n", strerror(errno));
    498         goto error_close_fd;
    499     }
    500 
    501     /* use inotify to find when processes are done dumping */
    502     int ifd = inotify_init();
    503     if (ifd < 0) {
    504         fprintf(stderr, "inotify_init: %s\n", strerror(errno));
    505         goto error_close_fd;
    506     }
    507 
    508     int wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE);
    509     if (wfd < 0) {
    510         fprintf(stderr, "inotify_add_watch(%s): %s\n", traces_path, strerror(errno));
    511         goto error_close_ifd;
    512     }
    513 
    514     struct dirent *d;
    515     int dalvik_found = 0;
    516     while ((d = readdir(proc))) {
    517         int pid = atoi(d->d_name);
    518         if (pid <= 0) continue;
    519 
    520         char path[PATH_MAX];
    521         char data[PATH_MAX];
    522         snprintf(path, sizeof(path), "/proc/%d/exe", pid);
    523         ssize_t len = readlink(path, data, sizeof(data) - 1);
    524         if (len <= 0) {
    525             continue;
    526         }
    527         data[len] = '\0';
    528 
    529         if (!strcmp(data, "/system/bin/app_process")) {
    530             /* skip zygote -- it won't dump its stack anyway */
    531             snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
    532             int fd = open(path, O_RDONLY);
    533             len = read(fd, data, sizeof(data) - 1);
    534             close(fd);
    535             if (len <= 0) {
    536                 continue;
    537             }
    538             data[len] = '\0';
    539             if (!strcmp(data, "zygote")) {
    540                 continue;
    541             }
    542 
    543             ++dalvik_found;
    544             if (kill(pid, SIGQUIT)) {
    545                 fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
    546                 continue;
    547             }
    548 
    549             /* wait for the writable-close notification from inotify */
    550             struct pollfd pfd = { ifd, POLLIN, 0 };
    551             int ret = poll(&pfd, 1, 200);  /* 200 msec timeout */
    552             if (ret < 0) {
    553                 fprintf(stderr, "poll: %s\n", strerror(errno));
    554             } else if (ret == 0) {
    555                 fprintf(stderr, "warning: timed out dumping pid %d\n", pid);
    556             } else {
    557                 struct inotify_event ie;
    558                 read(ifd, &ie, sizeof(ie));
    559             }
    560         } else if (should_dump_native_traces(data)) {
    561             /* dump native process if appropriate */
    562             if (lseek(fd, 0, SEEK_END) < 0) {
    563                 fprintf(stderr, "lseek: %s\n", strerror(errno));
    564             } else {
    565                 dump_backtrace_to_file(pid, fd);
    566             }
    567         }
    568     }
    569 
    570     if (dalvik_found == 0) {
    571         fprintf(stderr, "Warning: no Dalvik processes found to dump stacks\n");
    572     }
    573 
    574     static char dump_traces_path[PATH_MAX];
    575     strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path));
    576     strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path));
    577     if (rename(traces_path, dump_traces_path)) {
    578         fprintf(stderr, "rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno));
    579         goto error_close_ifd;
    580     }
    581     result = dump_traces_path;
    582 
    583     /* replace the saved [ANR] traces.txt file */
    584     rename(anr_traces_path, traces_path);
    585 
    586 error_close_ifd:
    587     close(ifd);
    588 error_close_fd:
    589     close(fd);
    590     return result;
    591 }
    592 
    593 void play_sound(const char* path) {
    594     run_command(NULL, 5, "/system/bin/stagefright", "-o", "-a", path, NULL);
    595 }
    596