Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, const std::string& calling_package){ ... // Redirect stdout to tmp_path_. This is the main bugreport entry and will be // moved into zip file later, if zipping. TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout))); // TODO: why not write to a file instead of stdout to overcome this problem? /* TODO: rather than generating a text file now and zipping it later, it would be more efficient to redirect stdout to the zip entry directly, but the libziparchive doesn't support that option yet. */ if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) { return ERROR; } ... // Dump state for the default case. This also drops root. RunStatus s = DumpstateDefaultAfterCritical(); ... // Zip the (now complete) .tmp file within the internal directory. FinalizeFile(); ... }
// TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. // // File: system/core/debuggerd/tombstoned/tombstoned.cpp staticconst std::string TOMBSTONE_DIR = "/data/tombstones/"; staticconst std::string TOMBSTONE_FILE_PREFIX = "tombstone_"; staticconst std::string ANR_DIR = "/data/anr/"; staticconst std::string ANR_FILE_PREFIX = "anr_";
Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical(){ // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the // buffer. DoLogcat(); // Capture timestamp after first logcat to use in next logcat time_t logcat_ts = time(nullptr);
/* collect stack traces from Dalvik and native processes (needs root) */ std::future<std::string> dump_traces; if (dump_pool_) { RETURN_IF_USER_DENIED_CONSENT(); // One thread is enough since we only need to enqueue DumpTraces here. dump_pool_->start(/* thread_counts = */1);
// DumpTraces takes long time, post it to the another thread in the // pool, if pool is available dump_traces = dump_pool_->enqueueTask( DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path); } else { RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_TRACES_TASK, ds.DumpTraces, &dump_traces_path); }
/* Run some operations that require root. */ if (!PropertiesHelper::IsDryRun()) { ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX); ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX); }
// Capture any IPSec policies in play. No keys are exposed here. RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
// Dump IPsec stats. No keys are exposed here. DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
// Run ss as root so we can see socket marks. RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
// Run iotop as root to show top 100 IO threads RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
// Gather shared memory buffer info if the product implements it RunCommand("Dmabuf dump", {"dmabuf_dump"}); RunCommand("Dmabuf per-buffer/per-exporter/per-device stats", {"dmabuf_dump", "-b"});
if (dump_pool_) { RETURN_IF_USER_DENIED_CONSENT(); WaitForTask(std::move(dump_traces));
// Current running thread in the pool is the root user also. Delete // the pool and make a new one later to ensure none of threads in the pool are root. dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_); } if (!DropRootUser()) { return Dumpstate::RunStatus::ERROR; }
RETURN_IF_USER_DENIED_CONSENT(); Dumpstate::RunStatus status = dumpstate(); // Capture logcat since the last time we did it. DoSystemLogcat(logcat_ts); return status; }