• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <time.h>
32 #include <unistd.h>
33 
34 #include <cutils/properties.h>
35 #include <cutils/sockets.h>
36 #include <private/android_filesystem_config.h>
37 
38 #include "dumpstate.h"
39 
for_each_pid(void (* func)(int,const char *),const char * header)40 void for_each_pid(void (*func)(int, const char *), const char *header) {
41     DIR *d;
42     struct dirent *de;
43 
44     if (!(d = opendir("/proc"))) {
45         printf("Failed to open /proc (%s)\n", strerror(errno));
46         return;
47     }
48 
49     printf("\n------ %s ------\n", header);
50     while ((de = readdir(d))) {
51         int pid;
52         int fd;
53         char cmdpath[255];
54         char cmdline[255];
55 
56         if (!(pid = atoi(de->d_name))) {
57             continue;
58         }
59 
60         sprintf(cmdpath,"/proc/%d/cmdline", pid);
61         memset(cmdline, 0, sizeof(cmdline));
62         if ((fd = open(cmdpath, O_RDONLY)) < 0) {
63             strcpy(cmdline, "N/A");
64         } else {
65             read(fd, cmdline, sizeof(cmdline));
66             close(fd);
67         }
68         func(pid, cmdline);
69     }
70 
71     closedir(d);
72 }
73 
show_wchan(int pid,const char * name)74 void show_wchan(int pid, const char *name) {
75     char path[255];
76     char buffer[255];
77     int fd;
78 
79     memset(buffer, 0, sizeof(buffer));
80 
81     sprintf(path, "/proc/%d/wchan", pid);
82     if ((fd = open(path, O_RDONLY)) < 0) {
83         printf("Failed to open '%s' (%s)\n", path, strerror(errno));
84         return;
85     }
86 
87     if (read(fd, buffer, sizeof(buffer)) < 0) {
88         printf("Failed to read '%s' (%s)\n", path, strerror(errno));
89         goto out_close;
90     }
91 
92     printf("%-7d %-32s %s\n", pid, name, buffer);
93 
94 out_close:
95     close(fd);
96     return;
97 }
98 
99 /* prints the contents of a file */
dump_file(const char * title,const char * path)100 int dump_file(const char *title, const char* path) {
101     char buffer[32768];
102     int fd = open(path, O_RDONLY);
103     if (fd < 0) {
104         int err = errno;
105         if (title) printf("------ %s (%s) ------\n", title, path);
106         printf("*** %s: %s\n", path, strerror(err));
107         if (title) printf("\n");
108         return -1;
109     }
110 
111     if (title) printf("------ %s (%s", title, path);
112 
113     if (title) {
114         struct stat st;
115         if (memcmp(path, "/proc/", 6) && memcmp(path, "/sys/", 5) && !fstat(fd, &st)) {
116             char stamp[80];
117             time_t mtime = st.st_mtime;
118             strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
119             printf(": %s", stamp);
120         }
121         printf(") ------\n");
122     }
123 
124     int newline = 0;
125     for (;;) {
126         int ret = read(fd, buffer, sizeof(buffer));
127         if (ret > 0) {
128             newline = (buffer[ret - 1] == '\n');
129             ret = fwrite(buffer, ret, 1, stdout);
130         }
131         if (ret <= 0) break;
132     }
133 
134     close(fd);
135     if (!newline) printf("\n");
136     if (title) printf("\n");
137     return 0;
138 }
139 
140 /* forks a command and waits for it to finish */
run_command(const char * title,int timeout_seconds,const char * command,...)141 int run_command(const char *title, int timeout_seconds, const char *command, ...) {
142     fflush(stdout);
143     clock_t start = clock();
144     pid_t pid = fork();
145 
146     /* handle error case */
147     if (pid < 0) {
148         printf("*** fork: %s\n", strerror(errno));
149         return pid;
150     }
151 
152     /* handle child case */
153     if (pid == 0) {
154         const char *args[1024] = {command};
155         size_t arg;
156 
157         va_list ap;
158         va_start(ap, command);
159         if (title) printf("------ %s (%s", title, command);
160         for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
161             args[arg] = va_arg(ap, const char *);
162             if (args[arg] == NULL) break;
163             if (title) printf(" %s", args[arg]);
164         }
165         if (title) printf(") ------\n");
166         fflush(stdout);
167 
168         execvp(command, (char**) args);
169         printf("*** exec(%s): %s\n", command, strerror(errno));
170         fflush(stdout);
171         _exit(-1);
172     }
173 
174     /* handle parent case */
175     for (;;) {
176         int status;
177         pid_t p = waitpid(pid, &status, WNOHANG);
178         float elapsed = (float) (clock() - start) / CLOCKS_PER_SEC;
179         if (p == pid) {
180             if (WIFSIGNALED(status)) {
181                 printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
182             } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
183                 printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
184             }
185             if (title) printf("[%s: %.1fs elapsed]\n\n", command, elapsed);
186             return status;
187         }
188 
189         if (timeout_seconds && elapsed > timeout_seconds) {
190             printf("*** %s: Timed out after %.1fs (killing pid %d)\n", command, elapsed, pid);
191             kill(pid, SIGTERM);
192             return -1;
193         }
194 
195         usleep(100000);  // poll every 0.1 sec
196     }
197 }
198 
199 size_t num_props = 0;
200 static char* props[2000];
201 
print_prop(const char * key,const char * name,void * user)202 static void print_prop(const char *key, const char *name, void *user) {
203     (void) user;
204     if (num_props < sizeof(props) / sizeof(props[0])) {
205         char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10];
206         snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name);
207         props[num_props++] = strdup(buf);
208     }
209 }
210 
compare_prop(const void * a,const void * b)211 static int compare_prop(const void *a, const void *b) {
212     return strcmp(*(char * const *) a, *(char * const *) b);
213 }
214 
215 /* prints all the system properties */
print_properties()216 void print_properties() {
217     size_t i;
218     num_props = 0;
219     property_list(print_prop, NULL);
220     qsort(&props, num_props, sizeof(props[0]), compare_prop);
221 
222     printf("------ SYSTEM PROPERTIES ------\n");
223     for (i = 0; i < num_props; ++i) {
224         fputs(props[i], stdout);
225         free(props[i]);
226     }
227     printf("\n");
228 }
229 
230 /* redirect output to a service control socket */
redirect_to_socket(FILE * redirect,const char * service)231 void redirect_to_socket(FILE *redirect, const char *service) {
232     int s = android_get_control_socket(service);
233     if (s < 0) {
234         fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno));
235         exit(1);
236     }
237     if (listen(s, 4) < 0) {
238         fprintf(stderr, "listen(control socket): %s\n", strerror(errno));
239         exit(1);
240     }
241 
242     struct sockaddr addr;
243     socklen_t alen = sizeof(addr);
244     int fd = accept(s, &addr, &alen);
245     if (fd < 0) {
246         fprintf(stderr, "accept(control socket): %s\n", strerror(errno));
247         exit(1);
248     }
249 
250     fflush(redirect);
251     dup2(fd, fileno(redirect));
252     close(fd);
253 }
254 
255 /* redirect output to a file, optionally gzipping; returns gzip pid (or -1) */
redirect_to_file(FILE * redirect,char * path,int gzip_level)256 pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) {
257     char *chp = path;
258 
259     /* skip initial slash */
260     if (chp[0] == '/')
261         chp++;
262 
263     /* create leading directories, if necessary */
264     while (chp && chp[0]) {
265         chp = strchr(chp, '/');
266         if (chp) {
267             *chp = 0;
268             mkdir(path, 0775);  /* drwxrwxr-x */
269             *chp++ = '/';
270         }
271     }
272 
273     int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
274     if (fd < 0) {
275         fprintf(stderr, "%s: %s\n", path, strerror(errno));
276         exit(1);
277     }
278 
279     pid_t gzip_pid = -1;
280     if (gzip_level > 0) {
281         int fds[2];
282         if (pipe(fds)) {
283             fprintf(stderr, "pipe: %s\n", strerror(errno));
284             exit(1);
285         }
286 
287         fflush(redirect);
288         fflush(stdout);
289 
290         gzip_pid = fork();
291         if (gzip_pid < 0) {
292             fprintf(stderr, "fork: %s\n", strerror(errno));
293             exit(1);
294         }
295 
296         if (gzip_pid == 0) {
297             dup2(fds[0], STDIN_FILENO);
298             dup2(fd, STDOUT_FILENO);
299 
300             close(fd);
301             close(fds[0]);
302             close(fds[1]);
303 
304             char level[10];
305             snprintf(level, sizeof(level), "-%d", gzip_level);
306             execlp("gzip", "gzip", level, NULL);
307             fprintf(stderr, "exec(gzip): %s\n", strerror(errno));
308             _exit(-1);
309         }
310 
311         close(fd);
312         close(fds[0]);
313         fd = fds[1];
314     }
315 
316     dup2(fd, fileno(redirect));
317     close(fd);
318     return gzip_pid;
319 }
320 
321 /* dump Dalvik stack traces, return the trace file location (NULL if none) */
dump_vm_traces()322 const char *dump_vm_traces() {
323     char traces_path[PROPERTY_VALUE_MAX] = "";
324     property_get("dalvik.vm.stack-trace-file", traces_path, "");
325     if (!traces_path[0]) return NULL;
326 
327     /* move the old traces.txt (if any) out of the way temporarily */
328     char anr_traces_path[PATH_MAX];
329     strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path));
330     strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path));
331     if (rename(traces_path, anr_traces_path) && errno != ENOENT) {
332         fprintf(stderr, "rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno));
333         return NULL;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
334     }
335 
336     /* make the directory if necessary */
337     char anr_traces_dir[PATH_MAX];
338     strlcpy(anr_traces_dir, traces_path, sizeof(anr_traces_dir));
339     char *slash = strrchr(anr_traces_dir, '/');
340     if (slash != NULL) {
341         *slash = '\0';
342         if (!mkdir(anr_traces_dir, 0775)) {
343             chown(anr_traces_dir, AID_SYSTEM, AID_SYSTEM);
344         } else if (errno != EEXIST) {
345             fprintf(stderr, "mkdir(%s): %s\n", anr_traces_dir, strerror(errno));
346             return NULL;
347         }
348     }
349 
350     /* create a new, empty traces.txt file to receive stack dumps */
351     int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC, 0666);  /* -rw-rw-rw- */
352     if (fd < 0) {
353         fprintf(stderr, "%s: %s\n", traces_path, strerror(errno));
354         return NULL;
355     }
356     close(fd);
357 
358     /* walk /proc and kill -QUIT all Dalvik processes */
359     DIR *proc = opendir("/proc");
360     if (proc == NULL) {
361         fprintf(stderr, "/proc: %s\n", strerror(errno));
362         return NULL;
363     }
364 
365     /* use inotify to find when processes are done dumping */
366     int ifd = inotify_init();
367     if (ifd < 0) {
368         fprintf(stderr, "inotify_init: %s\n", strerror(errno));
369         return NULL;
370     }
371 
372     int wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE);
373     if (wfd < 0) {
374         fprintf(stderr, "inotify_add_watch(%s): %s\n", traces_path, strerror(errno));
375         return NULL;
376     }
377 
378     struct dirent *d;
379     int dalvik_found = 0;
380     while ((d = readdir(proc))) {
381         int pid = atoi(d->d_name);
382         if (pid <= 0) continue;
383 
384         /* identify Dalvik: /proc/(pid)/exe = /system/bin/app_process */
385         char path[PATH_MAX], data[PATH_MAX];
386         snprintf(path, sizeof(path), "/proc/%d/exe", pid);
387         size_t len = readlink(path, data, sizeof(data) - 1);
388         if (len <= 0 || memcmp(data, "/system/bin/app_process", 23)) continue;
389 
390         /* skip zygote -- it won't dump its stack anyway */
391         snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
392         int fd = open(path, O_RDONLY);
393         len = read(fd, data, sizeof(data) - 1);
394         close(fd);
395         if (len <= 0 || !memcmp(data, "zygote", 6)) continue;
396 
397         ++dalvik_found;
398         if (kill(pid, SIGQUIT)) {
399             fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
400             continue;
401         }
402 
403         /* wait for the writable-close notification from inotify */
404         struct pollfd pfd = { ifd, POLLIN, 0 };
405         int ret = poll(&pfd, 1, 200);  /* 200 msec timeout */
406         if (ret < 0) {
407             fprintf(stderr, "poll: %s\n", strerror(errno));
408         } else if (ret == 0) {
409             fprintf(stderr, "warning: timed out dumping pid %d\n", pid);
410         } else {
411             struct inotify_event ie;
412             read(ifd, &ie, sizeof(ie));
413         }
414     }
415 
416     close(ifd);
417     if (dalvik_found == 0) {
418         fprintf(stderr, "Warning: no Dalvik processes found to dump stacks\n");
419     }
420 
421     static char dump_traces_path[PATH_MAX];
422     strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path));
423     strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path));
424     if (rename(traces_path, dump_traces_path)) {
425         fprintf(stderr, "rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno));
426         return NULL;
427     }
428 
429     /* replace the saved [ANR] traces.txt file */
430     rename(anr_traces_path, traces_path);
431     return dump_traces_path;
432 }
433 
play_sound(const char * path)434 void play_sound(const char* path) {
435     run_command(NULL, 5, "/system/bin/stagefright", "-o", "-a", path, NULL);
436 }
437