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