Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67f81c45 authored by Elliott Hughes's avatar Elliott Hughes Committed by android-build-merger
Browse files

Merge "Remove non-tombstoned ANR path."

am: 79474267

Change-Id: I6bbd1cac24fe21e35bfe8d282a3a0a7a6f572ff0
parents 82a2cb3c 79474267
Loading
Loading
Loading
Loading
+12 −87
Original line number Diff line number Diff line
@@ -863,53 +863,6 @@ static void DumpIpTablesAsRoot() {
    RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
}

static void AddGlobalAnrTraceFile(const bool add_to_zip, const std::string& anr_traces_file,
                                  const std::string& anr_traces_dir) {
    std::string dump_traces_dir;

    if (dump_traces_path != nullptr) {
        if (add_to_zip) {
            dump_traces_dir = dirname(dump_traces_path);
            MYLOGD("Adding ANR traces (directory %s) to the zip file\n", dump_traces_dir.c_str());
            ds.AddDir(dump_traces_dir, true);
        } else {
            MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
                   dump_traces_path);
            ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
        }
    }


    // Make sure directory is not added twice.
    // TODO: this is an overzealous check because it's relying on dump_traces_path - which is
    // generated by dump_traces() -  and anr_traces_path - which is retrieved from a system
    // property - but in reality they're the same path (although the former could be nullptr).
    // Anyways, once dump_traces() is refactored as a private Dumpstate function, this logic should
    // be revisited.
    bool already_dumped = anr_traces_dir == dump_traces_dir;

    MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
           dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);

    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
    if (fd.get() < 0) {
        printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
    } else {
        if (add_to_zip) {
            if (!already_dumped) {
                MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
                       anr_traces_dir.c_str());
                ds.AddDir(anr_traces_dir, true);
            }
        } else {
            MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
                   anr_traces_file.c_str());
            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get());
        }
    }
}

static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
    MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
           anr_traces_dir.c_str());
@@ -952,39 +905,12 @@ static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_
static void AddAnrTraceFiles() {
    const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;

    std::string anr_traces_file;
    std::string anr_traces_dir;
    bool is_global_trace_file = true;

    // First check whether the stack-trace-dir property is set. When it's set,
    // each ANR trace will be written to a separate file and not to a global
    // stack trace file.
    anr_traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
    if (anr_traces_dir.empty()) {
        anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
        if (!anr_traces_file.empty()) {
            anr_traces_dir = dirname(anr_traces_file.c_str());
        }
    } else {
        is_global_trace_file = false;
    }

    // We have neither configured a global trace file nor a trace directory,
    // there will be nothing to dump.
    if (anr_traces_file.empty() && anr_traces_dir.empty()) {
        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
        return;
    }
    std::string anr_traces_dir = "/data/anr";

    if (is_global_trace_file) {
        AddGlobalAnrTraceFile(add_to_zip, anr_traces_file, anr_traces_dir);
    } else {
    AddAnrTraceDir(add_to_zip, anr_traces_dir);
    }

    /* slow traces for slow operations */
    // Slow traces for slow operations.
    struct stat st;
    if (!anr_traces_dir.empty()) {
    int i = 0;
    while (true) {
        const std::string slow_trace_path =
@@ -997,7 +923,6 @@ static void AddAnrTraceFiles() {
        i++;
    }
}
}

static void DumpBlockStatFiles() {
    DurationReporter duration_reporter("DUMP BLOCK STAT");
+5 −172
Original line number Diff line number Diff line
@@ -856,26 +856,6 @@ std::set<int> get_interesting_hal_pids() {
    return pids; // whether it was okay or not
}

const char* DumpTraces(const std::string& traces_path);
const char* DumpTracesTombstoned(const std::string& traces_dir);

/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
const char *dump_traces() {
    DurationReporter duration_reporter("DUMP TRACES");

    const std::string traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
    if (!traces_dir.empty()) {
        return DumpTracesTombstoned(traces_dir);
    }

    const std::string traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
    if (!traces_file.empty()) {
        return DumpTraces(traces_file);
    }

    return nullptr;
}

static bool IsZygote(int pid) {
    static const std::string kZygotePrefix = "zygote";

@@ -888,8 +868,11 @@ static bool IsZygote(int pid) {
    return (cmdline.find(kZygotePrefix) == 0);
}

const char* DumpTracesTombstoned(const std::string& traces_dir) {
    const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
// Dump Dalvik and native stack traces, return the trace file location (nullptr if none).
const char* dump_traces() {
    DurationReporter duration_reporter("DUMP TRACES");

    const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";

    const size_t buf_size = temp_file_pattern.length() + 1;
    std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
@@ -991,156 +974,6 @@ const char* DumpTracesTombstoned(const std::string& traces_dir) {
    return file_name_buf.release();
}

const char* DumpTraces(const std::string& traces_path) {
    const char* result = NULL;
    /* move the old traces.txt (if any) out of the way temporarily */
    std::string anrtraces_path = traces_path + ".anr";
    if (rename(traces_path.c_str(), anrtraces_path.c_str()) && errno != ENOENT) {
        MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), anrtraces_path.c_str(), strerror(errno));
        return nullptr;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
    }

    /* create a new, empty traces.txt file to receive stack dumps */
    int fd = TEMP_FAILURE_RETRY(
        open(traces_path.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
             0666)); /* -rw-rw-rw- */
    if (fd < 0) {
        MYLOGE("%s: %s\n", traces_path.c_str(), strerror(errno));
        return nullptr;
    }
    int chmod_ret = fchmod(fd, 0666);
    if (chmod_ret < 0) {
        MYLOGE("fchmod on %s failed: %s\n", traces_path.c_str(), strerror(errno));
        close(fd);
        return nullptr;
    }

    /* Variables below must be initialized before 'goto' statements */
    int dalvik_found = 0;
    int ifd, wfd = -1;
    std::set<int> hal_pids = get_interesting_hal_pids();

    /* walk /proc and kill -QUIT all Dalvik processes */
    DIR *proc = opendir("/proc");
    if (proc == NULL) {
        MYLOGE("/proc: %s\n", strerror(errno));
        goto error_close_fd;
    }

    /* use inotify to find when processes are done dumping */
    ifd = inotify_init();
    if (ifd < 0) {
        MYLOGE("inotify_init: %s\n", strerror(errno));
        goto error_close_fd;
    }

    wfd = inotify_add_watch(ifd, traces_path.c_str(), IN_CLOSE_WRITE);
    if (wfd < 0) {
        MYLOGE("inotify_add_watch(%s): %s\n", traces_path.c_str(), strerror(errno));
        goto error_close_ifd;
    }

    struct dirent *d;
    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 (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) {
            /* skip zygote -- it won't dump its stack anyway */
            snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
            int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
            len = read(cfd, data, sizeof(data) - 1);
            close(cfd);
            if (len <= 0) {
                continue;
            }
            data[len] = '\0';
            if (!strncmp(data, "zygote", strlen("zygote"))) {
                continue;
            }

            ++dalvik_found;
            uint64_t start = Nanotime();
            if (kill(pid, SIGQUIT)) {
                MYLOGE("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, TRACE_DUMP_TIMEOUT_MS);
            if (ret < 0) {
                MYLOGE("poll: %s\n", strerror(errno));
            } else if (ret == 0) {
                MYLOGE("warning: timed out dumping pid %d\n", pid);
            } else {
                struct inotify_event ie;
                read(ifd, &ie, sizeof(ie));
            }

            if (lseek(fd, 0, SEEK_END) < 0) {
                MYLOGE("lseek: %s\n", strerror(errno));
            } else {
                dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid,
                        (float)(Nanotime() - start) / NANOS_PER_SEC);
            }
        } else if (should_dump_native_traces(data) ||
                   hal_pids.find(pid) != hal_pids.end()) {
            /* dump native process if appropriate */
            if (lseek(fd, 0, SEEK_END) < 0) {
                MYLOGE("lseek: %s\n", strerror(errno));
            } else {
                static uint16_t timeout_failures = 0;
                uint64_t start = Nanotime();

                /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
                if (timeout_failures == 3) {
                    dprintf(fd, "too many stack dump failures, skipping...\n");
                } else if (dump_backtrace_to_file_timeout(
                        pid, kDebuggerdNativeBacktrace, 20, fd) == -1) {
                    dprintf(fd, "dumping failed, likely due to a timeout\n");
                    timeout_failures++;
                } else {
                    timeout_failures = 0;
                }
                dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n", pid,
                        (float)(Nanotime() - start) / NANOS_PER_SEC);
            }
        }
    }

    if (dalvik_found == 0) {
        MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
    }

    static std::string dumptraces_path = android::base::StringPrintf(
        "%s/bugreport-%s", dirname(traces_path.c_str()), basename(traces_path.c_str()));
    if (rename(traces_path.c_str(), dumptraces_path.c_str())) {
        MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), dumptraces_path.c_str(),
               strerror(errno));
        goto error_close_ifd;
    }
    result = dumptraces_path.c_str();

    /* replace the saved [ANR] traces.txt file */
    rename(anrtraces_path.c_str(), traces_path.c_str());

error_close_ifd:
    close(ifd);
error_close_fd:
    close(fd);
    return result;
}

void dump_route_tables() {
    DurationReporter duration_reporter("DUMP ROUTE TABLES");
    if (PropertiesHelper::IsDryRun()) return;