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