static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject clazz, jint pid, jstring fileName) { if (fileName == NULL) { jniThrowNullPointerException(env, NULL); return; } const jchar* str = env->GetStringCritical(fileName, 0); String8 fileName8; if (str) { fileName8 = String8((char16_t*)str, env->GetStringLength(fileName)); env->ReleaseStringCritical(fileName, str); } int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */ if (fd < 0) { fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno)); return; } if (lseek(fd, 0, SEEK_END) < 0) { fprintf(stderr, "lseek: %s\n", strerror(errno)); } else { dump_backtrace_to_file(pid, fd); } close(fd); }
static int do_explicit_dump(pid_t tid, bool dump_backtrace) { fprintf(stdout, "Sending request to dump task %d.\n", tid); if (dump_backtrace) { fflush(stdout); if (dump_backtrace_to_file(tid, fileno(stdout)) < 0) { fputs("Error dumping backtrace.\n", stderr); return 1; } } else { char tombstone_path[PATH_MAX]; if (dump_tombstone(tid, tombstone_path, sizeof(tombstone_path)) < 0) { fputs("Error dumping tombstone.\n", stderr); return 1; } fprintf(stderr, "Tombstone written to: %s\n", tombstone_path); } return 0; }
ECode CDebug::DumpNativeBacktraceToFile( /* [in] */ Int32 pid, /* [in] */ const String& file) { if (file.IsNull()) { //jniThrowNullPointerException(env, NULL); return E_NULL_POINTER_EXCEPTION; } int fd = open(file.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */ if (fd < 0) { fprintf(stderr, "Can't open %s: %s\n", file.string(), strerror(errno)); return NOERROR; } if (lseek(fd, 0, SEEK_END) < 0) { fprintf(stderr, "lseek: %s\n", strerror(errno)); } else { dump_backtrace_to_file(pid, fd); } close(fd); return NOERROR; }
/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */ const char *dump_traces() { const char* result = NULL; char traces_path[PROPERTY_VALUE_MAX] = ""; property_get("dalvik.vm.stack-trace-file", traces_path, ""); if (!traces_path[0]) return NULL; /* move the old traces.txt (if any) out of the way temporarily */ char anr_traces_path[PATH_MAX]; strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path)); strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path)); if (rename(traces_path, anr_traces_path) && errno != ENOENT) { fprintf(stderr, "rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno)); return NULL; // Can't rename old traces.txt -- no permission? -- leave it alone instead } /* make the directory if necessary */ char anr_traces_dir[PATH_MAX]; strlcpy(anr_traces_dir, traces_path, sizeof(anr_traces_dir)); char *slash = strrchr(anr_traces_dir, '/'); if (slash != NULL) { *slash = '\0'; if (!mkdir(anr_traces_dir, 0775)) { chown(anr_traces_dir, AID_SYSTEM, AID_SYSTEM); chmod(anr_traces_dir, 0775); } else if (errno != EEXIST) { fprintf(stderr, "mkdir(%s): %s\n", anr_traces_dir, strerror(errno)); return NULL; } } /* create a new, empty traces.txt file to receive stack dumps */ int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666); /* -rw-rw-rw- */ if (fd < 0) { fprintf(stderr, "%s: %s\n", traces_path, strerror(errno)); return NULL; } int chmod_ret = fchmod(fd, 0666); if (chmod_ret < 0) { fprintf(stderr, "fchmod on %s failed: %s\n", traces_path, strerror(errno)); close(fd); return NULL; } /* walk /proc and kill -QUIT all Dalvik processes */ DIR *proc = opendir("/proc"); if (proc == NULL) { fprintf(stderr, "/proc: %s\n", strerror(errno)); goto error_close_fd; } /* use inotify to find when processes are done dumping */ int ifd = inotify_init(); if (ifd < 0) { fprintf(stderr, "inotify_init: %s\n", strerror(errno)); goto error_close_fd; } int wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE); if (wfd < 0) { fprintf(stderr, "inotify_add_watch(%s): %s\n", traces_path, strerror(errno)); goto error_close_ifd; } struct dirent *d; int dalvik_found = 0; while ((d = readdir(proc))) { int pid = atoi(d->d_name); if (pid <= 0) continue; char path[PATH_MAX]; char data[PATH_MAX]; snprintf(path, sizeof(path), "/proc/%d/exe", pid); ssize_t len = readlink(path, data, sizeof(data) - 1); if (len <= 0) { continue; } data[len] = '\0'; if (!strcmp(data, "/system/bin/app_process")) { /* skip zygote -- it won't dump its stack anyway */ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); int fd = open(path, O_RDONLY); len = read(fd, data, sizeof(data) - 1); close(fd); if (len <= 0) { continue; } data[len] = '\0'; if (!strcmp(data, "zygote")) { continue; } ++dalvik_found; if (kill(pid, SIGQUIT)) { fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno)); continue; } /* wait for the writable-close notification from inotify */ struct pollfd pfd = { ifd, POLLIN, 0 }; int ret = poll(&pfd, 1, 200); /* 200 msec timeout */ if (ret < 0) { fprintf(stderr, "poll: %s\n", strerror(errno)); } else if (ret == 0) { fprintf(stderr, "warning: timed out dumping pid %d\n", pid); } else { struct inotify_event ie; read(ifd, &ie, sizeof(ie)); } } else if (should_dump_native_traces(data)) { /* dump native process if appropriate */ if (lseek(fd, 0, SEEK_END) < 0) { fprintf(stderr, "lseek: %s\n", strerror(errno)); } else { dump_backtrace_to_file(pid, fd); } } } if (dalvik_found == 0) { fprintf(stderr, "Warning: no Dalvik processes found to dump stacks\n"); } static char dump_traces_path[PATH_MAX]; strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path)); strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path)); if (rename(traces_path, dump_traces_path)) { fprintf(stderr, "rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno)); goto error_close_ifd; } result = dump_traces_path; /* replace the saved [ANR] traces.txt file */ rename(anr_traces_path, traces_path); error_close_ifd: close(ifd); error_close_fd: close(fd); return result; }
bool SFWatchDog::threadLoop() { XLOGV("[%s]", __func__); { Mutex::Autolock _l(mScreenLock); } nsecs_t stopTime = 1; if (isSFThreadHang(&stopTime)) { char cmds[256]; static uint32_t rtt_ct = SW_WATCHDOG_RTTCOUNT; if (rtt_ct > 0) { rtt_ct --; } else { XLOGD("[SF-WD] swap rtt dump file"); // swap rtt dump file snprintf(cmds, sizeof(cmds), "mv %s.txt %s_1.txt", RTT_DUMP, RTT_DUMP); system(cmds); rtt_ct = SW_WATCHDOG_RTTCOUNT; } // append SurfaceFlinger rtt information to rtt file char filename[100]; snprintf(filename, sizeof(filename), "%s.txt", RTT_DUMP); int fd = open(filename, O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */ if (fd < 0) { ALOGE("Can't open %s: %s\n", filename, strerror(errno)); return true; } if (lseek(fd, 0, SEEK_END) < 0) { fprintf(stderr, "lseek: %s\n", strerror(errno)); } else { dump_backtrace_to_file(getpid(), fd); } close(fd); XLOGD("[SF-WD] dump rtt file: %s.txt", RTT_DUMP); XLOGW("[SF-WD] ============================================"); } else { stopTime = 1; } getProperty(); char value[PROPERTY_VALUE_MAX]; snprintf(value, sizeof(value), "%" PRId64 " ", stopTime); if (stopTime < 0 || stopTime >= 2147483247) { volatile nsecs_t tmpStopTime = stopTime; XLOGD("[SF-WD] tmpStopTime=(%" PRId64 ", %" PRId64 ")", tmpStopTime, stopTime); abort(); } uint32_t ret = property_set("service.sf.status", value); if (mUpdateCount) { if (mShowLog) XLOGV("[SF-WD] mUpdateCount: %d", mUpdateCount); #if 0 aee_ioctl_wdt_kick(WDT_SETBY_SF); #endif mUpdateCount = 0; } //else { // XLOGV("[SF-WD] mUpdateCount not update!!!!!: %d", mUpdateCount); // aee_ioctl_wdt_kick(WDT_SETBY_SF_NEED_NOT_UPDATE); //} usleep(mTimer * 1000); return true; }