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

Commit bd86372f authored by Narayan Kamath's avatar Narayan Kamath
Browse files

dumpstate: Further cleanups related to new stack dumping scheme.

- Rewrite AddDumpFds to iterate over all files in the dump directory
  instead of assuming a specific file pattern. This gives us additional
  flexibility in generating dump file names.

- Fix a bug in deducing the value of is_global_stack_trace_file.

- Add a better section header for the most recent ANR dump. The most
  recent dump will be titled "VM TRACES AT LAST ANR" and all others will
  be titled "HISTORICAL ANR". Also fixes the sort order so that the most
  recent ANR shows up first.

Bug: 36024548
Test: Manual; adb bugreport

Change-Id: I461712954d033ef3a3911d5b419a101cac71c8fb
parent cc15d22f
Loading
Loading
Loading
Loading
+53 −37
Original line number Diff line number Diff line
@@ -85,10 +85,10 @@ void add_mountinfo();
// with tombstoned, we should just put it in a common header.
//
// File: system/core/debuggerd/tombstoned/tombstoned.cpp
static const std::string TOMBSTONE_DIR = "/data/tombstones";
static const std::string TOMBSTONE_FILE_PREFIX = "/data/tombstones/tombstone_";
static const std::string ANR_DIR = "/data/anr";
static const std::string ANR_FILE_PREFIX = "/data/anr/anr_";
static const std::string TOMBSTONE_DIR = "/data/tombstones/";
static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
static const std::string ANR_DIR = "/data/anr/";
static const std::string ANR_FILE_PREFIX = "anr_";

struct DumpData {
    std::string name;
@@ -97,7 +97,7 @@ struct DumpData {
};

static bool operator<(const DumpData& d1, const DumpData& d2) {
    return d1.mtime < d2.mtime;
    return d1.mtime > d2.mtime;
}

static std::unique_ptr<std::vector<DumpData>> tombstone_data;
@@ -134,44 +134,49 @@ static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.descript
static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();

/*
 * Returns a vector of dump fds under |file_prefix|. The returned vector
 * is sorted by the mtimes of the dumps. If |limit_by_mtime| is set, the
 * vector only contains files that were written in the last 30 minutes.
 * Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
 * The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
 * is set, the vector only contains files that were written in the last 30 minutes.
 */
static std::vector<DumpData>* GetDumpFds(const std::string& file_prefix, bool limit_by_mtime) {
static std::vector<DumpData>* GetDumpFds(const std::string& dir_path,
                                         const std::string& file_prefix,
                                         bool limit_by_mtime) {
    const time_t thirty_minutes_ago = ds.now_ - 60 * 30;

    size_t i = 0;
    std::unique_ptr<std::vector<DumpData>> dump_data(new std::vector<DumpData>());
    while (true) {
        const std::string name = android::base::StringPrintf("%s%02zu", file_prefix.c_str(), i++);
        android::base::unique_fd fd(
            TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
        if (fd == -1) {
            if (errno != ENOENT) {
                MYLOGW("Unable to open dump file: %s %s\n", name.c_str(), strerror(errno));
            }
    std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);

            break;
    struct dirent* entry = nullptr;
    while ((entry = readdir(dump_dir.get()))) {
        if (entry->d_type != DT_REG) {
            continue;
        }

        struct stat st;
        if (fstat(fd, &st) == -1) {
            MYLOGW("Unable to stat dump file: %s %s\n", name.c_str(), strerror(errno));
        const std::string base_name(entry->d_name);
        if (base_name.find(file_prefix) != 0) {
            continue;
        }

        if (!S_ISREG(st.st_mode)) {
            MYLOGW("Unexpected mode for dump file: %s %x\n", name.c_str(), st.st_mode);
        const std::string abs_path = dir_path + base_name;
        android::base::unique_fd fd(
            TEMP_FAILURE_RETRY(open(abs_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
        if (fd == -1) {
            MYLOGW("Unable to open dump file: %s %s\n", abs_path.c_str(), strerror(errno));
            break;
        }

        struct stat st = {};
        if (fstat(fd, &st) == -1) {
            MYLOGW("Unable to stat dump file: %s %s\n", abs_path.c_str(), strerror(errno));
            continue;
        }

        if (limit_by_mtime && st.st_mtime >= thirty_minutes_ago) {
            MYLOGI("Excluding stale dump file: %s\n", name.c_str());
            MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
            continue;
        }

        DumpData data = {.name = name, .fd = fd.release(), .mtime = st.st_mtime};
        DumpData data = {.name = abs_path, .fd = fd.release(), .mtime = st.st_mtime};

        dump_data->push_back(data);
    }
@@ -181,12 +186,13 @@ static std::vector<DumpData>* GetDumpFds(const std::string& file_prefix, bool li
    return dump_data.release();
}

static bool AddDumps(const std::vector<DumpData>& dump_list, const char* type_name,
                     const bool add_to_zip) {
static bool AddDumps(const std::vector<DumpData>::const_iterator start,
                     const std::vector<DumpData>::const_iterator end,
                     const char* type_name, const bool add_to_zip) {
    bool dumped = false;
    for (size_t i = 0; i < dump_list.size(); i++) {
        const std::string& name = dump_list[i].name;
        const int fd = dump_list[i].fd;
    for (auto it = start; it != end; ++it) {
        const std::string& name = it->name;
        const int fd = it->fd;
        dumped = true;
        if (ds.IsZipping() && add_to_zip) {
            if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
@@ -991,8 +997,16 @@ static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_
        }
    }

    const bool anr_traces_dumped = AddDumps(*anr_data, "ANR", add_to_zip);
    if (!anr_traces_dumped) {
    // Add a specific message for the first ANR Dump.
    if (anr_data->size() > 0) {
        AddDumps(anr_data->begin(), anr_data->begin() + 1,
                 "VM TRACES AT LAST ANR", add_to_zip);

        if (anr_data->size() > 1) {
            AddDumps(anr_data->begin() + 1, anr_data->end(),
                     "HISTORICAL ANR", add_to_zip);
        }
    } else {
        printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
    }
}
@@ -1011,9 +1025,10 @@ static void AddAnrTraceFiles() {
    if (anr_traces_dir.empty()) {
        anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
        if (!anr_traces_file.empty()) {
            is_global_trace_file = true;
            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,
@@ -1117,7 +1132,8 @@ static void dumpstate() {

    // NOTE: tombstones are always added as separate entries in the zip archive
    // and are not interspersed with the main report.
    const bool tombstones_dumped = AddDumps(*tombstone_data, "TOMBSTONE", true /* add_to_zip */);
    const bool tombstones_dumped = AddDumps(tombstone_data->begin(), tombstone_data->end(),
                                            "TOMBSTONE", true /* add_to_zip */);
    if (!tombstones_dumped) {
        printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
    }
@@ -1798,8 +1814,8 @@ int main(int argc, char *argv[]) {
        dump_traces_path = dump_traces();

        /* Run some operations that require root. */
        tombstone_data.reset(GetDumpFds(TOMBSTONE_FILE_PREFIX, !ds.IsZipping()));
        anr_data.reset(GetDumpFds(ANR_FILE_PREFIX, !ds.IsZipping()));
        tombstone_data.reset(GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping()));
        anr_data.reset(GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping()));

        ds.AddDir(RECOVERY_DIR, true);
        ds.AddDir(RECOVERY_DATA_DIR, true);