Loading cmds/dumpstate/dumpstate.cpp +109 −48 Original line number Diff line number Diff line Loading @@ -131,6 +131,19 @@ static const std::string ANR_FILE_PREFIX = "anr_"; // TODO: temporary variables and functions used during C++ refactoring static Dumpstate& ds = Dumpstate::GetInstance(); #define RETURN_IF_USER_DENIED_CONSENT() \ if (ds.IsUserConsentDenied()) { \ MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \ return Dumpstate::RunStatus::USER_CONSENT_DENIED; \ } // Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED // if consent is found to be denied. #define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \ RETURN_IF_USER_DENIED_CONSENT(); \ func_ptr(__VA_ARGS__); \ RETURN_IF_USER_DENIED_CONSENT(); namespace android { namespace os { namespace { Loading Loading @@ -1054,7 +1067,7 @@ static void DumpIpAddrAndRules() { RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"}); } static void RunDumpsysTextByPriority(const std::string& title, int priority, static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority, std::chrono::milliseconds timeout, std::chrono::milliseconds service_timeout) { auto start = std::chrono::steady_clock::now(); Loading @@ -1064,6 +1077,7 @@ static void RunDumpsysTextByPriority(const std::string& title, int priority, Dumpsys::setServiceArgs(args, /* asProto = */ false, priority); Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false); for (const String16& service : services) { RETURN_IF_USER_DENIED_CONSENT(); std::string path(title); path.append(" - ").append(String8(service).c_str()); DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_); Loading @@ -1089,6 +1103,7 @@ static void RunDumpsysTextByPriority(const std::string& title, int priority, break; } } return Dumpstate::RunStatus::OK; } static void RunDumpsysText(const std::string& title, int priority, Loading @@ -1101,7 +1116,7 @@ static void RunDumpsysText(const std::string& title, int priority, } /* Dump all services registered with Normal or Default priority. */ static void RunDumpsysTextNormalPriority(const std::string& title, static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title, std::chrono::milliseconds timeout, std::chrono::milliseconds service_timeout) { DurationReporter duration_reporter(title); Loading @@ -1109,16 +1124,19 @@ static void RunDumpsysTextNormalPriority(const std::string& title, fsync(STDOUT_FILENO); RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout, service_timeout); RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout, RETURN_IF_USER_DENIED_CONSENT(); return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout, service_timeout); } static void RunDumpsysProto(const std::string& title, int priority, static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority, std::chrono::milliseconds timeout, std::chrono::milliseconds service_timeout) { if (!ds.IsZipping()) { MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str()); return; return Dumpstate::RunStatus::OK; } sp<android::IServiceManager> sm = defaultServiceManager(); Dumpsys dumpsys(sm.get()); Loading @@ -1129,6 +1147,7 @@ static void RunDumpsysProto(const std::string& title, int priority, auto start = std::chrono::steady_clock::now(); Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true); for (const String16& service : services) { RETURN_IF_USER_DENIED_CONSENT(); std::string path(kProtoPath); path.append(String8(service).c_str()); if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) { Loading Loading @@ -1157,31 +1176,41 @@ static void RunDumpsysProto(const std::string& title, int priority, break; } } return Dumpstate::RunStatus::OK; } // Runs dumpsys on services that must dump first and will take less than 100ms to dump. static void RunDumpsysCritical() { static Dumpstate::RunStatus RunDumpsysCritical() { RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, /* timeout= */ 5s, /* service_timeout= */ 500ms); RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, RETURN_IF_USER_DENIED_CONSENT(); return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, /* timeout= */ 5s, /* service_timeout= */ 500ms); } // Runs dumpsys on services that must dump first but can take up to 250ms to dump. static void RunDumpsysHigh() { static Dumpstate::RunStatus RunDumpsysHigh() { // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both // high priority. Reduce timeout once they are able to dump in a shorter time or // moved to a parallel task. RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH, /* timeout= */ 90s, /* service_timeout= */ 30s); RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH, RETURN_IF_USER_DENIED_CONSENT(); return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH, /* timeout= */ 5s, /* service_timeout= */ 1s); } // Runs dumpsys on services that must dump but can take up to 10s to dump. static void RunDumpsysNormal() { static Dumpstate::RunStatus RunDumpsysNormal() { RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s); RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, RETURN_IF_USER_DENIED_CONSENT(); return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, /* timeout= */ 90s, /* service_timeout= */ 10s); } Loading Loading @@ -1244,9 +1273,16 @@ static void DumpHals() { } } static void dumpstate() { // Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent // via the consent they are shown. Ignores other errors that occur while running various // commands. The consent checking is currently done around long running tasks, which happen to // be distributed fairly evenly throughout the function. static Dumpstate::RunStatus dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); // Dump various things. Note that anything that takes "long" (i.e. several seconds) should // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK). dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); RunCommand("UPTIME", {"uptime"}); DumpBlockStatFiles(); Loading @@ -1254,7 +1290,9 @@ static void dumpstate() { DumpFile("MEMORY INFO", "/proc/meminfo"); RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"}); RunCommand("PROCRANK", {"procrank"}, AS_ROOT_20); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20); DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat"); DumpFile("VMALLOC INFO", "/proc/vmallocinfo"); DumpFile("SLAB INFO", "/proc/slabinfo"); Loading @@ -1269,7 +1307,9 @@ static void dumpstate() { RunCommand("PROCESSES AND THREADS", {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"}); RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"}, CommandOptions::AS_ROOT); DumpHals(); Loading @@ -1290,7 +1330,9 @@ static void dumpstate() { } RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT); for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES"); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES"); for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS"); for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)"); Loading Loading @@ -1328,7 +1370,7 @@ static void dumpstate() { RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"}); RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"}); RunDumpsysHigh(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh); RunCommand("SYSTEM PROPERTIES", {"getprop"}); Loading @@ -1351,7 +1393,7 @@ static void dumpstate() { ds.AddDir(WMTRACE_DATA_DIR, false); } ds.DumpstateBoard(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard); /* Migrate the ril_dumpstate to a device specific dumpstate? */ int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0); Loading @@ -1371,14 +1413,16 @@ static void dumpstate() { printf("== Android Framework Services\n"); printf("========================================================\n"); RunDumpsysNormal(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal); printf("========================================================\n"); printf("== Checkins\n"); printf("========================================================\n"); RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}); RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"}); RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}); RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}); RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}); Loading Loading @@ -1442,19 +1486,27 @@ static void dumpstate() { printf("========================================================\n"); // This differs from the usual dumpsys stats, which is the stats report data. RunDumpsys("STATSDSTATS", {"stats", "--metadata"}); return Dumpstate::RunStatus::OK; } /* Dumps state for the default case. Returns true if everything went fine. */ static bool DumpstateDefault() { /* * Dumps state for the default case; drops root after it's no longer necessary. * * Returns RunStatus::OK if everything went fine. * Returns RunStatus::ERROR if there was an error. * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport * with the caller. */ static Dumpstate::RunStatus DumpstateDefault() { // Try to dump anrd trace if the daemon is running. dump_anrd_trace(); // Invoking the following dumpsys calls before dump_traces() to try and // Invoking the following dumpsys calls before DumpTraces() to try and // keep the system stats as close to its initial state as possible. RunDumpsysCritical(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical); /* collect stack traces from Dalvik and native processes (needs root) */ dump_traces_path = ds.DumpTraces(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path); /* Run some operations that require root. */ ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping()); Loading Loading @@ -1490,11 +1542,11 @@ static bool DumpstateDefault() { } if (!DropRootUser()) { return false; return Dumpstate::RunStatus::ERROR; } dumpstate(); return true; RETURN_IF_USER_DENIED_CONSENT(); return dumpstate(); } // This method collects common dumpsys for telephony and wifi Loading Loading @@ -1584,7 +1636,7 @@ static void DumpstateWifiOnly() { printf("========================================================\n"); } const char* Dumpstate::DumpTraces() { Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) { DurationReporter duration_reporter("DUMP TRACES"); const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX"; Loading @@ -1600,7 +1652,7 @@ const char* Dumpstate::DumpTraces() { android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC)); if (fd < 0) { MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno)); return nullptr; return RunStatus::OK; } // Nobody should have access to this temporary file except dumpstate, but we Loading @@ -1610,13 +1662,13 @@ const char* Dumpstate::DumpTraces() { const int chmod_ret = fchmod(fd, 0666); if (chmod_ret < 0) { MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno)); return nullptr; return RunStatus::OK; } std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir); if (proc.get() == nullptr) { MYLOGE("opendir /proc failed: %s\n", strerror(errno)); return nullptr; return RunStatus::OK; } // Number of times process dumping has timed out. If we encounter too many Loading @@ -1628,6 +1680,7 @@ const char* Dumpstate::DumpTraces() { struct dirent* d; while ((d = readdir(proc.get()))) { RETURN_IF_USER_DENIED_CONSENT(); int pid = atoi(d->d_name); if (pid <= 0) { continue; Loading Loading @@ -1689,7 +1742,8 @@ const char* Dumpstate::DumpTraces() { MYLOGE("Warning: no Dalvik processes found to dump stacks\n"); } return file_name_buf.release(); *path = file_name_buf.release(); return RunStatus::OK; } void Dumpstate::DumpstateBoard() { Loading Loading @@ -1730,6 +1784,7 @@ void Dumpstate::DumpstateBoard() { return; } // TODO(128270426): Check for consent in between? for (size_t i = 0; i < paths.size(); i++) { MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str()); Loading Loading @@ -2587,9 +2642,12 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, DumpstateWifiOnly(); } else { // Dump state for the default case. This also drops root. if (!DumpstateDefault()) { // Something went wrong. return RunStatus::ERROR; RunStatus s = DumpstateDefault(); if (s != RunStatus::OK) { if (s == RunStatus::USER_CONSENT_TIMED_OUT) { HandleUserConsentDenied(); } return s; } } Loading Loading @@ -2626,9 +2684,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI( "Did not receive user consent yet." " Will not copy the bugreport artifacts to caller.\n"); // TODO(b/111441001): // 1. cancel outstanding requests // 2. check for result more frequently // TODO(b/111441001): cancel outstanding requests } } Loading Loading @@ -2683,6 +2739,11 @@ void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& c } } bool Dumpstate::IsUserConsentDenied() const { return ds.consent_callback_ != nullptr && ds.consent_callback_->getResult() == UserConsentResult::DENIED; } void Dumpstate::CleanupFiles() { android::os::UnlinkAndLogOnError(tmp_path_); android::os::UnlinkAndLogOnError(screenshot_path_); Loading cmds/dumpstate/dumpstate.h +12 −2 Original line number Diff line number Diff line Loading @@ -291,8 +291,11 @@ class Dumpstate { // TODO: temporary method until Dumpstate object is properly set void SetProgress(std::unique_ptr<Progress> progress); // Dumps Dalvik and native stack traces, return the trace file location (nullptr if none). const char* DumpTraces(); // Dumps Dalvik and native stack traces, sets the trace file location to path // if it succeeded. // Note that it returns early if user consent is denied with status USER_CONSENT_DENIED. // Returns OK in all other cases. RunStatus DumpTraces(const char** path); void DumpstateBoard(); Loading Loading @@ -330,6 +333,13 @@ class Dumpstate { /* Sets runtime options. */ void SetOptions(std::unique_ptr<DumpOptions> options); /* * Returns true if user consent is necessary and has been denied. * Consent is only necessary if the caller has asked to copy over the bugreport to a file they * provided. */ bool IsUserConsentDenied() const; /* * Structure to hold options that determine the behavior of dumpstate. */ Loading cmds/dumpstate/utils.cpp +18 −4 Original line number Diff line number Diff line Loading @@ -102,14 +102,16 @@ DurationReporter::DurationReporter(const std::string& title, bool logcat_only) DurationReporter::~DurationReporter() { if (!title_.empty()) { uint64_t elapsed = Nanotime() - started_; MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC); float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC; if (elapsed < .5f) { return; } MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed); if (logcat_only_) { return; } // Use "Yoda grammar" to make it easier to grep|sort sections. printf("------ %.3fs was the duration of '%s' ------\n", (float)elapsed / NANOS_PER_SEC, title_.c_str()); printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str()); } } Loading Loading @@ -278,6 +280,12 @@ static void __for_each_pid(void (*helper)(int, const char *, void *), const char if (header) printf("\n------ %s ------\n", header); while ((de = readdir(d))) { if (ds.IsUserConsentDenied()) { MYLOGE( "Returning early because user denied consent to share bugreport with calling app."); closedir(d); return; } int pid; int fd; char cmdpath[255]; Loading Loading @@ -350,6 +358,12 @@ static void for_each_tid_helper(int pid, const char *cmdline, void *arg) { func(pid, pid, cmdline); while ((de = readdir(d))) { if (ds.IsUserConsentDenied()) { MYLOGE( "Returning early because user denied consent to share bugreport with calling app."); closedir(d); return; } int tid; int fd; char commpath[255]; Loading cmds/installd/dexopt.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -608,7 +608,7 @@ static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t f // the app uid. If we cannot do that, there's no point in returning the fd // since dex2oat/profman will fail with SElinux denials. if (fchown(fd.get(), uid, uid) < 0) { PLOG(ERROR) << "Could not chwon profile " << profile; PLOG(ERROR) << "Could not chown profile " << profile; return invalid_unique_fd(); } return fd; Loading cmds/installd/otapreopt_chroot.cpp +0 −71 Original line number Diff line number Diff line Loading @@ -41,23 +41,6 @@ using android::base::StringPrintf; namespace android { namespace installd { // Configuration for bind-mounted Bionic artifacts. static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker"; static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker"; static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/"; static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/"; static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64"; static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64"; static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/"; static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/"; static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"}; static void CloseDescriptor(int fd) { if (fd >= 0) { int result = close(fd); Loading Loading @@ -94,43 +77,6 @@ static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_pac } } // Copied from system/core/init/mount_namespace.cpp. static bool BindMount(const std::string& source, const std::string& mount_point, bool recursive = false) { unsigned long mountflags = MS_BIND; if (recursive) { mountflags |= MS_REC; } if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) { PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point; return false; } return true; } // Copied from system/core/init/mount_namespace.cpp and and adjusted (bind // mounts are not made private, as the /postinstall is already private (see // `android::installd::otapreopt_chroot`). static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source, const std::string& linker_mount_point, const std::string& lib_mount_dir) { if (access(linker_source.c_str(), F_OK) != 0) { PLOG(INFO) << linker_source << " does not exist. Skipping mounting Bionic there."; return true; } if (!BindMount(linker_source, linker_mount_point)) { return false; } for (const auto& libname : kBionicLibFileNames) { std::string mount_point = lib_mount_dir + libname; std::string source = lib_dir_source + libname; if (!BindMount(source, mount_point)) { return false; } } return true; } // Entry for otapreopt_chroot. Expected parameters are: // [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params] // The file descriptor denoted by status-fd will be closed. The rest of the parameters will Loading Loading @@ -274,23 +220,6 @@ static int otapreopt_chroot(const int argc, char **arg) { // the Android Runtime APEX, as it is required by otapreopt to run dex2oat. std::vector<apex::ApexFile> active_packages = ActivateApexPackages(); // Bind-mount Bionic artifacts from the Runtime APEX. // This logic is copied and adapted from system/core/init/mount_namespace.cpp. if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint, kBionicLibsMountPointDir)) { LOG(ERROR) << "Failed to mount 32-bit Bionic artifacts from the Runtime APEX."; // Clean up and exit. DeactivateApexPackages(active_packages); exit(215); } if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64, kBionicLibsMountPointDir64)) { LOG(ERROR) << "Failed to mount 64-bit Bionic artifacts from the Runtime APEX."; // Clean up and exit. DeactivateApexPackages(active_packages); exit(216); } // Now go on and run otapreopt. // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc Loading Loading
cmds/dumpstate/dumpstate.cpp +109 −48 Original line number Diff line number Diff line Loading @@ -131,6 +131,19 @@ static const std::string ANR_FILE_PREFIX = "anr_"; // TODO: temporary variables and functions used during C++ refactoring static Dumpstate& ds = Dumpstate::GetInstance(); #define RETURN_IF_USER_DENIED_CONSENT() \ if (ds.IsUserConsentDenied()) { \ MYLOGE("Returning early as user denied consent to share bugreport with calling app."); \ return Dumpstate::RunStatus::USER_CONSENT_DENIED; \ } // Runs func_ptr, but checks user consent before and after running it. Returns USER_CONSENT_DENIED // if consent is found to be denied. #define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(func_ptr, ...) \ RETURN_IF_USER_DENIED_CONSENT(); \ func_ptr(__VA_ARGS__); \ RETURN_IF_USER_DENIED_CONSENT(); namespace android { namespace os { namespace { Loading Loading @@ -1054,7 +1067,7 @@ static void DumpIpAddrAndRules() { RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"}); } static void RunDumpsysTextByPriority(const std::string& title, int priority, static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, int priority, std::chrono::milliseconds timeout, std::chrono::milliseconds service_timeout) { auto start = std::chrono::steady_clock::now(); Loading @@ -1064,6 +1077,7 @@ static void RunDumpsysTextByPriority(const std::string& title, int priority, Dumpsys::setServiceArgs(args, /* asProto = */ false, priority); Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false); for (const String16& service : services) { RETURN_IF_USER_DENIED_CONSENT(); std::string path(title); path.append(" - ").append(String8(service).c_str()); DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_); Loading @@ -1089,6 +1103,7 @@ static void RunDumpsysTextByPriority(const std::string& title, int priority, break; } } return Dumpstate::RunStatus::OK; } static void RunDumpsysText(const std::string& title, int priority, Loading @@ -1101,7 +1116,7 @@ static void RunDumpsysText(const std::string& title, int priority, } /* Dump all services registered with Normal or Default priority. */ static void RunDumpsysTextNormalPriority(const std::string& title, static Dumpstate::RunStatus RunDumpsysTextNormalPriority(const std::string& title, std::chrono::milliseconds timeout, std::chrono::milliseconds service_timeout) { DurationReporter duration_reporter(title); Loading @@ -1109,16 +1124,19 @@ static void RunDumpsysTextNormalPriority(const std::string& title, fsync(STDOUT_FILENO); RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, timeout, service_timeout); RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout, RETURN_IF_USER_DENIED_CONSENT(); return RunDumpsysTextByPriority(title, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT, timeout, service_timeout); } static void RunDumpsysProto(const std::string& title, int priority, static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority, std::chrono::milliseconds timeout, std::chrono::milliseconds service_timeout) { if (!ds.IsZipping()) { MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str()); return; return Dumpstate::RunStatus::OK; } sp<android::IServiceManager> sm = defaultServiceManager(); Dumpsys dumpsys(sm.get()); Loading @@ -1129,6 +1147,7 @@ static void RunDumpsysProto(const std::string& title, int priority, auto start = std::chrono::steady_clock::now(); Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true); for (const String16& service : services) { RETURN_IF_USER_DENIED_CONSENT(); std::string path(kProtoPath); path.append(String8(service).c_str()); if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) { Loading Loading @@ -1157,31 +1176,41 @@ static void RunDumpsysProto(const std::string& title, int priority, break; } } return Dumpstate::RunStatus::OK; } // Runs dumpsys on services that must dump first and will take less than 100ms to dump. static void RunDumpsysCritical() { static Dumpstate::RunStatus RunDumpsysCritical() { RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, /* timeout= */ 5s, /* service_timeout= */ 500ms); RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, RETURN_IF_USER_DENIED_CONSENT(); return RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, /* timeout= */ 5s, /* service_timeout= */ 500ms); } // Runs dumpsys on services that must dump first but can take up to 250ms to dump. static void RunDumpsysHigh() { static Dumpstate::RunStatus RunDumpsysHigh() { // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both // high priority. Reduce timeout once they are able to dump in a shorter time or // moved to a parallel task. RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH, /* timeout= */ 90s, /* service_timeout= */ 30s); RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH, RETURN_IF_USER_DENIED_CONSENT(); return RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH, /* timeout= */ 5s, /* service_timeout= */ 1s); } // Runs dumpsys on services that must dump but can take up to 10s to dump. static void RunDumpsysNormal() { static Dumpstate::RunStatus RunDumpsysNormal() { RunDumpsysTextNormalPriority("DUMPSYS", /* timeout= */ 90s, /* service_timeout= */ 10s); RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, RETURN_IF_USER_DENIED_CONSENT(); return RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL, /* timeout= */ 90s, /* service_timeout= */ 10s); } Loading Loading @@ -1244,9 +1273,16 @@ static void DumpHals() { } } static void dumpstate() { // Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent // via the consent they are shown. Ignores other errors that occur while running various // commands. The consent checking is currently done around long running tasks, which happen to // be distributed fairly evenly throughout the function. static Dumpstate::RunStatus dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); // Dump various things. Note that anything that takes "long" (i.e. several seconds) should // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK). dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); RunCommand("UPTIME", {"uptime"}); DumpBlockStatFiles(); Loading @@ -1254,7 +1290,9 @@ static void dumpstate() { DumpFile("MEMORY INFO", "/proc/meminfo"); RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"}); RunCommand("PROCRANK", {"procrank"}, AS_ROOT_20); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20); DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat"); DumpFile("VMALLOC INFO", "/proc/vmallocinfo"); DumpFile("SLAB INFO", "/proc/slabinfo"); Loading @@ -1269,7 +1307,9 @@ static void dumpstate() { RunCommand("PROCESSES AND THREADS", {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"}); RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"}, CommandOptions::AS_ROOT); DumpHals(); Loading @@ -1290,7 +1330,9 @@ static void dumpstate() { } RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT); for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES"); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES"); for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS"); for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)"); Loading Loading @@ -1328,7 +1370,7 @@ static void dumpstate() { RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"}); RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"}); RunDumpsysHigh(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh); RunCommand("SYSTEM PROPERTIES", {"getprop"}); Loading @@ -1351,7 +1393,7 @@ static void dumpstate() { ds.AddDir(WMTRACE_DATA_DIR, false); } ds.DumpstateBoard(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard); /* Migrate the ril_dumpstate to a device specific dumpstate? */ int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0); Loading @@ -1371,14 +1413,16 @@ static void dumpstate() { printf("== Android Framework Services\n"); printf("========================================================\n"); RunDumpsysNormal(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal); printf("========================================================\n"); printf("== Checkins\n"); printf("========================================================\n"); RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}); RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"}); RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}); RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}); RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}); Loading Loading @@ -1442,19 +1486,27 @@ static void dumpstate() { printf("========================================================\n"); // This differs from the usual dumpsys stats, which is the stats report data. RunDumpsys("STATSDSTATS", {"stats", "--metadata"}); return Dumpstate::RunStatus::OK; } /* Dumps state for the default case. Returns true if everything went fine. */ static bool DumpstateDefault() { /* * Dumps state for the default case; drops root after it's no longer necessary. * * Returns RunStatus::OK if everything went fine. * Returns RunStatus::ERROR if there was an error. * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport * with the caller. */ static Dumpstate::RunStatus DumpstateDefault() { // Try to dump anrd trace if the daemon is running. dump_anrd_trace(); // Invoking the following dumpsys calls before dump_traces() to try and // Invoking the following dumpsys calls before DumpTraces() to try and // keep the system stats as close to its initial state as possible. RunDumpsysCritical(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical); /* collect stack traces from Dalvik and native processes (needs root) */ dump_traces_path = ds.DumpTraces(); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path); /* Run some operations that require root. */ ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping()); Loading Loading @@ -1490,11 +1542,11 @@ static bool DumpstateDefault() { } if (!DropRootUser()) { return false; return Dumpstate::RunStatus::ERROR; } dumpstate(); return true; RETURN_IF_USER_DENIED_CONSENT(); return dumpstate(); } // This method collects common dumpsys for telephony and wifi Loading Loading @@ -1584,7 +1636,7 @@ static void DumpstateWifiOnly() { printf("========================================================\n"); } const char* Dumpstate::DumpTraces() { Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) { DurationReporter duration_reporter("DUMP TRACES"); const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX"; Loading @@ -1600,7 +1652,7 @@ const char* Dumpstate::DumpTraces() { android::base::unique_fd fd(mkostemp(file_name_buf.get(), O_APPEND | O_CLOEXEC)); if (fd < 0) { MYLOGE("mkostemp on pattern %s: %s\n", file_name_buf.get(), strerror(errno)); return nullptr; return RunStatus::OK; } // Nobody should have access to this temporary file except dumpstate, but we Loading @@ -1610,13 +1662,13 @@ const char* Dumpstate::DumpTraces() { const int chmod_ret = fchmod(fd, 0666); if (chmod_ret < 0) { MYLOGE("fchmod on %s failed: %s\n", file_name_buf.get(), strerror(errno)); return nullptr; return RunStatus::OK; } std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir); if (proc.get() == nullptr) { MYLOGE("opendir /proc failed: %s\n", strerror(errno)); return nullptr; return RunStatus::OK; } // Number of times process dumping has timed out. If we encounter too many Loading @@ -1628,6 +1680,7 @@ const char* Dumpstate::DumpTraces() { struct dirent* d; while ((d = readdir(proc.get()))) { RETURN_IF_USER_DENIED_CONSENT(); int pid = atoi(d->d_name); if (pid <= 0) { continue; Loading Loading @@ -1689,7 +1742,8 @@ const char* Dumpstate::DumpTraces() { MYLOGE("Warning: no Dalvik processes found to dump stacks\n"); } return file_name_buf.release(); *path = file_name_buf.release(); return RunStatus::OK; } void Dumpstate::DumpstateBoard() { Loading Loading @@ -1730,6 +1784,7 @@ void Dumpstate::DumpstateBoard() { return; } // TODO(128270426): Check for consent in between? for (size_t i = 0; i < paths.size(); i++) { MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str()); Loading Loading @@ -2587,9 +2642,12 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, DumpstateWifiOnly(); } else { // Dump state for the default case. This also drops root. if (!DumpstateDefault()) { // Something went wrong. return RunStatus::ERROR; RunStatus s = DumpstateDefault(); if (s != RunStatus::OK) { if (s == RunStatus::USER_CONSENT_TIMED_OUT) { HandleUserConsentDenied(); } return s; } } Loading Loading @@ -2626,9 +2684,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI( "Did not receive user consent yet." " Will not copy the bugreport artifacts to caller.\n"); // TODO(b/111441001): // 1. cancel outstanding requests // 2. check for result more frequently // TODO(b/111441001): cancel outstanding requests } } Loading Loading @@ -2683,6 +2739,11 @@ void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& c } } bool Dumpstate::IsUserConsentDenied() const { return ds.consent_callback_ != nullptr && ds.consent_callback_->getResult() == UserConsentResult::DENIED; } void Dumpstate::CleanupFiles() { android::os::UnlinkAndLogOnError(tmp_path_); android::os::UnlinkAndLogOnError(screenshot_path_); Loading
cmds/dumpstate/dumpstate.h +12 −2 Original line number Diff line number Diff line Loading @@ -291,8 +291,11 @@ class Dumpstate { // TODO: temporary method until Dumpstate object is properly set void SetProgress(std::unique_ptr<Progress> progress); // Dumps Dalvik and native stack traces, return the trace file location (nullptr if none). const char* DumpTraces(); // Dumps Dalvik and native stack traces, sets the trace file location to path // if it succeeded. // Note that it returns early if user consent is denied with status USER_CONSENT_DENIED. // Returns OK in all other cases. RunStatus DumpTraces(const char** path); void DumpstateBoard(); Loading Loading @@ -330,6 +333,13 @@ class Dumpstate { /* Sets runtime options. */ void SetOptions(std::unique_ptr<DumpOptions> options); /* * Returns true if user consent is necessary and has been denied. * Consent is only necessary if the caller has asked to copy over the bugreport to a file they * provided. */ bool IsUserConsentDenied() const; /* * Structure to hold options that determine the behavior of dumpstate. */ Loading
cmds/dumpstate/utils.cpp +18 −4 Original line number Diff line number Diff line Loading @@ -102,14 +102,16 @@ DurationReporter::DurationReporter(const std::string& title, bool logcat_only) DurationReporter::~DurationReporter() { if (!title_.empty()) { uint64_t elapsed = Nanotime() - started_; MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC); float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC; if (elapsed < .5f) { return; } MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed); if (logcat_only_) { return; } // Use "Yoda grammar" to make it easier to grep|sort sections. printf("------ %.3fs was the duration of '%s' ------\n", (float)elapsed / NANOS_PER_SEC, title_.c_str()); printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str()); } } Loading Loading @@ -278,6 +280,12 @@ static void __for_each_pid(void (*helper)(int, const char *, void *), const char if (header) printf("\n------ %s ------\n", header); while ((de = readdir(d))) { if (ds.IsUserConsentDenied()) { MYLOGE( "Returning early because user denied consent to share bugreport with calling app."); closedir(d); return; } int pid; int fd; char cmdpath[255]; Loading Loading @@ -350,6 +358,12 @@ static void for_each_tid_helper(int pid, const char *cmdline, void *arg) { func(pid, pid, cmdline); while ((de = readdir(d))) { if (ds.IsUserConsentDenied()) { MYLOGE( "Returning early because user denied consent to share bugreport with calling app."); closedir(d); return; } int tid; int fd; char commpath[255]; Loading
cmds/installd/dexopt.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -608,7 +608,7 @@ static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t f // the app uid. If we cannot do that, there's no point in returning the fd // since dex2oat/profman will fail with SElinux denials. if (fchown(fd.get(), uid, uid) < 0) { PLOG(ERROR) << "Could not chwon profile " << profile; PLOG(ERROR) << "Could not chown profile " << profile; return invalid_unique_fd(); } return fd; Loading
cmds/installd/otapreopt_chroot.cpp +0 −71 Original line number Diff line number Diff line Loading @@ -41,23 +41,6 @@ using android::base::StringPrintf; namespace android { namespace installd { // Configuration for bind-mounted Bionic artifacts. static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker"; static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker"; static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/"; static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/"; static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64"; static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64"; static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/"; static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/"; static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"}; static void CloseDescriptor(int fd) { if (fd >= 0) { int result = close(fd); Loading Loading @@ -94,43 +77,6 @@ static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_pac } } // Copied from system/core/init/mount_namespace.cpp. static bool BindMount(const std::string& source, const std::string& mount_point, bool recursive = false) { unsigned long mountflags = MS_BIND; if (recursive) { mountflags |= MS_REC; } if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) { PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point; return false; } return true; } // Copied from system/core/init/mount_namespace.cpp and and adjusted (bind // mounts are not made private, as the /postinstall is already private (see // `android::installd::otapreopt_chroot`). static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source, const std::string& linker_mount_point, const std::string& lib_mount_dir) { if (access(linker_source.c_str(), F_OK) != 0) { PLOG(INFO) << linker_source << " does not exist. Skipping mounting Bionic there."; return true; } if (!BindMount(linker_source, linker_mount_point)) { return false; } for (const auto& libname : kBionicLibFileNames) { std::string mount_point = lib_mount_dir + libname; std::string source = lib_dir_source + libname; if (!BindMount(source, mount_point)) { return false; } } return true; } // Entry for otapreopt_chroot. Expected parameters are: // [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params] // The file descriptor denoted by status-fd will be closed. The rest of the parameters will Loading Loading @@ -274,23 +220,6 @@ static int otapreopt_chroot(const int argc, char **arg) { // the Android Runtime APEX, as it is required by otapreopt to run dex2oat. std::vector<apex::ApexFile> active_packages = ActivateApexPackages(); // Bind-mount Bionic artifacts from the Runtime APEX. // This logic is copied and adapted from system/core/init/mount_namespace.cpp. if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint, kBionicLibsMountPointDir)) { LOG(ERROR) << "Failed to mount 32-bit Bionic artifacts from the Runtime APEX."; // Clean up and exit. DeactivateApexPackages(active_packages); exit(215); } if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64, kBionicLibsMountPointDir64)) { LOG(ERROR) << "Failed to mount 64-bit Bionic artifacts from the Runtime APEX."; // Clean up and exit. DeactivateApexPackages(active_packages); exit(216); } // Now go on and run otapreopt. // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc Loading