utils.cpp revision d907b32052aca02ad679e6ae786848d328723080
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
45static const int64_t NANOS_PER_SEC = 1000000000;
46
47/* list of native processes to include in the native dumps */
48static const char* native_processes_to_dump[] = {
49        "/system/bin/drmserver",
50        "/system/bin/mediaserver",
51        "/system/bin/sdcard",
52        "/system/bin/surfaceflinger",
53        "/system/bin/vehicle_network_service",
54        NULL,
55};
56
57static uint64_t nanotime() {
58    struct timespec ts;
59    clock_gettime(CLOCK_MONOTONIC, &ts);
60    return (uint64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
61}
62
63void for_each_userid(void (*func)(int), const char *header) {
64    ON_DRY_RUN_RETURN();
65    DIR *d;
66    struct dirent *de;
67
68    if (header) printf("\n------ %s ------\n", header);
69    func(0);
70
71    if (!(d = opendir("/data/system/users"))) {
72        printf("Failed to open /data/system/users (%s)\n", strerror(errno));
73        return;
74    }
75
76    while ((de = readdir(d))) {
77        int userid;
78        if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
79            continue;
80        }
81        func(userid);
82    }
83
84    closedir(d);
85}
86
87static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
88    DIR *d;
89    struct dirent *de;
90
91    if (!(d = opendir("/proc"))) {
92        printf("Failed to open /proc (%s)\n", strerror(errno));
93        return;
94    }
95
96    printf("\n------ %s ------\n", header);
97    while ((de = readdir(d))) {
98        int pid;
99        int fd;
100        char cmdpath[255];
101        char cmdline[255];
102
103        if (!(pid = atoi(de->d_name))) {
104            continue;
105        }
106
107        sprintf(cmdpath,"/proc/%d/cmdline", pid);
108        memset(cmdline, 0, sizeof(cmdline));
109        if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) < 0) {
110            strcpy(cmdline, "N/A");
111        } else {
112            read(fd, cmdline, sizeof(cmdline) - 1);
113            close(fd);
114        }
115        helper(pid, cmdline, arg);
116    }
117
118    closedir(d);
119}
120
121static void for_each_pid_helper(int pid, const char *cmdline, void *arg) {
122    for_each_pid_func *func = (for_each_pid_func*) arg;
123    func(pid, cmdline);
124}
125
126void for_each_pid(for_each_pid_func func, const char *header) {
127    ON_DRY_RUN_RETURN();
128  __for_each_pid(for_each_pid_helper, header, (void *)func);
129}
130
131static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
132    DIR *d;
133    struct dirent *de;
134    char taskpath[255];
135    for_each_tid_func *func = (for_each_tid_func *) arg;
136
137    sprintf(taskpath, "/proc/%d/task", pid);
138
139    if (!(d = opendir(taskpath))) {
140        printf("Failed to open %s (%s)\n", taskpath, strerror(errno));
141        return;
142    }
143
144    func(pid, pid, cmdline);
145
146    while ((de = readdir(d))) {
147        int tid;
148        int fd;
149        char commpath[255];
150        char comm[255];
151
152        if (!(tid = atoi(de->d_name))) {
153            continue;
154        }
155
156        if (tid == pid)
157            continue;
158
159        sprintf(commpath,"/proc/%d/comm", tid);
160        memset(comm, 0, sizeof(comm));
161        if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
162            strcpy(comm, "N/A");
163        } else {
164            char *c;
165            read(fd, comm, sizeof(comm) - 1);
166            close(fd);
167
168            c = strrchr(comm, '\n');
169            if (c) {
170                *c = '\0';
171            }
172        }
173        func(pid, tid, comm);
174    }
175
176    closedir(d);
177}
178
179void for_each_tid(for_each_tid_func func, const char *header) {
180    ON_DRY_RUN_RETURN();
181    __for_each_pid(for_each_tid_helper, header, (void *) func);
182}
183
184void show_wchan(int pid, int tid, const char *name) {
185    ON_DRY_RUN_RETURN();
186    char path[255];
187    char buffer[255];
188    int fd;
189    char name_buffer[255];
190
191    memset(buffer, 0, sizeof(buffer));
192
193    sprintf(path, "/proc/%d/wchan", tid);
194    if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
195        printf("Failed to open '%s' (%s)\n", path, strerror(errno));
196        return;
197    }
198
199    if (read(fd, buffer, sizeof(buffer)) < 0) {
200        printf("Failed to read '%s' (%s)\n", path, strerror(errno));
201        goto out_close;
202    }
203
204    snprintf(name_buffer, sizeof(name_buffer), "%*s%s",
205             pid == tid ? 0 : 3, "", name);
206
207    printf("%-7d %-32s %s\n", tid, name_buffer, buffer);
208
209out_close:
210    close(fd);
211    return;
212}
213
214void do_dmesg() {
215    printf("------ KERNEL LOG (dmesg) ------\n");
216    ON_DRY_RUN_RETURN();
217    /* Get size of kernel buffer */
218    int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
219    if (size <= 0) {
220        printf("Unexpected klogctl return value: %d\n\n", size);
221        return;
222    }
223    char *buf = (char *) malloc(size + 1);
224    if (buf == NULL) {
225        printf("memory allocation failed\n\n");
226        return;
227    }
228    int retval = klogctl(KLOG_READ_ALL, buf, size);
229    if (retval < 0) {
230        printf("klogctl failure\n\n");
231        free(buf);
232        return;
233    }
234    buf[retval] = '\0';
235    printf("%s\n\n", buf);
236    free(buf);
237    return;
238}
239
240void do_showmap(int pid, const char *name) {
241    char title[255];
242    char arg[255];
243
244    sprintf(title, "SHOW MAP %d (%s)", pid, name);
245    sprintf(arg, "%d", pid);
246    run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL);
247}
248
249static int _dump_file_from_fd(const char *title, const char *path, int fd) {
250    if (title) printf("------ %s (%s", title, path);
251
252    if (title) {
253        struct stat st;
254        if (memcmp(path, "/proc/", 6) && memcmp(path, "/sys/", 5) && !fstat(fd, &st)) {
255            char stamp[80];
256            time_t mtime = st.st_mtime;
257            strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
258            printf(": %s", stamp);
259        }
260        printf(") ------\n");
261    }
262
263    bool newline = false;
264    fd_set read_set;
265    struct timeval tm;
266    while (1) {
267        FD_ZERO(&read_set);
268        FD_SET(fd, &read_set);
269        /* Timeout if no data is read for 30 seconds. */
270        tm.tv_sec = 30;
271        tm.tv_usec = 0;
272        uint64_t elapsed = nanotime();
273        int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, NULL, NULL, &tm));
274        if (ret == -1) {
275            printf("*** %s: select failed: %s\n", path, strerror(errno));
276            newline = true;
277            break;
278        } else if (ret == 0) {
279            elapsed = nanotime() - elapsed;
280            printf("*** %s: Timed out after %.3fs\n", path,
281                   (float) elapsed / NANOS_PER_SEC);
282            newline = true;
283            break;
284        } else {
285            char buffer[65536];
286            ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
287            if (bytes_read > 0) {
288                fwrite(buffer, bytes_read, 1, stdout);
289                newline = (buffer[bytes_read-1] == '\n');
290            } else {
291                if (bytes_read == -1) {
292                    printf("*** %s: Failed to read from fd: %s", path, strerror(errno));
293                    newline = true;
294                }
295                break;
296            }
297        }
298    }
299    close(fd);
300
301    if (!newline) printf("\n");
302    if (title) printf("\n");
303    return 0;
304}
305
306/* prints the contents of a file */
307int dump_file(const char *title, const char *path) {
308    if (title) printf("------ %s (%s) ------\n", title, path);
309    ON_DRY_RUN_RETURN(0);
310
311    int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
312    if (fd < 0) {
313        int err = errno;
314        printf("*** %s: %s\n", path, strerror(err));
315        if (title) printf("\n");
316        return -1;
317    }
318    return _dump_file_from_fd(title, path, fd);
319}
320
321/* calls skip to gate calling dump_from_fd recursively
322 * in the specified directory. dump_from_fd defaults to
323 * dump_file_from_fd above when set to NULL. skip defaults
324 * to false when set to NULL. dump_from_fd will always be
325 * called with title NULL.
326 */
327int dump_files(const char *title, const char *dir,
328        bool (*skip)(const char *path),
329        int (*dump_from_fd)(const char *title, const char *path, int fd)) {
330    DIR *dirp;
331    struct dirent *d;
332    char *newpath = NULL;
333    const char *slash = "/";
334    int fd, retval = 0;
335
336    if (title) {
337        printf("------ %s (%s) ------\n", title, dir);
338    }
339    ON_DRY_RUN_RETURN(0);
340
341    if (dir[strlen(dir) - 1] == '/') {
342        ++slash;
343    }
344    dirp = opendir(dir);
345    if (dirp == NULL) {
346        retval = -errno;
347        fprintf(stderr, "%s: %s\n", dir, strerror(errno));
348        return retval;
349    }
350
351    if (!dump_from_fd) {
352        dump_from_fd = dump_file_from_fd;
353    }
354    for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) {
355        if ((d->d_name[0] == '.')
356         && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
357          || (d->d_name[1] == '\0'))) {
358            continue;
359        }
360        asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
361                 (d->d_type == DT_DIR) ? "/" : "");
362        if (!newpath) {
363            retval = -errno;
364            continue;
365        }
366        if (skip && (*skip)(newpath)) {
367            continue;
368        }
369        if (d->d_type == DT_DIR) {
370            int ret = dump_files(NULL, newpath, skip, dump_from_fd);
371            if (ret < 0) {
372                retval = ret;
373            }
374            continue;
375        }
376        fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
377        if (fd < 0) {
378            retval = fd;
379            printf("*** %s: %s\n", newpath, strerror(errno));
380            continue;
381        }
382        (*dump_from_fd)(NULL, newpath, fd);
383    }
384    closedir(dirp);
385    if (title) {
386        printf("\n");
387    }
388    return retval;
389}
390
391/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
392 * it's possible to avoid issues where opening the file itself can get
393 * stuck.
394 */
395int dump_file_from_fd(const char *title, const char *path, int fd) {
396    ON_DRY_RUN_RETURN(0);
397    int flags = fcntl(fd, F_GETFL);
398    if (flags == -1) {
399        printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
400        return -1;
401    } else if (!(flags & O_NONBLOCK)) {
402        printf("*** %s: fd must have O_NONBLOCK set.\n", path);
403        return -1;
404    }
405    return _dump_file_from_fd(title, path, fd);
406}
407
408bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
409    sigset_t child_mask, old_mask;
410    sigemptyset(&child_mask);
411    sigaddset(&child_mask, SIGCHLD);
412
413    if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
414        printf("*** sigprocmask failed: %s\n", strerror(errno));
415        return false;
416    }
417
418    struct timespec ts;
419    ts.tv_sec = timeout_seconds;
420    ts.tv_nsec = 0;
421    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
422    int saved_errno = errno;
423    // Set the signals back the way they were.
424    if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
425        printf("*** sigprocmask failed: %s\n", strerror(errno));
426        if (ret == 0) {
427            return false;
428        }
429    }
430    if (ret == -1) {
431        errno = saved_errno;
432        if (errno == EAGAIN) {
433            errno = ETIMEDOUT;
434        } else {
435            printf("*** sigtimedwait failed: %s\n", strerror(errno));
436        }
437        return false;
438    }
439
440    pid_t child_pid = waitpid(pid, status, WNOHANG);
441    if (child_pid != pid) {
442        if (child_pid != -1) {
443            printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
444        } else {
445            printf("*** waitpid failed: %s\n", strerror(errno));
446        }
447        return false;
448    }
449    return true;
450}
451
452/* forks a command and waits for it to finish */
453int run_command(const char *title, int timeout_seconds, const char *command, ...) {
454    fflush(stdout);
455
456    const char *args[1024] = {command};
457    size_t arg;
458    va_list ap;
459    va_start(ap, command);
460    if (title) printf("------ %s (%s", title, command);
461    for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
462        args[arg] = va_arg(ap, const char *);
463        if (args[arg] == NULL) break;
464        if (title) printf(" %s", args[arg]);
465    }
466    if (title) printf(") ------\n");
467    fflush(stdout);
468
469    ON_DRY_RUN_RETURN(0);
470
471    return run_command_always(title, timeout_seconds, args);
472}
473
474/* forks a command and waits for it to finish */
475int run_command_always(const char *title, int timeout_seconds, const char *args[]) {
476    const char *command = args[0];
477
478    uint64_t start = nanotime();
479    pid_t pid = fork();
480
481    /* handle error case */
482    if (pid < 0) {
483        printf("*** fork: %s\n", strerror(errno));
484        return pid;
485    }
486
487    /* handle child case */
488    if (pid == 0) {
489
490        /* make sure the child dies when dumpstate dies */
491        prctl(PR_SET_PDEATHSIG, SIGKILL);
492
493        /* just ignore SIGPIPE, will go down with parent's */
494        struct sigaction sigact;
495        memset(&sigact, 0, sizeof(sigact));
496        sigact.sa_handler = SIG_IGN;
497        sigaction(SIGPIPE, &sigact, NULL);
498
499        execvp(command, (char**) args);
500        printf("*** exec(%s): %s\n", command, strerror(errno));
501        fflush(stdout);
502        _exit(-1);
503    }
504
505    /* handle parent case */
506    int status;
507    bool ret = waitpid_with_timeout(pid, timeout_seconds, &status);
508    uint64_t elapsed = nanotime() - start;
509    if (!ret) {
510        if (errno == ETIMEDOUT) {
511            printf("*** %s: Timed out after %.3fs (killing pid %d)\n", command,
512                   (float) elapsed / NANOS_PER_SEC, pid);
513        } else {
514            printf("*** %s: Error after %.4fs (killing pid %d)\n", command,
515                   (float) elapsed / NANOS_PER_SEC, pid);
516        }
517        kill(pid, SIGTERM);
518        if (!waitpid_with_timeout(pid, 5, NULL)) {
519            kill(pid, SIGKILL);
520            if (!waitpid_with_timeout(pid, 5, NULL)) {
521                printf("*** %s: Cannot kill %d even with SIGKILL.\n", command, pid);
522            }
523        }
524        return -1;
525    }
526
527    if (WIFSIGNALED(status)) {
528        printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
529    } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
530        printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
531    }
532    if (title) printf("[%s: %.3fs elapsed]\n\n", command, (float)elapsed / NANOS_PER_SEC);
533
534    return status;
535}
536
537size_t num_props = 0;
538static char* props[2000];
539
540static void print_prop(const char *key, const char *name, void *user) {
541    (void) user;
542    if (num_props < sizeof(props) / sizeof(props[0])) {
543        char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10];
544        snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name);
545        props[num_props++] = strdup(buf);
546    }
547}
548
549static int compare_prop(const void *a, const void *b) {
550    return strcmp(*(char * const *) a, *(char * const *) b);
551}
552
553/* prints all the system properties */
554void print_properties() {
555    printf("------ SYSTEM PROPERTIES ------\n");
556    ON_DRY_RUN_RETURN();
557    size_t i;
558    num_props = 0;
559    property_list(print_prop, NULL);
560    qsort(&props, num_props, sizeof(props[0]), compare_prop);
561
562    for (i = 0; i < num_props; ++i) {
563        fputs(props[i], stdout);
564        free(props[i]);
565    }
566    printf("\n");
567}
568
569/* redirect output to a service control socket */
570void redirect_to_socket(FILE *redirect, const char *service) {
571    int s = android_get_control_socket(service);
572    if (s < 0) {
573        fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno));
574        exit(1);
575    }
576    fcntl(s, F_SETFD, FD_CLOEXEC);
577    if (listen(s, 4) < 0) {
578        fprintf(stderr, "listen(control socket): %s\n", strerror(errno));
579        exit(1);
580    }
581
582    struct sockaddr addr;
583    socklen_t alen = sizeof(addr);
584    int fd = accept(s, &addr, &alen);
585    if (fd < 0) {
586        fprintf(stderr, "accept(control socket): %s\n", strerror(errno));
587        exit(1);
588    }
589
590    fflush(redirect);
591    dup2(fd, fileno(redirect));
592    close(fd);
593}
594
595/* redirect output to a file */
596void redirect_to_file(FILE *redirect, char *path) {
597    char *chp = path;
598
599    /* skip initial slash */
600    if (chp[0] == '/')
601        chp++;
602
603    /* create leading directories, if necessary */
604    while (chp && chp[0]) {
605        chp = strchr(chp, '/');
606        if (chp) {
607            *chp = 0;
608            mkdir(path, 0770);  /* drwxrwx--- */
609            *chp++ = '/';
610        }
611    }
612
613    int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
614                                     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
615    if (fd < 0) {
616        fprintf(stderr, "%s: %s\n", path, strerror(errno));
617        exit(1);
618    }
619
620    TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
621    close(fd);
622}
623
624static bool should_dump_native_traces(const char* path) {
625    for (const char** p = native_processes_to_dump; *p; p++) {
626        if (!strcmp(*p, path)) {
627            return true;
628        }
629    }
630    return false;
631}
632
633/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
634const char *dump_traces() {
635    ON_DRY_RUN_RETURN(NULL);
636    const char* result = NULL;
637
638    char traces_path[PROPERTY_VALUE_MAX] = "";
639    property_get("dalvik.vm.stack-trace-file", traces_path, "");
640    if (!traces_path[0]) return NULL;
641
642    /* move the old traces.txt (if any) out of the way temporarily */
643    char anr_traces_path[PATH_MAX];
644    strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path));
645    strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path));
646    if (rename(traces_path, anr_traces_path) && errno != ENOENT) {
647        fprintf(stderr, "rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno));
648        return NULL;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
649    }
650
651    /* create a new, empty traces.txt file to receive stack dumps */
652    int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
653                                     0666));  /* -rw-rw-rw- */
654    if (fd < 0) {
655        fprintf(stderr, "%s: %s\n", traces_path, strerror(errno));
656        return NULL;
657    }
658    int chmod_ret = fchmod(fd, 0666);
659    if (chmod_ret < 0) {
660        fprintf(stderr, "fchmod on %s failed: %s\n", traces_path, strerror(errno));
661        close(fd);
662        return NULL;
663    }
664
665    /* Variables below must be initialized before 'goto' statements */
666    int dalvik_found = 0;
667    int ifd, wfd = -1;
668
669    /* walk /proc and kill -QUIT all Dalvik processes */
670    DIR *proc = opendir("/proc");
671    if (proc == NULL) {
672        fprintf(stderr, "/proc: %s\n", strerror(errno));
673        goto error_close_fd;
674    }
675
676    /* use inotify to find when processes are done dumping */
677    ifd = inotify_init();
678    if (ifd < 0) {
679        fprintf(stderr, "inotify_init: %s\n", strerror(errno));
680        goto error_close_fd;
681    }
682
683    wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE);
684    if (wfd < 0) {
685        fprintf(stderr, "inotify_add_watch(%s): %s\n", traces_path, strerror(errno));
686        goto error_close_ifd;
687    }
688
689    struct dirent *d;
690    while ((d = readdir(proc))) {
691        int pid = atoi(d->d_name);
692        if (pid <= 0) continue;
693
694        char path[PATH_MAX];
695        char data[PATH_MAX];
696        snprintf(path, sizeof(path), "/proc/%d/exe", pid);
697        ssize_t len = readlink(path, data, sizeof(data) - 1);
698        if (len <= 0) {
699            continue;
700        }
701        data[len] = '\0';
702
703        if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) {
704            /* skip zygote -- it won't dump its stack anyway */
705            snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
706            int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
707            len = read(cfd, data, sizeof(data) - 1);
708            close(cfd);
709            if (len <= 0) {
710                continue;
711            }
712            data[len] = '\0';
713            if (!strncmp(data, "zygote", strlen("zygote"))) {
714                continue;
715            }
716
717            ++dalvik_found;
718            uint64_t start = nanotime();
719            if (kill(pid, SIGQUIT)) {
720                fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
721                continue;
722            }
723
724            /* wait for the writable-close notification from inotify */
725            struct pollfd pfd = { ifd, POLLIN, 0 };
726            int ret = poll(&pfd, 1, 5000);  /* 5 sec timeout */
727            if (ret < 0) {
728                fprintf(stderr, "poll: %s\n", strerror(errno));
729            } else if (ret == 0) {
730                fprintf(stderr, "warning: timed out dumping pid %d\n", pid);
731            } else {
732                struct inotify_event ie;
733                read(ifd, &ie, sizeof(ie));
734            }
735
736            if (lseek(fd, 0, SEEK_END) < 0) {
737                fprintf(stderr, "lseek: %s\n", strerror(errno));
738            } else {
739                dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n",
740                        pid, (float)(nanotime() - start) / NANOS_PER_SEC);
741            }
742        } else if (should_dump_native_traces(data)) {
743            /* dump native process if appropriate */
744            if (lseek(fd, 0, SEEK_END) < 0) {
745                fprintf(stderr, "lseek: %s\n", strerror(errno));
746            } else {
747                static uint16_t timeout_failures = 0;
748                uint64_t start = nanotime();
749
750                /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
751                if (timeout_failures == 3) {
752                    dprintf(fd, "too many stack dump failures, skipping...\n");
753                } else if (dump_backtrace_to_file_timeout(pid, fd, 20) == -1) {
754                    dprintf(fd, "dumping failed, likely due to a timeout\n");
755                    timeout_failures++;
756                } else {
757                    timeout_failures = 0;
758                }
759                dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n",
760                        pid, (float)(nanotime() - start) / NANOS_PER_SEC);
761            }
762        }
763    }
764
765    if (dalvik_found == 0) {
766        fprintf(stderr, "Warning: no Dalvik processes found to dump stacks\n");
767    }
768
769    static char dump_traces_path[PATH_MAX];
770    strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path));
771    strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path));
772    if (rename(traces_path, dump_traces_path)) {
773        fprintf(stderr, "rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno));
774        goto error_close_ifd;
775    }
776    result = dump_traces_path;
777
778    /* replace the saved [ANR] traces.txt file */
779    rename(anr_traces_path, traces_path);
780
781error_close_ifd:
782    close(ifd);
783error_close_fd:
784    close(fd);
785    return result;
786}
787
788void dump_route_tables() {
789    ON_DRY_RUN_RETURN();
790    const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
791    dump_file("RT_TABLES", RT_TABLES_PATH);
792    FILE* fp = fopen(RT_TABLES_PATH, "re");
793    if (!fp) {
794        printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
795        return;
796    }
797    char table[16];
798    // Each line has an integer (the table number), a space, and a string (the table name). We only
799    // need the table number. It's a 32-bit unsigned number, so max 10 chars. Skip the table name.
800    // Add a fixed max limit so this doesn't go awry.
801    for (int i = 0; i < 64 && fscanf(fp, " %10s %*s", table) == 1; ++i) {
802        run_command("ROUTE TABLE IPv4", 10, "ip", "-4", "route", "show", "table", table, NULL);
803        run_command("ROUTE TABLE IPv6", 10, "ip", "-6", "route", "show", "table", table, NULL);
804    }
805    fclose(fp);
806}
807