diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0d20b6487c61e7d1bde93acf4a14b7a89083a16d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index e048a1914545e0240347aedc27a7581425e0a08c..0473bb833e24280837ce79331f6b762ec4ecf666 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -6,6 +6,7 @@ clang_format = true clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp cmds/idlcli/ include/input/ + libs/binder/fuzzer/ libs/binder/ndk/ libs/binderthreadstate/ libs/graphicsenv/ diff --git a/aidl/gui/android/view/LayerMetadataKey.aidl b/aidl/gui/android/view/LayerMetadataKey.aidl new file mode 100644 index 0000000000000000000000000000000000000000..7026ca8fadfc7b8b49478639625937622ed647f8 --- /dev/null +++ b/aidl/gui/android/view/LayerMetadataKey.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +/** @hide */ +@Backing(type="int") +enum LayerMetadataKey { + METADATA_OWNER_UID = 1, + METADATA_WINDOW_TYPE = 2, + METADATA_TASK_ID = 3, + METADATA_MOUSE_CURSOR = 4, +} diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 0637693c9db8072ff3e765640e7cfe751e4b90ee..994375b30e541c702b487ec28255ad52fb9c211f 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -129,6 +129,8 @@ on late-init chmod 0666 /sys/kernel/tracing/events/task/task_rename/enable chmod 0666 /sys/kernel/debug/tracing/events/task/task_newtask/enable chmod 0666 /sys/kernel/tracing/events/task/task_newtask/enable + chmod 0666 /sys/kernel/debug/tracing/events/gpu_mem/gpu_mem_total/enable + chmod 0666 /sys/kernel/tracing/events/gpu_mem/gpu_mem_total/enable # disk chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index ba54d1343698a00b1256bc37281fb54a61a953f8..ead491e4dd85e5a13ccd6489a5c1aacf95b39672 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -66,7 +66,6 @@ filegroup { name: "dumpstate_aidl", srcs: [ "binder/android/os/IDumpstateListener.aidl", - "binder/android/os/IDumpstateToken.aidl", "binder/android/os/IDumpstate.aidl", ], path: "binder", @@ -77,6 +76,7 @@ cc_defaults { defaults: ["dumpstate_cflag_defaults"], shared_libs: [ "android.hardware.dumpstate@1.0", + "android.hardware.dumpstate@1.1", "libziparchive", "libbase", "libbinder", diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index 10d3d1756b9bc73026e0a8c8480bdd5c726ba353..bfcc058c1bb793fb5bbc44fe65ad5811c5f33b83 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -58,8 +58,6 @@ static binder::Status exception(uint32_t code, const std::string& msg) { exit(0); } -class DumpstateToken : public BnDumpstateToken {}; - } // namespace DumpstateService::DumpstateService() : ds_(nullptr) { @@ -81,48 +79,16 @@ status_t DumpstateService::Start() { return android::OK; } -// Note: this method is part of the old flow and is not expected to be used in combination -// with startBugreport. -binder::Status DumpstateService::setListener(const std::string& name, - const sp& listener, - bool getSectionDetails, - sp* returned_token) { - *returned_token = nullptr; - if (name.empty()) { - MYLOGE("setListener(): name not set\n"); - return binder::Status::ok(); - } - if (listener == nullptr) { - MYLOGE("setListener(): listener not set\n"); - return binder::Status::ok(); - } - std::lock_guard lock(lock_); - if (ds_ == nullptr) { - ds_ = &(Dumpstate::GetInstance()); - } - if (ds_->listener_ != nullptr) { - MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str()); - return binder::Status::ok(); - } - - ds_->listener_name_ = name; - ds_->listener_ = listener; - ds_->report_section_ = getSectionDetails; - *returned_token = new DumpstateToken(); - - return binder::Status::ok(); -} - binder::Status DumpstateService::startBugreport(int32_t calling_uid, const std::string& calling_package, android::base::unique_fd bugreport_fd, android::base::unique_fd screenshot_fd, int bugreport_mode, - const sp& listener) { + const sp& listener, + bool is_screenshot_requested) { MYLOGI("startBugreport() with mode: %d\n", bugreport_mode); - // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a - // time. + // Ensure there is only one bugreport in progress at a time. std::lock_guard lock(lock_); if (ds_ != nullptr) { MYLOGE("Error! There is already a bugreport in progress. Returning."); @@ -153,9 +119,9 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, std::unique_ptr options = std::make_unique(); options->Initialize(static_cast(bugreport_mode), bugreport_fd, - screenshot_fd); + screenshot_fd, is_screenshot_requested); - if (bugreport_fd.get() == -1 || (options->do_fb && screenshot_fd.get() == -1)) { + if (bugreport_fd.get() == -1 || (options->do_screenshot && screenshot_fd.get() == -1)) { MYLOGE("Invalid filedescriptor"); signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); } @@ -171,6 +137,8 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, ds_info->calling_package = calling_package; pthread_t thread; + // Initialize dumpstate + ds_->Initialize(); status_t err = pthread_create(&thread, nullptr, dumpstate_thread_main, ds_info); if (err != 0) { delete ds_info; @@ -182,14 +150,13 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, } binder::Status DumpstateService::cancelBugreport() { - // This is a no-op since the cancellation is done from java side via setting sys properties. - // See BugreportManagerServiceImpl. - // TODO(b/111441001): maybe make native and java sides use different binder interface - // to avoid these annoyances. + std::lock_guard lock(lock_); + ds_->Cancel(); return binder::Status::ok(); } status_t DumpstateService::dump(int fd, const Vector&) { + std::lock_guard lock(lock_); if (ds_ == nullptr) { dprintf(fd, "Bugreport not in progress yet"); return NO_ERROR; @@ -204,19 +171,17 @@ status_t DumpstateService::dump(int fd, const Vector&) { dprintf(fd, "progress:\n"); ds_->progress_->Dump(fd, " "); dprintf(fd, "args: %s\n", ds_->options_->args.c_str()); - dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str()); + dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode.c_str()); dprintf(fd, "version: %s\n", ds_->version_.c_str()); dprintf(fd, "bugreport_dir: %s\n", destination.c_str()); dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str()); dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str()); dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str()); dprintf(fd, "path: %s\n", ds_->path_.c_str()); - dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str()); dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str()); dprintf(fd, "name: %s\n", ds_->name_.c_str()); dprintf(fd, "now: %ld\n", ds_->now_); dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false"); - dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str()); dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str()); dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str()); diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h index aaaa4286cc274d794a7bb73ce05e785f7ff04945..ac8d3acbb5f494b44681d01480b717a4ad26ef74 100644 --- a/cmds/dumpstate/DumpstateService.h +++ b/cmds/dumpstate/DumpstateService.h @@ -24,7 +24,6 @@ #include #include "android/os/BnDumpstate.h" -#include "android/os/BnDumpstateToken.h" #include "dumpstate.h" namespace android { @@ -38,14 +37,12 @@ class DumpstateService : public BinderService, public BnDumpst static char const* getServiceName(); status_t dump(int fd, const Vector& args) override; - binder::Status setListener(const std::string& name, const sp& listener, - bool getSectionDetails, - sp* returned_token) override; binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package, android::base::unique_fd bugreport_fd, android::base::unique_fd screenshot_fd, int bugreport_mode, - const sp& listener) override; + const sp& listener, + bool is_screenshot_requested) override; // No-op binder::Status cancelBugreport(); diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md index c818c05117464e1e34b5df83d514fd1e84b97f62..26dabbbcef8800d959c05248d61a52148543ab89 100644 --- a/cmds/dumpstate/README.md +++ b/cmds/dumpstate/README.md @@ -92,6 +92,12 @@ Then to restore the default version: adb shell setprop dumpstate.version default ``` +## To set Bugreport API workflow for bugreport + +``` +adb shell setprop settings_call_bugreport_api true +``` + ## Code style and formatting Use the style defined at the diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index cb2d8b8d2c16c995e0aa0d84216ccb7f75b21b71..ba008bb27ee45634d09743e62cef4b875007144a 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -17,24 +17,12 @@ package android.os; import android.os.IDumpstateListener; -import android.os.IDumpstateToken; /** * Binder interface for the currently running dumpstate process. * {@hide} */ interface IDumpstate { - // TODO: remove method once startBugReport is used by Shell. - /* - * Sets the listener for this dumpstate progress. - * - * Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already - * set (the listener behaves like a Highlander: There Can be Only One). - * Set {@code getSectionDetails} to true in order to receive callbacks with per section - * progress details - */ - IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener, - boolean getSectionDetails); // NOTE: If you add to or change these modes, please also change the corresponding enums // in system server, in BugreportParams.java. @@ -76,10 +64,12 @@ interface IDumpstate { * @param screenshotFd the file to which screenshot should be written * @param bugreportMode the mode that specifies other run time options; must be one of above * @param listener callback for updates; optional + * @param isScreenshotRequested indicates screenshot is requested or not */ void startBugreport(int callingUid, @utf8InCpp String callingPackage, FileDescriptor bugreportFd, FileDescriptor screenshotFd, - int bugreportMode, IDumpstateListener listener); + int bugreportMode, IDumpstateListener listener, + boolean isScreenshotRequested); /* * Cancels the bugreport currently in progress. diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl index e4864607535f7054c38583531b3cefb8845404d7..a5e6c68363d4f225509d3a4c93fa36f361519cd5 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl @@ -32,7 +32,7 @@ interface IDumpstateListener { * * @param progress the progress in [0, 100] */ - void onProgress(int progress); + oneway void onProgress(int progress); // NOTE: If you add to or change these error codes, please also change the corresponding enums // in system server, in BugreportManager.java. @@ -54,11 +54,23 @@ interface IDumpstateListener { /** * Called on an error condition with one of the error codes listed above. + * This is not an asynchronous method since it can race with dumpstate exiting, thus triggering + * death recipient. */ void onError(int errorCode); /** * Called when taking bugreport finishes successfully. */ - void onFinished(); + oneway void onFinished(); + + /** + * Called when screenshot is taken. + */ + oneway void onScreenshotTaken(boolean success); + + /** + * Called when ui intensive bugreport dumps are finished. + */ + oneway void onUiIntensiveBugreportDumpsFinished(String callingPackage); } diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index e2884e578cdcfd4b2f2f415a88552babbccecdba..af41643d5d1501118bd075684e7173667a872e53 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -64,6 +64,8 @@ #include #include #include +#include +#include #include #include #include @@ -86,7 +88,11 @@ #include "DumpstateService.h" #include "dumpstate.h" -using ::android::hardware::dumpstate::V1_0::IDumpstateDevice; +using IDumpstateDevice_1_0 = ::android::hardware::dumpstate::V1_0::IDumpstateDevice; +using IDumpstateDevice_1_1 = ::android::hardware::dumpstate::V1_1::IDumpstateDevice; +using ::android::hardware::dumpstate::V1_1::DumpstateMode; +using ::android::hardware::dumpstate::V1_1::DumpstateStatus; +using ::android::hardware::dumpstate::V1_1::toString; using ::std::literals::chrono_literals::operator""ms; using ::std::literals::chrono_literals::operator""s; @@ -204,6 +210,10 @@ static int Open(std::string path, int flags, mode_t mode = 0) { return fd; } +static int OpenForWrite(std::string path) { + return Open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +} static int OpenForRead(std::string path) { return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); @@ -235,6 +245,9 @@ static bool CopyFileToFd(const std::string& input_file, int out_fd) { } static bool UnlinkAndLogOnError(const std::string& file) { + if (file.empty()) { + return false; + } if (unlink(file.c_str())) { MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno)); return false; @@ -242,15 +255,6 @@ static bool UnlinkAndLogOnError(const std::string& file) { return true; } -static bool IsFileEmpty(const std::string& file_path) { - std::ifstream file(file_path, std::ios::binary | std::ios::ate); - if(file.bad()) { - MYLOGE("Cannot open file: %s\n", file_path.c_str()); - return true; - } - return file.tellg() <= 0; -} - int64_t GetModuleMetadataVersion() { auto binder = defaultServiceManager()->getService(android::String16("package_native")); if (binder == nullptr) { @@ -275,6 +279,27 @@ int64_t GetModuleMetadataVersion() { return version_code; } +static bool PathExists(const std::string& path) { + struct stat sb; + return stat(path.c_str(), &sb) == 0; +} + +static bool CopyFileToFile(const std::string& input_file, const std::string& output_file) { + if (input_file == output_file) { + MYLOGD("Skipping copying bugreport file since the destination is the same (%s)\n", + output_file.c_str()); + return false; + } + else if (PathExists(output_file)) { + MYLOGD("Cannot overwrite an existing file (%s)\n", output_file.c_str()); + return false; + } + + MYLOGD("Going to copy bugreport file (%s) to %s\n", input_file.c_str(), output_file.c_str()); + android::base::unique_fd out_fd(OpenForWrite(output_file)); + return CopyFileToFd(input_file, out_fd.get()); +} + } // namespace } // namespace os } // namespace android @@ -299,18 +324,16 @@ static const std::string kDumpstateBoardFiles[] = { }; static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles); -static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options"; static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id"; static constexpr char PROPERTY_VERSION[] = "dumpstate.version"; -static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title"; -static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description"; static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build(); /* * 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. + * The returned vector is sorted by the mtimes of the dumps with descending + * order. If |limit_by_mtime| is set, the vector only contains files that + * were written in the last 30 minutes. */ static std::vector GetDumpFds(const std::string& dir_path, const std::string& file_prefix, @@ -357,6 +380,10 @@ static std::vector GetDumpFds(const std::string& dir_path, dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime}); } + if (!dump_data.empty()) { + std::sort(dump_data.begin(), dump_data.end(), + [](const auto& a, const auto& b) { return a.mtime > b.mtime; }); + } return dump_data; } @@ -664,6 +691,24 @@ android::binder::Status Dumpstate::ConsentCallback::onReportApproved() { std::lock_guard lock(lock_); result_ = APPROVED; MYLOGD("User approved consent to share bugreport\n"); + + // Maybe copy screenshot so calling app can display the screenshot to the user as soon as + // consent is granted. + if (ds.options_->is_screenshot_copied) { + return android::binder::Status::ok(); + } + + if (!ds.options_->do_screenshot || ds.options_->screenshot_fd.get() == -1 || + !ds.do_early_screenshot_) { + return android::binder::Status::ok(); + } + + bool copy_succeeded = android::os::CopyFileToFd(ds.screenshot_path_, + ds.options_->screenshot_fd.get()); + ds.options_->is_screenshot_copied = copy_succeeded; + if (copy_succeeded) { + android::os::UnlinkAndLogOnError(ds.screenshot_path_); + } return android::binder::Status::ok(); } @@ -717,8 +762,8 @@ void Dumpstate::PrintHeader() const { RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"}, CommandOptions::WithTimeout(1).Always().Build()); printf("Bugreport format version: %s\n", version_.c_str()); - printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_, - PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str()); + printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s bugreport_mode=%s\n", id_, pid_, + PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str()); printf("\n"); } @@ -968,6 +1013,31 @@ static void DumpIncidentReport() { unlink(path.c_str()); } +static void DumpVisibleWindowViews() { + if (!ds.IsZipping()) { + MYLOGD("Not dumping visible views because it's not a zipped bugreport\n"); + return; + } + DurationReporter duration_reporter("VISIBLE WINDOW VIEWS"); + const std::string path = ds.bugreport_internal_dir_ + "/tmp_visible_window_views"; + auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))); + if (fd < 0) { + MYLOGE("Could not open %s to dump visible views.\n", path.c_str()); + return; + } + RunCommandToFd(fd, "", {"cmd", "window", "dump-visible-window-views"}, + CommandOptions::WithTimeout(120).Build()); + bool empty = 0 == lseek(fd, 0, SEEK_END); + if (!empty) { + ds.AddZipEntry("visible_windows.zip", path); + } else { + MYLOGW("Failed to dump visible windows\n"); + } + unlink(path.c_str()); +} + static void DumpIpTablesAsRoot() { RunCommand("IPTABLES", {"iptables", "-L", "-nvx"}); RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"}); @@ -1333,6 +1403,46 @@ static void DumpExternalFragmentationInfo() { printf("\n"); } +static void DumpstateLimitedOnly() { + // Trimmed-down version of dumpstate to only include a whitelisted + // set of logs (system log, event log, and system server / system app + // crashes, and networking logs). See b/136273873 and b/138459828 + // for context. + DurationReporter duration_reporter("DUMPSTATE"); + unsigned long timeout_ms; + // calculate timeout + timeout_ms = logcat_timeout({"main", "system", "crash"}); + RunCommand("SYSTEM LOG", + {"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); + timeout_ms = logcat_timeout({"events"}); + RunCommand( + "EVENT LOG", + {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"}, + CommandOptions::WithTimeoutInMs(timeout_ms).Build()); + + printf("========================================================\n"); + printf("== Networking Service\n"); + printf("========================================================\n"); + + RunDumpsys("DUMPSYS NETWORK_SERVICE_LIMITED", {"wifi", "-a"}, + CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); + + printf("========================================================\n"); + printf("== Dropbox crashes\n"); + printf("========================================================\n"); + + RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"}); + RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"}); + + printf("========================================================\n"); + printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(), + ds.progress_->GetMax(), ds.progress_->GetInitialMax()); + printf("========================================================\n"); + printf("== dumpstate: done (id %d)\n", ds.id_); + printf("========================================================\n"); +} + // 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 @@ -1352,6 +1462,8 @@ static Dumpstate::RunStatus dumpstate() { RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20); + RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpVisibleWindowViews); + DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat"); DumpFile("VMALLOC INFO", "/proc/vmallocinfo"); DumpFile("SLAB INFO", "/proc/slabinfo"); @@ -1396,7 +1508,7 @@ static Dumpstate::RunStatus dumpstate() { /* Dump Bluetooth HCI logs */ ds.AddDir("/data/misc/bluetooth/logs", true); - if (ds.options_->do_fb && !ds.do_early_screenshot_) { + if (ds.options_->do_screenshot && !ds.do_early_screenshot_) { MYLOGI("taking late screenshot\n"); ds.TakeScreenshot(); } @@ -1560,11 +1672,7 @@ static Dumpstate::RunStatus dumpstate() { * Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport * with the caller. */ -static Dumpstate::RunStatus DumpstateDefault() { - // Invoking the following dumpsys calls before DumpTraces() to try and - // keep the system stats as close to its initial state as possible. - RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical); - +Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { // Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the // buffer. DoLogcat(); @@ -1667,7 +1775,7 @@ static void DumpstateRadioCommon(bool include_sensitive_info = true) { // information. This information MUST NOT identify user-installed packages (UIDs are OK, package // names are not), and MUST NOT contain logs of user application traffic. // TODO(b/148168577) rename this and other related fields/methods to "connectivity" instead. -static void DumpstateTelephonyOnly() { +static void DumpstateTelephonyOnly(const std::string& calling_package) { DurationReporter duration_reporter("DUMPSTATE"); const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build(); @@ -1690,14 +1798,23 @@ static void DumpstateTelephonyOnly() { RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); - // TODO(b/146521742) build out an argument to include bound services here for user builds - RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), - SEC_TO_MSEC(10)); - RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(), - SEC_TO_MSEC(10)); + if (include_sensitive_info) { + // Carrier apps' services will be dumped below in dumpsys activity service all-non-platform. + RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + } else { + // If the caller is a carrier app and has a carrier service, dump it here since we aren't + // running dumpsys activity service all-non-platform below. Due to the increased output, we + // give a higher timeout as well. + RunDumpsys("DUMPSYS", {"carrier_config", "--requesting-package", calling_package}, + CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(30)); + } + RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); + RunDumpsys("DUMPSYS", {"telephony.registry"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); if (include_sensitive_info) { // Contains raw IP addresses, omit from reports on user builds. RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); @@ -1893,8 +2010,8 @@ void Dumpstate::DumpstateBoard() { std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i]))); } - sp dumpstate_device(IDumpstateDevice::getService()); - if (dumpstate_device == nullptr) { + sp dumpstate_device_1_0(IDumpstateDevice_1_0::getService()); + if (dumpstate_device_1_0 == nullptr) { MYLOGE("No IDumpstateDevice implementation\n"); return; } @@ -1925,29 +2042,54 @@ void Dumpstate::DumpstateBoard() { handle.get()->data[i] = fd.release(); } - // Given that bugreport is required to diagnose failures, it's better to - // set an arbitrary amount of timeout for IDumpstateDevice than to block the - // rest of bugreport. In the timeout case, we will kill dumpstate board HAL - // and grab whatever dumped - std::packaged_task - dumpstate_task([paths, dumpstate_device, &handle]() -> bool { - android::hardware::Return status = dumpstate_device->dumpstateBoard(handle.get()); + // Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount + // of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we + // will kill the HAL and grab whatever it dumped in time. + constexpr size_t timeout_sec = 30; + // Prefer version 1.1 if available. New devices launching with R are no longer allowed to + // implement just 1.0. + const char* descriptor_to_kill; + using DumpstateBoardTask = std::packaged_task; + DumpstateBoardTask dumpstate_board_task; + sp dumpstate_device_1_1( + IDumpstateDevice_1_1::castFrom(dumpstate_device_1_0)); + if (dumpstate_device_1_1 != nullptr) { + MYLOGI("Using IDumpstateDevice v1.1"); + descriptor_to_kill = IDumpstateDevice_1_1::descriptor; + dumpstate_board_task = DumpstateBoardTask([this, dumpstate_device_1_1, &handle]() -> bool { + ::android::hardware::Return status = + dumpstate_device_1_1->dumpstateBoard_1_1(handle.get(), options_->dumpstate_hal_mode, + SEC_TO_MSEC(timeout_sec)); if (!status.isOk()) { MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str()); return false; + } else if (status != DumpstateStatus::OK) { + MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n", toString(status).c_str()); + return false; } return true; }); + } else { + MYLOGI("Using IDumpstateDevice v1.0"); + descriptor_to_kill = IDumpstateDevice_1_0::descriptor; + dumpstate_board_task = DumpstateBoardTask([dumpstate_device_1_0, &handle]() -> bool { + ::android::hardware::Return status = + dumpstate_device_1_0->dumpstateBoard(handle.get()); + if (!status.isOk()) { + MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str()); + return false; + } + return true; + }); + } + auto result = dumpstate_board_task.get_future(); + std::thread(std::move(dumpstate_board_task)).detach(); - auto result = dumpstate_task.get_future(); - std::thread(std::move(dumpstate_task)).detach(); - - constexpr size_t timeout_sec = 30; if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) { MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec); - if (!android::base::SetProperty("ctl.interface_restart", - android::base::StringPrintf("%s/default", - IDumpstateDevice::descriptor))) { + if (!android::base::SetProperty( + "ctl.interface_restart", + android::base::StringPrintf("%s/default", descriptor_to_kill))) { MYLOGE("Couldn't restart dumpstate HAL\n"); } } @@ -1979,30 +2121,28 @@ void Dumpstate::DumpstateBoard() { continue; } AddZipEntry(kDumpstateBoardFiles[i], paths[i]); + printf("*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str()); } - - printf("*** See dumpstate-board.txt entry ***\n"); } static void ShowUsage() { fprintf(stderr, - "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] " - "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" + "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-d] [-p] " + "[-z] [-s] [-S] [-q] [-P] [-R] [-L] [-V version]\n" " -h: display this help message\n" " -b: play sound file instead of vibrate, at beginning of job\n" " -e: play sound file instead of vibrate, at end of job\n" + " -o: write to custom directory (only in limited mode)\n" " -d: append date to filename\n" " -p: capture screenshot to filename.png\n" " -z: generate zipped file\n" " -s: write output to control socket (for init)\n" " -S: write file location to control socket (for init; requires -z)\n" " -q: disable vibrate\n" - " -B: send broadcast when finished\n" - " -P: send broadcast when started and update system properties on " - "progress (requires -B)\n" - " -R: take bugreport in remote mode (requires -z, -d and -B, " - "shouldn't be used with -P)\n" + " -P: send broadcast when started and do progress updates\n" + " -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n" " -w: start binder service and make it wait for a call to startBugreport\n" + " -L: output limited information that is safe for submission in feedback reports\n" " -v: prints the dumpstate header and exit\n"); } @@ -2058,41 +2198,6 @@ bool Dumpstate::FinishZipFile() { return true; } -static std::string SHA256_file_hash(const std::string& filepath) { - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK - | O_CLOEXEC | O_NOFOLLOW))); - if (fd == -1) { - MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno)); - return nullptr; - } - - SHA256_CTX ctx; - SHA256_Init(&ctx); - - std::vector buffer(65536); - while (1) { - ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size())); - if (bytes_read == 0) { - break; - } else if (bytes_read == -1) { - MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno)); - return nullptr; - } - - SHA256_Update(&ctx, buffer.data(), bytes_read); - } - - uint8_t hash[SHA256_DIGEST_LENGTH]; - SHA256_Final(hash, &ctx); - - char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1]; - for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) { - sprintf(hash_buffer + (i * 2), "%02x", hash[i]); - } - hash_buffer[sizeof(hash_buffer) - 1] = 0; - return std::string(hash_buffer); -} - static void SendBroadcast(const std::string& action, const std::vector& args) { // clang-format off std::vector am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0", @@ -2151,27 +2256,27 @@ static void PrepareToWriteToFile() { ds.base_name_ += "-wifi"; } - if (ds.options_->do_fb) { - ds.screenshot_path_ = ds.GetPath(".png"); + if (ds.options_->do_screenshot) { + ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-png.tmp" : ".png"); } ds.tmp_path_ = ds.GetPath(".tmp"); ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt"); - std::string destination = ds.options_->bugreport_fd.get() != -1 + std::string destination = ds.CalledByApi() ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get()) : ds.bugreport_internal_dir_.c_str(); MYLOGD( - "Bugreport dir: %s\n" - "Base name: %s\n" - "Suffix: %s\n" - "Log path: %s\n" - "Temporary path: %s\n" - "Screenshot path: %s\n", + "Bugreport dir: [%s] " + "Base name: [%s] " + "Suffix: [%s] " + "Log path: [%s] " + "Temporary path: [%s] " + "Screenshot path: [%s]\n", destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str()); if (ds.options_->do_zip_file) { - ds.path_ = ds.GetPath(".zip"); + ds.path_ = ds.GetPath(ds.CalledByApi() ? "-zip.tmp" : ".zip"); MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str()); create_parent_dirs(ds.path_.c_str()); ds.zip_file.reset(fopen(ds.path_.c_str(), "wb")); @@ -2185,37 +2290,10 @@ static void PrepareToWriteToFile() { } /* - * Finalizes writing to the file by renaming or zipping the tmp file to the final location, + * Finalizes writing to the file by zipping the tmp file to the final location, * printing zipped file status, etc. */ static void FinalizeFile() { - /* check if user changed the suffix using system properties */ - std::string name = - android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), ""); - bool change_suffix = false; - if (!name.empty()) { - /* must whitelist which characters are allowed, otherwise it could cross directories */ - std::regex valid_regex("^[-_a-zA-Z0-9]+$"); - if (std::regex_match(name.c_str(), valid_regex)) { - change_suffix = true; - } else { - MYLOGE("invalid suffix provided by user: %s\n", name.c_str()); - } - } - if (change_suffix) { - MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str()); - ds.name_ = name; - if (!ds.screenshot_path_.empty()) { - std::string new_screenshot_path = ds.GetPath(".png"); - if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) { - MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(), - new_screenshot_path.c_str(), strerror(errno)); - } else { - ds.screenshot_path_ = new_screenshot_path; - } - } - } - bool do_text_file = true; if (ds.options_->do_zip_file) { if (!ds.FinishZipFile()) { @@ -2223,27 +2301,15 @@ static void FinalizeFile() { do_text_file = true; } else { do_text_file = false; - // If the user has changed the suffix, we need to change the zip file name. - std::string new_path = ds.GetPath(".zip"); - if (ds.path_ != new_path) { - MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str()); - if (rename(ds.path_.c_str(), new_path.c_str())) { - MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(), - strerror(errno)); - } else { - ds.path_ = new_path; - } - } } } - if (do_text_file) { - ds.path_ = ds.GetPath(".txt"); - MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str()); - if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) { - MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno)); - ds.path_.clear(); - } + + std::string final_path = ds.path_; + if (ds.options_->OutputToCustomFile()) { + final_path = ds.GetPath(ds.options_->out_dir, ".zip"); + android::os::CopyFileToFile(ds.path_, final_path); } + if (ds.options_->use_control_socket) { if (do_text_file) { dprintf(ds.control_socket_fd_, @@ -2251,55 +2317,12 @@ static void FinalizeFile() { "for more details\n", ds.log_path_.c_str()); } else { - dprintf(ds.control_socket_fd_, "OK:%s\n", ds.path_.c_str()); - } - } -} - -/* Broadcasts that we are done with the bugreport */ -static void SendBugreportFinishedBroadcast() { - // TODO(b/111441001): use callback instead of broadcast. - if (!ds.path_.empty()) { - MYLOGI("Final bugreport path: %s\n", ds.path_.c_str()); - // clang-format off - - std::vector am_args = { - "--receiver-permission", "android.permission.DUMP", - "--ei", "android.intent.extra.ID", std::to_string(ds.id_), - "--ei", "android.intent.extra.PID", std::to_string(ds.pid_), - "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()), - "--es", "android.intent.extra.BUGREPORT", ds.path_, - "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_ - }; - // clang-format on - if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) { - am_args.push_back("--es"); - am_args.push_back("android.intent.extra.SCREENSHOT"); - am_args.push_back(ds.screenshot_path_); - } - if (!ds.options_->notification_title.empty()) { - am_args.push_back("--es"); - am_args.push_back("android.intent.extra.TITLE"); - am_args.push_back(ds.options_->notification_title); - if (!ds.options_->notification_description.empty()) { - am_args.push_back("--es"); - am_args.push_back("android.intent.extra.DESCRIPTION"); - am_args.push_back(ds.options_->notification_description); - } - } - if (ds.options_->is_remote_mode) { - am_args.push_back("--es"); - am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH"); - am_args.push_back(SHA256_file_hash(ds.path_)); - SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args); - } else { - SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args); + dprintf(ds.control_socket_fd_, "OK:%s\n", final_path.c_str()); } - } else { - MYLOGE("Skipping finished broadcast because bugreport could not be generated\n"); } } + static inline const char* ModeToString(Dumpstate::BugreportMode mode) { switch (mode) { case Dumpstate::BugreportMode::BUGREPORT_FULL: @@ -2319,125 +2342,71 @@ static inline const char* ModeToString(Dumpstate::BugreportMode mode) { } } -static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) { - options->extra_options = ModeToString(mode); +static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options, + bool is_screenshot_requested) { + // Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for + // default system screenshots. + options->bugreport_mode = ModeToString(mode); switch (mode) { case Dumpstate::BugreportMode::BUGREPORT_FULL: - options->do_broadcast = true; - options->do_fb = true; + options->do_screenshot = is_screenshot_requested; + options->dumpstate_hal_mode = DumpstateMode::FULL; break; case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE: // Currently, the dumpstate binder is only used by Shell to update progress. options->do_start_service = true; options->do_progress_updates = true; - options->do_fb = false; - options->do_broadcast = true; + options->do_screenshot = is_screenshot_requested; + options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE; break; case Dumpstate::BugreportMode::BUGREPORT_REMOTE: options->do_vibrate = false; options->is_remote_mode = true; - options->do_fb = false; - options->do_broadcast = true; + options->do_screenshot = false; + options->dumpstate_hal_mode = DumpstateMode::REMOTE; break; case Dumpstate::BugreportMode::BUGREPORT_WEAR: options->do_start_service = true; options->do_progress_updates = true; options->do_zip_file = true; - options->do_fb = true; - options->do_broadcast = true; + options->do_screenshot = is_screenshot_requested; + options->dumpstate_hal_mode = DumpstateMode::WEAR; break; + // TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY. case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY: options->telephony_only = true; options->do_progress_updates = true; - options->do_fb = false; - options->do_broadcast = true; + options->do_screenshot = false; + options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY; break; case Dumpstate::BugreportMode::BUGREPORT_WIFI: options->wifi_only = true; options->do_zip_file = true; - options->do_fb = false; - options->do_broadcast = true; + options->do_screenshot = false; + options->dumpstate_hal_mode = DumpstateMode::WIFI; break; case Dumpstate::BugreportMode::BUGREPORT_DEFAULT: break; } } -static Dumpstate::BugreportMode getBugreportModeFromProperty() { - // If the system property is not set, it's assumed to be a default bugreport. - Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT; - - std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, ""); - if (!extra_options.empty()) { - // Framework uses a system property to override some command-line args. - // Currently, it contains the type of the requested bugreport. - if (extra_options == "bugreportplus") { - mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE; - } else if (extra_options == "bugreportfull") { - mode = Dumpstate::BugreportMode::BUGREPORT_FULL; - } else if (extra_options == "bugreportremote") { - mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE; - } else if (extra_options == "bugreportwear") { - mode = Dumpstate::BugreportMode::BUGREPORT_WEAR; - } else if (extra_options == "bugreporttelephony") { - mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY; - } else if (extra_options == "bugreportwifi") { - mode = Dumpstate::BugreportMode::BUGREPORT_WIFI; - } else { - MYLOGE("Unknown extra option: %s\n", extra_options.c_str()); - } - // Reset the property - android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, ""); - } - return mode; -} - -// TODO: Move away from system properties when we have options passed via binder calls. -/* Sets runtime options from the system properties and then clears those properties. */ -static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) { - Dumpstate::BugreportMode mode = getBugreportModeFromProperty(); - SetOptionsFromMode(mode, options); - - options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, ""); - if (!options->notification_title.empty()) { - // Reset the property - android::base::SetProperty(PROPERTY_EXTRA_TITLE, ""); - - options->notification_description = - android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, ""); - if (!options->notification_description.empty()) { - // Reset the property - android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, ""); - } - MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(), - options->notification_description.c_str()); - } -} - static void LogDumpOptions(const Dumpstate::DumpOptions& options) { - MYLOGI("do_zip_file: %d\n", options.do_zip_file); - MYLOGI("do_add_date: %d\n", options.do_add_date); - MYLOGI("do_vibrate: %d\n", options.do_vibrate); - MYLOGI("use_socket: %d\n", options.use_socket); - MYLOGI("use_control_socket: %d\n", options.use_control_socket); - MYLOGI("do_fb: %d\n", options.do_fb); - MYLOGI("do_broadcast: %d\n", options.do_broadcast); - MYLOGI("is_remote_mode: %d\n", options.is_remote_mode); - MYLOGI("show_header_only: %d\n", options.show_header_only); - MYLOGI("do_start_service: %d\n", options.do_start_service); - MYLOGI("telephony_only: %d\n", options.telephony_only); - MYLOGI("wifi_only: %d\n", options.wifi_only); - MYLOGI("do_progress_updates: %d\n", options.do_progress_updates); - MYLOGI("fd: %d\n", options.bugreport_fd.get()); - MYLOGI("extra_options: %s\n", options.extra_options.c_str()); - MYLOGI("args: %s\n", options.args.c_str()); - MYLOGI("notification_title: %s\n", options.notification_title.c_str()); - MYLOGI("notification_description: %s\n", options.notification_description.c_str()); + MYLOGI( + "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_screenshot: %d " + "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d " + "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s " + "limited_only: %d args: %s\n", + options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket, + options.do_screenshot, options.is_remote_mode, options.show_header_only, + options.do_start_service, options.telephony_only, options.wifi_only, + options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(), + toString(options.dumpstate_hal_mode).c_str(), options.limited_only, options.args.c_str()); } void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd_in, - const android::base::unique_fd& screenshot_fd_in) { + const android::base::unique_fd& screenshot_fd_in, + bool is_screenshot_requested) { // In the new API world, date is always added; output is always a zip file. // TODO(111441001): remove these options once they are obsolete. do_add_date = true; @@ -2447,29 +2416,26 @@ void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode, bugreport_fd.reset(dup(bugreport_fd_in.get())); screenshot_fd.reset(dup(screenshot_fd_in.get())); - extra_options = ModeToString(bugreport_mode); - SetOptionsFromMode(bugreport_mode, this); + SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested); } Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) { RunStatus status = RunStatus::OK; int c; - while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) { + while ((c = getopt(argc, argv, "dho:svqzpLPBRSV:w")) != -1) { switch (c) { // clang-format off case 'd': do_add_date = true; break; case 'z': do_zip_file = true; break; - // o=use_outfile not supported anymore. - // TODO(b/111441001): Remove when all callers have migrated. - case 'o': break; + case 'o': out_dir = optarg; break; case 's': use_socket = true; break; case 'S': use_control_socket = true; break; case 'v': show_header_only = true; break; case 'q': do_vibrate = false; break; - case 'p': do_fb = true; break; + case 'p': do_screenshot = true; break; case 'P': do_progress_updates = true; break; case 'R': is_remote_mode = true; break; - case 'B': do_broadcast = true; break; + case 'L': limited_only = true; break; case 'V': break; // compatibility no-op case 'w': // This was already processed @@ -2495,7 +2461,6 @@ Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) // Reset next index used by getopt so this can be called multiple times, for eg, in tests. optind = 1; - SetOptionsFromProperties(this); return status; } @@ -2504,7 +2469,7 @@ bool Dumpstate::DumpOptions::ValidateOptions() const { return false; } - if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) { + if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) { return false; } @@ -2512,11 +2477,7 @@ bool Dumpstate::DumpOptions::ValidateOptions() const { return false; } - if (do_progress_updates && !do_broadcast) { - return false; - } - - if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) { + if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) { return false; } return true; @@ -2526,6 +2487,13 @@ void Dumpstate::SetOptions(std::unique_ptr options) { options_ = std::move(options); } +void Dumpstate::Initialize() { + /* gets the sequential id */ + uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0); + id_ = ++last_id; + android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id)); +} + Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) { Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package); if (listener_ != nullptr) { @@ -2552,6 +2520,17 @@ Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& call return status; } +void Dumpstate::Cancel() { + CleanupTmpFiles(); + android::os::UnlinkAndLogOnError(log_path_); + for (int i = 0; i < NUM_OF_DUMPS; i++) { + android::os::UnlinkAndLogOnError(ds.bugreport_internal_dir_ + "/" + + kDumpstateBoardFiles[i]); + } + tombstone_data_.clear(); + anr_data_.clear(); +} + /* * Dumps relevant information to a bugreport based on the given options. * @@ -2570,8 +2549,8 @@ Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& call * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also * gets added to the archive. * - * Bugreports are first generated in a local directory and later copied to the caller's fd if - * supplied. + * Bugreports are first generated in a local directory and later copied to the caller's fd + * or directory if supplied. */ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, const std::string& calling_package) { @@ -2612,11 +2591,8 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, return RunStatus::OK; } - if (options_->bugreport_fd.get() != -1) { - // If the output needs to be copied over to the caller's fd, get user consent. - android::String16 package(calling_package.c_str()); - CheckUserConsent(calling_uid, package); - } + MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n", + calling_uid, calling_package.c_str()); // Redirect output if needed bool is_redirecting = options_->OutputToFile(); @@ -2628,13 +2604,6 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, : ""; progress_.reset(new Progress(stats_path)); - /* gets the sequential id */ - uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0); - id_ = ++last_id; - android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id)); - - MYLOGI("begin\n"); - if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) { MYLOGE("Failed to acquire wake lock: %s\n", strerror(errno)); } else { @@ -2657,10 +2626,8 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n"); } - MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(), - options_->extra_options.c_str()); - - MYLOGI("bugreport format version: %s\n", version_.c_str()); + MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n", + id_, options_->args.c_str(), options_->bugreport_mode.c_str(), version_.c_str()); do_early_screenshot_ = options_->do_progress_updates; @@ -2685,18 +2652,13 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, PrepareToWriteToFile(); if (options_->do_progress_updates) { - if (options_->do_broadcast) { - // clang-format off - std::vector am_args = { - "--receiver-permission", "android.permission.DUMP", - "--es", "android.intent.extra.NAME", name_, - "--ei", "android.intent.extra.ID", std::to_string(id_), - "--ei", "android.intent.extra.PID", std::to_string(pid_), - "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()), - }; - // clang-format on - SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args); - } + // clang-format off + std::vector am_args = { + "--receiver-permission", "android.permission.DUMP", + }; + // clang-format on + // Send STARTED broadcast for apps that listen to bugreport generation events + SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args); if (options_->use_control_socket) { dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str()); } @@ -2714,11 +2676,6 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, Vibrate(150); } - if (options_->do_fb && do_early_screenshot_) { - MYLOGI("taking early screenshot\n"); - TakeScreenshot(); - } - if (options_->do_zip_file && zip_file != nullptr) { if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(), @@ -2763,14 +2720,34 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, // duration is logged into MYLOG instead. PrintHeader(); + // TODO(b/158737089) reduce code repetition in if branches if (options_->telephony_only) { - DumpstateTelephonyOnly(); + MaybeTakeEarlyScreenshot(); + onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); + MaybeCheckUserConsent(calling_uid, calling_package); + DumpstateTelephonyOnly(calling_package); DumpstateBoard(); } else if (options_->wifi_only) { + MaybeTakeEarlyScreenshot(); + onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); + MaybeCheckUserConsent(calling_uid, calling_package); DumpstateWifiOnly(); + } else if (options_->limited_only) { + MaybeTakeEarlyScreenshot(); + onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); + MaybeCheckUserConsent(calling_uid, calling_package); + DumpstateLimitedOnly(); } else { + // Invoke critical dumpsys first to preserve system state, before doing anything else. + RunDumpsysCritical(); + + // Take screenshot and get consent only after critical dumpsys has finished. + MaybeTakeEarlyScreenshot(); + onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package); + MaybeCheckUserConsent(calling_uid, calling_package); + // Dump state for the default case. This also drops root. - RunStatus s = DumpstateDefault(); + RunStatus s = DumpstateDefaultAfterCritical(); if (s != RunStatus::OK) { if (s == RunStatus::USER_CONSENT_DENIED) { HandleUserConsentDenied(); @@ -2784,15 +2761,15 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout))); } - // Rename, and/or zip the (now complete) .tmp file within the internal directory. + // Zip the (now complete) .tmp file within the internal directory. if (options_->OutputToFile()) { FinalizeFile(); } - // Share the final file with the caller if the user has consented. + // Share the final file with the caller if the user has consented or Shell is the caller. Dumpstate::RunStatus status = Dumpstate::RunStatus::OK; - if (options_->bugreport_fd.get() != -1) { - status = CopyBugreportIfUserConsented(); + if (CalledByApi()) { + status = CopyBugreportIfUserConsented(calling_uid); if (status != Dumpstate::RunStatus::OK && status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) { // Do an early return if there were errors. We make an exception for consent @@ -2801,13 +2778,6 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI("User denied consent. Returning\n"); return status; } - if (options_->do_fb && options_->screenshot_fd.get() != -1) { - bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_, - options_->screenshot_fd.get()); - if (copy_succeeded) { - android::os::UnlinkAndLogOnError(screenshot_path_); - } - } if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) { MYLOGI( "Did not receive user consent yet." @@ -2832,12 +2802,6 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, } } - /* tell activity manager we're done */ - if (options_->do_broadcast) { - SendBugreportFinishedBroadcast(); - // Note that listener_ is notified in Run(); - } - MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(), progress_->GetInitialMax()); progress_->Save(); @@ -2861,14 +2825,41 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, : RunStatus::OK; } -void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) { +void Dumpstate::MaybeTakeEarlyScreenshot() { + if (!options_->do_screenshot || !do_early_screenshot_) { + return; + } + + TakeScreenshot(); +} + +void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid, + const std::string& calling_package) { + if (calling_uid == AID_SHELL || !CalledByApi()) { + return; + } + if (listener_ != nullptr) { + // Let listener know ui intensive bugreport dumps are finished, then it can do event + // handling if required. + android::String16 package(calling_package.c_str()); + listener_->onUiIntensiveBugreportDumpsFinished(package); + } +} + +void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) { + if (calling_uid == AID_SHELL || !CalledByApi()) { + // No need to get consent for shell triggered dumpstates, or not through + // bugreporting API (i.e. no fd to copy back). + return; + } consent_callback_ = new ConsentCallback(); const String16 incidentcompanion("incidentcompanion"); sp ics(defaultServiceManager()->getService(incidentcompanion)); + android::String16 package(calling_package.c_str()); if (ics != nullptr) { MYLOGD("Checking user consent via incidentcompanion service\n"); android::interface_cast(ics)->authorizeReport( - calling_uid, calling_package, String16(), String16(), + calling_uid, package, String16(), String16(), 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get()); } else { MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n"); @@ -2880,7 +2871,11 @@ bool Dumpstate::IsUserConsentDenied() const { ds.consent_callback_->getResult() == UserConsentResult::DENIED; } -void Dumpstate::CleanupFiles() { +bool Dumpstate::CalledByApi() const { + return ds.options_->bugreport_fd.get() != -1 ? true : false; +} + +void Dumpstate::CleanupTmpFiles() { android::os::UnlinkAndLogOnError(tmp_path_); android::os::UnlinkAndLogOnError(screenshot_path_); android::os::UnlinkAndLogOnError(path_); @@ -2888,14 +2883,19 @@ void Dumpstate::CleanupFiles() { Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() { MYLOGD("User denied consent; deleting files and returning\n"); - CleanupFiles(); + CleanupTmpFiles(); return USER_CONSENT_DENIED; } -Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() { +Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented(int32_t calling_uid) { // If the caller has asked to copy the bugreport over to their directory, we need explicit - // user consent. - UserConsentResult consent_result = consent_callback_->getResult(); + // user consent (unless the caller is Shell). + UserConsentResult consent_result; + if (calling_uid == AID_SHELL) { + consent_result = UserConsentResult::APPROVED; + } else { + consent_result = consent_callback_->getResult(); + } if (consent_result == UserConsentResult::UNAVAILABLE) { // User has not responded yet. uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs(); @@ -2920,6 +2920,16 @@ Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() { bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get()); if (copy_succeeded) { android::os::UnlinkAndLogOnError(path_); + if (options_->do_screenshot && + options_->screenshot_fd.get() != -1 && + !options_->is_screenshot_copied) { + copy_succeeded = android::os::CopyFileToFd(screenshot_path_, + options_->screenshot_fd.get()); + options_->is_screenshot_copied = copy_succeeded; + if (copy_succeeded) { + android::os::UnlinkAndLogOnError(screenshot_path_); + } + } } return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR; } else if (consent_result == UserConsentResult::UNAVAILABLE) { @@ -2944,8 +2954,9 @@ Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) { assert(options_->bugreport_fd.get() == -1); // calling_uid and calling_package are for user consent to share the bugreport with - // an app; they are irrelvant here because bugreport is only written to a local - // directory, and not shared. + // an app; they are irrelevant here because bugreport is triggered via command line. + // Update Last ID before calling Run(). + Initialize(); status = Run(-1 /* calling_uid */, "" /* calling_package */); } return status; @@ -3759,15 +3770,13 @@ void Dumpstate::UpdateProgress(int32_t delta_sec) { } if (listener_ != nullptr) { - if (percent % 5 == 0) { - // We don't want to spam logcat, so only log multiples of 5. - MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max, - percent); + if (percent % 10 == 0) { + // We don't want to spam logcat, so only log multiples of 10. + MYLOGD("Setting progress: %d/%d (%d%%)\n", progress, max, percent); } else { // stderr is ignored on normal invocations, but useful when calling // /system/bin/dumpstate directly for debuggging. - fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), - progress, max, percent); + fprintf(stderr, "Setting progress: %d/%d (%d%%)\n", progress, max, percent); } listener_->onProgress(percent); @@ -3784,6 +3793,11 @@ void Dumpstate::TakeScreenshot(const std::string& path) { } else { MYLOGE("Failed to take screenshot on %s\n", real_path.c_str()); } + if (listener_ != nullptr) { + // Show a visual indication to indicate screenshot is taken via + // IDumpstateListener.onScreenshotTaken() + listener_->onScreenshotTaken(status == 0); + } } bool is_dir(const char* pathname) { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 82bf8219a2fbeb91891a33d900d215ffe0f4a29c..0d25d307a64774e7b39d8914e14720e3c34a0239 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -215,6 +216,9 @@ class Dumpstate { /* Checkes whether dumpstate is generating a zipped bugreport. */ bool IsZipping() const; + /* Initialize dumpstate fields before starting bugreport generation */ + void Initialize(); + /* * Forks a command, waits for it to finish, and returns its status. * @@ -328,11 +332,19 @@ class Dumpstate { struct DumpOptions; - /* Main entry point for running a complete bugreport. */ + /* + * Main entry point for running a complete bugreport. + * + * Initialize() dumpstate before calling this method. + * + */ RunStatus Run(int32_t calling_uid, const std::string& calling_package); RunStatus ParseCommandlineAndRun(int argc, char* argv[]); + /* Deletes in-progress files */ + void Cancel(); + /* Sets runtime options. */ void SetOptions(std::unique_ptr options); @@ -343,6 +355,11 @@ class Dumpstate { */ bool IsUserConsentDenied() const; + /* + * Returns true if dumpstate is called by bugreporting API + */ + bool CalledByApi() const; + /* * Structure to hold options that determine the behavior of dumpstate. */ @@ -353,34 +370,43 @@ class Dumpstate { // Writes bugreport content to a socket; only flatfile format is supported. bool use_socket = false; bool use_control_socket = false; - bool do_fb = false; - bool do_broadcast = false; + bool do_screenshot = false; + bool is_screenshot_copied = false; bool is_remote_mode = false; bool show_header_only = false; bool do_start_service = false; bool telephony_only = false; bool wifi_only = false; + // Trimmed-down version of dumpstate to only include whitelisted logs. + bool limited_only = false; // Whether progress updates should be published. bool do_progress_updates = false; - // File descriptor to output zip file. + // The mode we'll use when calling IDumpstateDevice::dumpstateBoard. + // TODO(b/148168577) get rid of the AIDL values, replace them with the HAL values instead. + // The HAL is actually an API surface that can be validated, while the AIDL is not (@hide). + ::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode = + ::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT; + // File descriptor to output zip file. Takes precedence over out_dir. android::base::unique_fd bugreport_fd; // File descriptor to screenshot file. android::base::unique_fd screenshot_fd; - // TODO: rename to MODE. - // Extra options passed as system property. - std::string extra_options; + // Custom output directory. + std::string out_dir; + // Bugreport mode of the bugreport. + std::string bugreport_mode; // Command-line arguments as string std::string args; // Notification title and description std::string notification_title; std::string notification_description; - /* Initializes options from commandline arguments and system properties. */ + /* Initializes options from commandline arguments. */ RunStatus Initialize(int argc, char* argv[]); /* Initializes options from the requested mode. */ void Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd, - const android::base::unique_fd& screenshot_fd); + const android::base::unique_fd& screenshot_fd, + bool is_screenshot_requested); /* Returns true if the options set so far are consistent. */ bool ValidateOptions() const; @@ -391,6 +417,12 @@ class Dumpstate { // specified, it is preferred. If not bugreport is written to /bugreports. return !use_socket; } + + /* Returns if options specified require writing to custom file location */ + bool OutputToCustomFile() { + // Custom location is only honored in limited mode. + return limited_only && !out_dir.empty() && bugreport_fd.get() == -1; + } }; // TODO: initialize fields on constructor @@ -451,8 +483,6 @@ class Dumpstate { // Binder object listening to progress. android::sp listener_; - std::string listener_name_; - bool report_section_; // List of open tombstone dump files. std::vector tombstone_data_; @@ -485,16 +515,24 @@ class Dumpstate { private: RunStatus RunInternal(int32_t calling_uid, const std::string& calling_package); - void CheckUserConsent(int32_t calling_uid, const android::String16& calling_package); + RunStatus DumpstateDefaultAfterCritical(); + + void MaybeTakeEarlyScreenshot(); + + void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid, + const std::string& calling_package); + + void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package); // Removes the in progress files output files (tmp file, zip/txt file, screenshot), // but leaves the log file alone. - void CleanupFiles(); + void CleanupTmpFiles(); RunStatus HandleUserConsentDenied(); - // Copies bugreport artifacts over to the caller's directories provided there is user consent. - RunStatus CopyBugreportIfUserConsented(); + // Copies bugreport artifacts over to the caller's directories provided there is user consent or + // called by Shell. + RunStatus CopyBugreportIfUserConsented(int32_t calling_uid); // Used by GetInstance() only. explicit Dumpstate(const std::string& version = VERSION_CURRENT); diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc index 14937b80b96ab176559d373c1b9d268d965d2f79..e491a4b61418adf8cd2079d6634c1922bf20a128 100644 --- a/cmds/dumpstate/dumpstate.rc +++ b/cmds/dumpstate/dumpstate.rc @@ -11,8 +11,7 @@ service dumpstate /system/bin/dumpstate -s # dumpstatez generates a zipped bugreport but also uses a socket to print the file location once # it is finished. -service dumpstatez /system/bin/dumpstate -S -d -z \ - -o /data/user_de/0/com.android.shell/files/bugreports/bugreport +service dumpstatez /system/bin/dumpstate -S -d -z socket dumpstate stream 0660 shell log class main disabled diff --git a/cmds/dumpstate/main.cpp b/cmds/dumpstate/main.cpp index 68d373377cd7a8e80934138fe42a3a51a501e80e..ec89c0dd6e07918280a718826b7b45563ab3bd1a 100644 --- a/cmds/dumpstate/main.cpp +++ b/cmds/dumpstate/main.cpp @@ -30,7 +30,7 @@ bool ShouldStartServiceAndWait(int argc, char* argv[]) { bool do_wait = false; int c; // Keep flags in sync with Dumpstate::DumpOptions::Initialize. - while ((c = getopt(argc, argv, "wdho:svqzpPBRSV:")) != -1 && !do_wait) { + while ((c = getopt(argc, argv, "dho:svqzpLPBRSV:w")) != -1 && !do_wait) { switch (c) { case 'w': do_wait = true; diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index 256dc055e1da5deaef2b1b10d54d8f319ed8cc50..6f2d75403d890c83ef273d70d9db66b2f636a12c 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -167,6 +167,21 @@ class DumpstateListener : public BnDumpstateListener { return binder::Status::ok(); } + binder::Status onScreenshotTaken(bool success) override { + std::lock_guard lock(lock_); + dprintf(out_fd_, "\rResult of taking screenshot: %s", success ? "success" : "failure"); + return binder::Status::ok(); + } + + binder::Status onUiIntensiveBugreportDumpsFinished(const android::String16& callingpackage) + override { + std::lock_guard lock(lock_); + std::string callingpackageUtf8 = std::string(String8(callingpackage).string()); + dprintf(out_fd_, "\rCalling package of ui intensive bugreport dumps finished: %s", + callingpackageUtf8.c_str()); + return binder::Status::ok(); + } + bool getIsFinished() { std::lock_guard lock(lock_); return is_finished_; @@ -195,21 +210,16 @@ class ZippedBugreportGenerationTest : public Test { static Dumpstate& ds; static std::chrono::milliseconds duration; static void SetUpTestCase() { - property_set("dumpstate.options", "bugreportplus"); // clang-format off char* argv[] = { (char*)"dumpstate", (char*)"-d", (char*)"-z", - (char*)"-B", - (char*)"-o", - (char*)dirname(android::base::GetExecutablePath().c_str()) + (char*)"-B" }; // clang-format on sp listener(new DumpstateListener(dup(fileno(stdout)), sections)); ds.listener_ = listener; - ds.listener_name_ = "Smokey"; - ds.report_section_ = true; auto start = std::chrono::steady_clock::now(); ds.ParseCommandlineAndRun(ARRAY_SIZE(argv), argv); auto end = std::chrono::steady_clock::now(); @@ -450,7 +460,7 @@ TEST_F(DumpstateBinderTest, Baseline) { sp listener(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener, true); // startBugreport is an async call. Verify binder call succeeded first, then wait till listener // gets expected callbacks. EXPECT_TRUE(status.isOk()); @@ -487,7 +497,7 @@ TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) { android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), 2000, // invalid bugreport mode - listener); + listener, false); EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); // The service should have died, freeing itself up for a new invocation. @@ -518,13 +528,13 @@ TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) { sp listener1(new DumpstateListener(dup(fileno(stdout)))); android::binder::Status status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1, true); EXPECT_TRUE(status.isOk()); // try to make another call to startBugreport. This should fail. sp listener2(new DumpstateListener(dup(fileno(stdout)))); status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd2), std::move(screenshot_fd2), - Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2); + Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2, true); EXPECT_FALSE(status.isOk()); WaitTillExecutionComplete(listener2.get()); EXPECT_EQ(listener2->getErrorCode(), diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 99d482f034714f084d6e04061ee4d512e4aad5ff..c7df1bb6a34363a257cfff888622373752f5cfe7 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -36,19 +36,22 @@ #include #include #include +#include +#include #include namespace android { namespace os { namespace dumpstate { +using ::android::hardware::dumpstate::V1_1::DumpstateMode; using ::testing::EndsWith; using ::testing::HasSubstr; -using ::testing::IsNull; using ::testing::IsEmpty; +using ::testing::IsNull; using ::testing::NotNull; -using ::testing::StrEq; using ::testing::StartsWith; +using ::testing::StrEq; using ::testing::Test; using ::testing::internal::CaptureStderr; using ::testing::internal::CaptureStdout; @@ -62,6 +65,9 @@ class DumpstateListenerMock : public IDumpstateListener { MOCK_METHOD1(onProgress, binder::Status(int32_t progress)); MOCK_METHOD1(onError, binder::Status(int32_t error_code)); MOCK_METHOD0(onFinished, binder::Status()); + MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success)); + MOCK_METHOD1(onUiIntensiveBugreportDumpsFinished, + binder::Status(const android::String16& callingpackage)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); @@ -148,10 +154,9 @@ class DumpOptionsTest : public Test { options_ = Dumpstate::DumpOptions(); } void TearDown() { - // Reset the property - property_set("dumpstate.options", ""); } Dumpstate::DumpOptions options_; + android::base::unique_fd fd; }; TEST_F(DumpOptionsTest, InitializeNone) { @@ -167,14 +172,16 @@ TEST_F(DumpOptionsTest, InitializeNone) { EXPECT_FALSE(options_.do_add_date); EXPECT_FALSE(options_.do_zip_file); + EXPECT_EQ("", options_.out_dir); EXPECT_FALSE(options_.use_socket); EXPECT_FALSE(options_.use_control_socket); EXPECT_FALSE(options_.show_header_only); EXPECT_TRUE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); - EXPECT_FALSE(options_.do_broadcast); + EXPECT_FALSE(options_.limited_only); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeAdbBugreport) { @@ -197,11 +204,12 @@ TEST_F(DumpOptionsTest, InitializeAdbBugreport) { // Other options retain default values EXPECT_TRUE(options_.do_vibrate); EXPECT_FALSE(options_.show_header_only); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); - EXPECT_FALSE(options_.do_broadcast); EXPECT_FALSE(options_.use_socket); + EXPECT_FALSE(options_.limited_only); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { @@ -223,31 +231,19 @@ TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) { EXPECT_FALSE(options_.do_zip_file); EXPECT_FALSE(options_.use_control_socket); EXPECT_FALSE(options_.show_header_only); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); - EXPECT_FALSE(options_.do_broadcast); + EXPECT_FALSE(options_.limited_only); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeFullBugReport) { - // clang-format off - char* argv[] = { - const_cast("bugreport"), - const_cast("-d"), - const_cast("-p"), - const_cast("-B"), - const_cast("-z"), - }; - // clang-format on - property_set("dumpstate.options", "bugreportfull"); - - Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); - - EXPECT_EQ(status, Dumpstate::RunStatus::OK); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); - EXPECT_TRUE(options_.do_broadcast); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -257,30 +253,17 @@ TEST_F(DumpOptionsTest, InitializeFullBugReport) { EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); EXPECT_FALSE(options_.do_start_service); + EXPECT_FALSE(options_.limited_only); } TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { - // clang-format off - char* argv[] = { - const_cast("bugreport"), - const_cast("-d"), - const_cast("-p"), - const_cast("-B"), - const_cast("-z"), - }; - // clang-format on - - property_set("dumpstate.options", "bugreportplus"); - - Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); - - EXPECT_EQ(status, Dumpstate::RunStatus::OK); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_broadcast); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.do_start_service); - EXPECT_FALSE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -288,60 +271,34 @@ TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) { EXPECT_FALSE(options_.show_header_only); EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); + EXPECT_FALSE(options_.limited_only); } TEST_F(DumpOptionsTest, InitializeRemoteBugReport) { - // clang-format off - char* argv[] = { - const_cast("bugreport"), - const_cast("-d"), - const_cast("-p"), - const_cast("-B"), - const_cast("-z"), - }; - // clang-format on - - property_set("dumpstate.options", "bugreportremote"); - - Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); - - EXPECT_EQ(status, Dumpstate::RunStatus::OK); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd, false); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_broadcast); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.is_remote_mode); EXPECT_FALSE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE); // Other options retain default values EXPECT_FALSE(options_.use_control_socket); EXPECT_FALSE(options_.show_header_only); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.use_socket); + EXPECT_FALSE(options_.limited_only); } TEST_F(DumpOptionsTest, InitializeWearBugReport) { - // clang-format off - char* argv[] = { - const_cast("bugreport"), - const_cast("-d"), - const_cast("-p"), - const_cast("-B"), - const_cast("-z"), - }; - // clang-format on - - property_set("dumpstate.options", "bugreportwear"); - - Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); - - EXPECT_EQ(status, Dumpstate::RunStatus::OK); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); - EXPECT_TRUE(options_.do_broadcast); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.do_start_service); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -349,30 +306,17 @@ TEST_F(DumpOptionsTest, InitializeWearBugReport) { EXPECT_FALSE(options_.show_header_only); EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); + EXPECT_FALSE(options_.limited_only); } TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { - // clang-format off - char* argv[] = { - const_cast("bugreport"), - const_cast("-d"), - const_cast("-p"), - const_cast("-B"), - const_cast("-z"), - }; - // clang-format on - - property_set("dumpstate.options", "bugreporttelephony"); - - Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); - - EXPECT_EQ(status, Dumpstate::RunStatus::OK); + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd, false); EXPECT_TRUE(options_.do_add_date); - EXPECT_FALSE(options_.do_fb); - EXPECT_TRUE(options_.do_broadcast); + EXPECT_FALSE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); EXPECT_TRUE(options_.telephony_only); EXPECT_TRUE(options_.do_progress_updates); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -380,37 +324,57 @@ TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) { EXPECT_FALSE(options_.show_header_only); EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); + EXPECT_FALSE(options_.limited_only); } TEST_F(DumpOptionsTest, InitializeWifiBugReport) { + options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false); + EXPECT_TRUE(options_.do_add_date); + EXPECT_FALSE(options_.do_screenshot); + EXPECT_TRUE(options_.do_zip_file); + EXPECT_TRUE(options_.wifi_only); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI); + + // Other options retain default values + EXPECT_TRUE(options_.do_vibrate); + EXPECT_FALSE(options_.use_control_socket); + EXPECT_FALSE(options_.show_header_only); + EXPECT_FALSE(options_.do_progress_updates); + EXPECT_FALSE(options_.is_remote_mode); + EXPECT_FALSE(options_.use_socket); + EXPECT_FALSE(options_.limited_only); +} + +TEST_F(DumpOptionsTest, InitializeLimitedOnlyBugreport) { // clang-format off char* argv[] = { - const_cast("bugreport"), + const_cast("dumpstatez"), + const_cast("-S"), const_cast("-d"), - const_cast("-p"), - const_cast("-B"), const_cast("-z"), + const_cast("-q"), + const_cast("-L"), + const_cast("-o abc") }; // clang-format on - property_set("dumpstate.options", "bugreportwifi"); - Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); EXPECT_EQ(status, Dumpstate::RunStatus::OK); EXPECT_TRUE(options_.do_add_date); - EXPECT_FALSE(options_.do_fb); - EXPECT_TRUE(options_.do_broadcast); EXPECT_TRUE(options_.do_zip_file); - EXPECT_TRUE(options_.wifi_only); + EXPECT_TRUE(options_.use_control_socket); + EXPECT_FALSE(options_.do_vibrate); + EXPECT_TRUE(options_.limited_only); + EXPECT_EQ(" abc", std::string(options_.out_dir)); // Other options retain default values - EXPECT_TRUE(options_.do_vibrate); - EXPECT_FALSE(options_.use_control_socket); EXPECT_FALSE(options_.show_header_only); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeDefaultBugReport) { @@ -420,20 +384,16 @@ TEST_F(DumpOptionsTest, InitializeDefaultBugReport) { const_cast("bugreport"), const_cast("-d"), const_cast("-p"), - const_cast("-B"), const_cast("-z"), }; // clang-format on - - property_set("dumpstate.options", ""); - Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); EXPECT_EQ(status, Dumpstate::RunStatus::OK); EXPECT_TRUE(options_.do_add_date); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_zip_file); - EXPECT_TRUE(options_.do_broadcast); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); // Other options retain default values EXPECT_TRUE(options_.do_vibrate); @@ -443,6 +403,7 @@ TEST_F(DumpOptionsTest, InitializeDefaultBugReport) { EXPECT_FALSE(options_.is_remote_mode); EXPECT_FALSE(options_.use_socket); EXPECT_FALSE(options_.wifi_only); + EXPECT_FALSE(options_.limited_only); } TEST_F(DumpOptionsTest, InitializePartial1) { @@ -469,10 +430,11 @@ TEST_F(DumpOptionsTest, InitializePartial1) { // Other options retain default values EXPECT_FALSE(options_.show_header_only); EXPECT_TRUE(options_.do_vibrate); - EXPECT_FALSE(options_.do_fb); + EXPECT_FALSE(options_.do_screenshot); EXPECT_FALSE(options_.do_progress_updates); EXPECT_FALSE(options_.is_remote_mode); - EXPECT_FALSE(options_.do_broadcast); + EXPECT_FALSE(options_.limited_only); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializePartial2) { @@ -484,7 +446,6 @@ TEST_F(DumpOptionsTest, InitializePartial2) { const_cast("-p"), const_cast("-P"), const_cast("-R"), - const_cast("-B"), }; // clang-format on @@ -493,16 +454,17 @@ TEST_F(DumpOptionsTest, InitializePartial2) { EXPECT_EQ(status, Dumpstate::RunStatus::OK); EXPECT_TRUE(options_.show_header_only); EXPECT_FALSE(options_.do_vibrate); - EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_screenshot); EXPECT_TRUE(options_.do_progress_updates); EXPECT_TRUE(options_.is_remote_mode); - EXPECT_TRUE(options_.do_broadcast); // Other options retain default values EXPECT_FALSE(options_.do_add_date); EXPECT_FALSE(options_.do_zip_file); EXPECT_FALSE(options_.use_socket); EXPECT_FALSE(options_.use_control_socket); + EXPECT_FALSE(options_.limited_only); + EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT); } TEST_F(DumpOptionsTest, InitializeHelp) { @@ -544,7 +506,7 @@ TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) { } TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) { - options_.do_broadcast = true; + options_.do_progress_updates = true; // Writing to socket = !writing to file. options_.use_socket = true; EXPECT_FALSE(options_.ValidateOptions()); @@ -561,19 +523,10 @@ TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) { EXPECT_TRUE(options_.ValidateOptions()); } -TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) { - options_.do_progress_updates = true; - EXPECT_FALSE(options_.ValidateOptions()); - - options_.do_broadcast = true; - EXPECT_TRUE(options_.ValidateOptions()); -} - TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) { options_.is_remote_mode = true; EXPECT_FALSE(options_.ValidateOptions()); - options_.do_broadcast = true; options_.do_zip_file = true; options_.do_add_date = true; EXPECT_TRUE(options_.ValidateOptions()); @@ -616,8 +569,8 @@ class DumpstateTest : public DumpstateBaseTest { ds.progress_.reset(new Progress(initial_max, progress, 1.2)); } - std::string GetProgressMessage(const std::string& listener_name, int progress, int max, - int old_max = 0, bool update_progress = true) { + std::string GetProgressMessage(int progress, int max, + int old_max = 0, bool update_progress = true) { EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress"; EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max"; @@ -630,9 +583,8 @@ class DumpstateTest : public DumpstateBaseTest { } if (update_progress) { - message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n", - listener_name.c_str(), progress, max, - (100 * progress / max)); + message += android::base::StringPrintf("Setting progress: %d/%d (%d%%)\n", + progress, max, (100 * progress / max)); } return message; @@ -787,18 +739,17 @@ TEST_F(DumpstateTest, RunCommandIsKilled) { TEST_F(DumpstateTest, RunCommandProgress) { sp listener(new DumpstateListenerMock()); ds.listener_ = listener; - ds.listener_name_ = "FoxMulder"; SetProgress(0, 30); EXPECT_CALL(*listener, onProgress(66)); // 20/30 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build())); - std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30); + std::string progress_message = GetProgressMessage(20, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); EXPECT_CALL(*listener, onProgress(80)); // 24/30 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 24, 30); + progress_message = GetProgressMessage(24, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); @@ -806,20 +757,20 @@ TEST_F(DumpstateTest, RunCommandProgress) { SetDryRun(true); EXPECT_CALL(*listener, onProgress(90)); // 27/30 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 27, 30); + progress_message = GetProgressMessage(27, 30); EXPECT_THAT(out, IsEmpty()); EXPECT_THAT(err, StrEq(progress_message)); SetDryRun(false); EXPECT_CALL(*listener, onProgress(96)); // 29/30 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 29, 30); + progress_message = GetProgressMessage(29, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); EXPECT_CALL(*listener, onProgress(100)); // 30/30 % EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build())); - progress_message = GetProgressMessage(ds.listener_name_, 30, 30); + progress_message = GetProgressMessage(30, 30); EXPECT_THAT(out, StrEq("stdout\n")); EXPECT_THAT(err, StrEq("stderr\n" + progress_message)); @@ -1044,14 +995,12 @@ TEST_F(DumpstateTest, DumpFileOnDryRun) { TEST_F(DumpstateTest, DumpFileUpdateProgress) { sp listener(new DumpstateListenerMock()); ds.listener_ = listener; - ds.listener_name_ = "FoxMulder"; SetProgress(0, 30); EXPECT_CALL(*listener, onProgress(16)); // 5/30 % EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt")); - std::string progress_message = - GetProgressMessage(ds.listener_name_, 5, 30); // TODO: unhardcode WEIGHT_FILE (5)? + std::string progress_message = GetProgressMessage(5, 30); // TODO: unhardcode WEIGHT_FILE (5)? EXPECT_THAT(err, StrEq(progress_message)); EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline @@ -1063,48 +1012,6 @@ class DumpstateServiceTest : public DumpstateBaseTest { DumpstateService dss; }; -TEST_F(DumpstateServiceTest, SetListenerNoName) { - sp listener(new DumpstateListenerMock()); - sp token; - EXPECT_TRUE(dss.setListener("", listener, /* getSectionDetails = */ false, &token).isOk()); - ASSERT_THAT(token, IsNull()); -} - -TEST_F(DumpstateServiceTest, SetListenerNoPointer) { - sp token; - EXPECT_TRUE( - dss.setListener("whatever", nullptr, /* getSectionDetails = */ false, &token).isOk()); - ASSERT_THAT(token, IsNull()); -} - -TEST_F(DumpstateServiceTest, SetListenerTwice) { - sp listener(new DumpstateListenerMock()); - sp token; - EXPECT_TRUE( - dss.setListener("whatever", listener, /* getSectionDetails = */ false, &token).isOk()); - ASSERT_THAT(token, NotNull()); - EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever")); - EXPECT_FALSE(Dumpstate::GetInstance().report_section_); - - token.clear(); - EXPECT_TRUE( - dss.setListener("whatsoever", listener, /* getSectionDetails = */ false, &token).isOk()); - ASSERT_THAT(token, IsNull()); - EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever")); - EXPECT_FALSE(Dumpstate::GetInstance().report_section_); -} - -TEST_F(DumpstateServiceTest, SetListenerWithSectionDetails) { - sp listener(new DumpstateListenerMock()); - sp token; - Dumpstate::GetInstance().listener_ = nullptr; - EXPECT_TRUE( - dss.setListener("whatever", listener, /* getSectionDetails = */ true, &token).isOk()); - ASSERT_THAT(token, NotNull()); - EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever")); - EXPECT_TRUE(Dumpstate::GetInstance().report_section_); -} - class ProgressTest : public DumpstateBaseTest { public: Progress GetInstance(int32_t max, double growth_factor, const std::string& path = "") { diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index d398559ee8523efaec1d14f486e0744431fe7c3d..3a3df08534c0efeaaaa43a5734fbdef6edbc3b5d 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -14,15 +14,14 @@ * limitations under the License. */ +#include "GLHelper.h" + #include #include - -#include #include +#include -#include "GLHelper.h" - - namespace android { +namespace android { GLHelper::GLHelper() : mDisplay(EGL_NO_DISPLAY), @@ -228,15 +227,15 @@ bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) { return false; } - DisplayInfo info; - status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info); + DisplayConfig config; + status_t err = mSurfaceComposerClient->getActiveDisplayConfig(dpy, &config); if (err != NO_ERROR) { - fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err); + fprintf(stderr, "SurfaceComposer::getActiveDisplayConfig failed: %#x\n", err); return false; } - float scaleX = float(info.w) / float(w); - float scaleY = float(info.h) / float(h); + float scaleX = static_cast(config.resolution.getWidth()) / w; + float scaleY = static_cast(config.resolution.getHeight()) / h; *scale = scaleX < scaleY ? scaleX : scaleY; return true; diff --git a/cmds/installd/.gitignore b/cmds/installd/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..abc921ce6401d41f6798307d154ec168fa0e75af --- /dev/null +++ b/cmds/installd/.gitignore @@ -0,0 +1,2 @@ +# ignore the files generated by intellij +.idea diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index 2754571b0872a186f14305de069cf918827db421..523115f476853307bb29927d7524fafd885758c6 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -13,6 +13,7 @@ cc_defaults { srcs: [ "CacheItem.cpp", "CacheTracker.cpp", + "CrateManager.cpp", "InstalldNativeService.cpp", "QuotaUtils.cpp", "dexopt.cpp", @@ -185,6 +186,7 @@ filegroup { name: "installd_aidl", srcs: [ "binder/android/os/IInstalld.aidl", + "binder/android/os/storage/CrateMetadata.aidl", ], path: "binder", } diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b17cba15d5e39dc7fe72725de90c95a8686966c1 --- /dev/null +++ b/cmds/installd/CrateManager.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CrateManager.h" + +#ifdef ENABLE_STORAGE_CRATES + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "utils.h" + +using android::base::StringPrintf; + +namespace android { +namespace installd { + +CrateManager::CrateManager(const char* uuid, userid_t userId, const std::string& packageName) { + mPackageName = packageName; + mRoot = create_data_user_ce_package_path(uuid, userId, (const char*)packageName.c_str()); + mCratedFoldersRoot = StringPrintf("%s/crates", mRoot.c_str()); +} + +CrateManager::~CrateManager() {} + +static std::string getValidatedCratedPath(std::string path) { + size_t pos = path.rfind("/"); + if (pos == std::string::npos) { + return path; + } + + return path.substr(pos + 1, path.length()); +} + +void CrateManager::traverseChildDir(const std::string& targetDir, + std::function& onVisitChildDir) { + char* argv[] = {(char*)targetDir.c_str(), nullptr}; + FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr); + if (fts == nullptr) { + PLOG(WARNING) << "Failed to fts_open " << targetDir; + return; + } + + FTSENT* p; + while ((p = fts_read(fts)) != nullptr) { + switch (p->fts_info) { + case FTS_D: + if (p->fts_level == 1) { + onVisitChildDir(p); + } + break; + default: + break; + } + + if (p->fts_level == 1) { + fts_set(fts, p, FTS_SKIP); + } + } + fts_close(fts); +} + +void CrateManager::traverseAllPackagesForUser( + const std::optional& uuid, userid_t userId, + std::function& onHandlingPackage) { + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + + auto ce_path = create_data_user_ce_path(uuid_, userId); + traverseChildDir(ce_path, onHandlingPackage); +} + +void CrateManager::createCrate( + CratedFolder cratedFolder, + std::function& onCreateCrate) { + const char* path = cratedFolder->fts_path; + if (path == nullptr || *path == '\0') { + return; + } + + CrateMetadata crateMetadata; + crateMetadata.uid = cratedFolder->fts_statp->st_uid; + crateMetadata.packageName = mPackageName; + crateMetadata.id = getValidatedCratedPath(path); + + onCreateCrate(cratedFolder, std::move(crateMetadata)); +} + +void CrateManager::traverseAllCrates(std::function& onCreateCrate) { + std::function onVisitCrateDir = [&](FTSENT* cratedFolder) -> void { + createCrate(cratedFolder, onCreateCrate); + }; + traverseChildDir(mCratedFoldersRoot, onVisitCrateDir); +} + +#if CRATE_DEBUG +void CrateManager::dump(const CrateMetadata& CrateMetadata) { + LOG(DEBUG) << "CrateMetadata = {" + << "uid : \"" << CrateMetadata.uid + << "\", packageName : \"" << CrateMetadata.packageName + << "\", id : \"" << CrateMetadata.id + << "\"}"; +} +#endif + +} // namespace installd +} // namespace android + +#endif // ENABLE_STORAGE_CRATES \ No newline at end of file diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h new file mode 100644 index 0000000000000000000000000000000000000000..1f30b5dc7948c1fa49af678c6adb07ac4e9da711 --- /dev/null +++ b/cmds/installd/CrateManager.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_INSTALLD_CRATE_INFO_MANAGER_H +#define ANDROID_INSTALLD_CRATE_INFO_MANAGER_H + +#ifdef ENABLE_STORAGE_CRATES + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef CRATE_DEBUG +#define CRATE_DEBUG 1 +#endif + +namespace android { +namespace installd { + +using android::os::storage::CrateMetadata; + +/** + * The crated folder actually is a folder that is the first level child director. In order to + * distingish between the crated folder and the other FTSENT*, to define the type "CratedFolder" + * make the code easy to identify the difference. + */ +typedef FTSENT* CratedFolder; + +/** + * In order to give the users more fine-grained files controlling, the crate information can help + * applications' developers to show the more detail information to the users. The crate information + * include the Label, Expiration etc.. + */ +class CrateManager { +public: + CrateManager(const char* uuid, userid_t userId, const std::string& packageName); + ~CrateManager(); + + void traverseAllCrates(std::function& onCreateCrate); + + static void traverseChildDir(const std::string& targetDir, + std::function& onVisitChildDir); + + static void traverseAllPackagesForUser( + const std::optional& uuid, + userid_t userId, + std::function& onHandlingPackage); + +#if CRATE_DEBUG + static void dump(const CrateMetadata& CrateMetadata); +#endif +private: + std::string mRoot; + std::string mCratedFoldersRoot; + std::string mPackageName; + + void createCrate( + CratedFolder cratedFolder, + std::function& onCreateCrate); +}; + +} // namespace installd +} // namespace android + +#else // ENABLE_STORAGE_CRATES +#include +using android::os::storage::CrateMetadata; +#endif // ENABLE_STORAGE_CRATES + +#endif // ANDROID_INSTALLD_CRATE_INFO_MANAGER_H diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 43c490038260224a1201bcf9b86582900452bd71..0782b430a3d378d19316373c85039a47b4aeef1f 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +68,7 @@ #include "view_compiler.h" #include "CacheTracker.h" +#include "CrateManager.h" #include "MatchExtensionGen.h" #include "QuotaUtils.h" @@ -90,16 +91,15 @@ static constexpr const mode_t kRollbackFolderMode = 0700; static constexpr const char* kCpPath = "/system/bin/cp"; static constexpr const char* kXattrDefault = "user.default"; +static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce"; +static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de"; + static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M static constexpr const char* PKG_LIB_POSTFIX = "/lib"; static constexpr const char* CACHE_DIR_POSTFIX = "/cache"; static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache"; -static constexpr const char *kIdMapPath = "/system/bin/idmap"; -static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/"; -static constexpr const char* IDMAP_SUFFIX = "@idmap"; - // fsverity assumes the page size is always 4096. If not, the feature can not be // enabled. static constexpr int kVerityPageSize = 4096; @@ -107,9 +107,15 @@ static constexpr size_t kSha256Size = 32; static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode"; static constexpr const char* kFuseProp = "persist.sys.fuse"; +/** + * Property to control if app data isolation is enabled. + */ +static constexpr const char* kAppDataIsolationEnabledProperty = "persist.zygote.app_data_isolation"; static constexpr const char* kMntSdcardfs = "/mnt/runtime/default/"; static constexpr const char* kMntFuse = "/mnt/pass_through/0/"; +static std::atomic sAppDataIsolationEnabled(false); + namespace { constexpr const char* kDump = "android.permission.DUMP"; @@ -269,6 +275,8 @@ status_t InstalldNativeService::start() { sp ps(ProcessState::self()); ps->startThreadPool(); ps->giveThreadPoolName(); + sAppDataIsolationEnabled = android::base::GetBoolProperty( + kAppDataIsolationEnabledProperty, true); return android::OK; } @@ -488,9 +496,12 @@ binder::Status InstalldNativeService::createAppData(const std::optional(_aidl_return)) != 0) { - return error("Failed to get_path_inode for " + path); + if (_aidl_return != nullptr) { + ino_t result; + if (get_path_inode(path, &result) != 0) { + return error("Failed to get_path_inode for " + path); + } + *_aidl_return = static_cast(result); } } if (flags & FLAG_STORAGE_DE) { @@ -1161,8 +1172,8 @@ binder::Status InstalldNativeService::destroyCeSnapshotsNotSpecified( binder::Status InstalldNativeService::moveCompleteApp(const std::optional& fromUuid, const std::optional& toUuid, const std::string& packageName, - const std::string& dataAppName, int32_t appId, const std::string& seInfo, - int32_t targetSdkVersion) { + int32_t appId, const std::string& seInfo, + int32_t targetSdkVersion, const std::string& fromCodePath) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_UUID(fromUuid); CHECK_ARGUMENT_UUID(toUuid); @@ -1172,25 +1183,24 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::optionalc_str() : nullptr; const char* to_uuid = toUuid ? toUuid->c_str() : nullptr; const char* package_name = packageName.c_str(); - const char* data_app_name = dataAppName.c_str(); binder::Status res = ok(); std::vector users = get_known_users(from_uuid); + auto to_app_package_path_parent = create_data_app_path(to_uuid); + auto to_app_package_path = StringPrintf("%s/%s", to_app_package_path_parent.c_str(), + android::base::Basename(fromCodePath).c_str()); + // Copy app { - auto from = create_data_app_package_path(from_uuid, data_app_name); - auto to = create_data_app_package_path(to_uuid, data_app_name); - auto to_parent = create_data_app_path(to_uuid); - - int rc = copy_directory_recursive(from.c_str(), to_parent.c_str()); + int rc = copy_directory_recursive(fromCodePath.c_str(), to_app_package_path_parent.c_str()); if (rc != 0) { - res = error(rc, "Failed copying " + from + " to " + to); + res = error(rc, "Failed copying " + fromCodePath + " to " + to_app_package_path); goto fail; } - if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) { - res = error("Failed to restorecon " + to); + if (selinux_android_restorecon(to_app_package_path.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) { + res = error("Failed to restorecon " + to_app_package_path); goto fail; } } @@ -1247,9 +1257,8 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::optional& uuid, + const std::vector& packageNames, int32_t userId, + std::optional>>* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_UUID(uuid); + for (const auto& packageName : packageNames) { + CHECK_ARGUMENT_PACKAGE_NAME(packageName); + } +#ifdef ENABLE_STORAGE_CRATES + std::lock_guard lock(mLock); + + auto retVector = std::vector>(); + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + + std::function onCreateCrate = + [&](CratedFolder cratedFolder, CrateMetadata&& crateMetadata) -> void { + if (cratedFolder == nullptr) { + return; + } + retVector.push_back(std::move(crateMetadata)); + }; + + for (const auto& packageName : packageNames) { +#if CRATE_DEBUG + LOG(DEBUG) << "packageName = " << packageName; +#endif + auto crateManager = std::make_unique(uuid_, userId, packageName); + crateManager->traverseAllCrates(onCreateCrate); + } + +#if CRATE_DEBUG + LOG(WARNING) << "retVector.size() =" << retVector.size(); + for (auto& item : retVector) { + CrateManager::dump(item); + } +#endif + + *_aidl_return = std::move(retVector); +#else // ENABLE_STORAGE_CRATES + _aidl_return->reset(); + + /* prevent compile warning fail */ + if (userId < 0) { + return error(); + } +#endif // ENABLE_STORAGE_CRATES + return ok(); +} + +binder::Status InstalldNativeService::getUserCrates( + const std::optional& uuid, int32_t userId, + std::optional>>* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_UUID(uuid); +#ifdef ENABLE_STORAGE_CRATES + std::lock_guard lock(mLock); + + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + auto retVector = std::vector>(); + + std::function onCreateCrate = + [&](CratedFolder cratedFolder, CrateMetadata&& crateMetadata) -> void { + if (cratedFolder == nullptr) { + return; + } + retVector->push_back(std::move(crateMetadata)); + }; + + std::function onHandingPackage = [&](FTSENT* packageDir) -> void { + auto crateManager = std::make_unique(uuid_, userId, packageDir->fts_name); + crateManager->traverseAllCrates(onCreateCrate); + }; + CrateManager::traverseAllPackagesForUser(uuid, userId, onHandingPackage); + +#if CRATE_DEBUG + LOG(DEBUG) << "retVector.size() =" << retVector.size(); + for (auto& item : retVector) { + CrateManager::dump(item); + } +#endif + + *_aidl_return = std::move(retVector); +#else // ENABLE_STORAGE_CRATES + _aidl_return->reset(); + + /* prevent compile warning fail */ + if (userId < 0) { + return error(); + } +#endif // ENABLE_STORAGE_CRATES + return ok(); +} + binder::Status InstalldNativeService::setAppQuota(const std::optional& uuid, int32_t userId, int32_t appId, int64_t cacheQuota) { ENFORCE_UID(AID_SYSTEM); @@ -2276,7 +2379,7 @@ binder::Status InstalldNativeService::destroyProfileSnapshot(const std::string& static const char* getCStr(const std::optional& data, const char* default_value = nullptr) { - return !data ? default_value : data->c_str(); + return data ? data->c_str() : default_value; } binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid, const std::optional& packageName, const std::string& instructionSet, @@ -2423,206 +2526,6 @@ out: return res; } -static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) -{ - execl(kIdMapPath, kIdMapPath, "--fd", target_apk, overlay_apk, - StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr); - PLOG(ERROR) << "execl (" << kIdMapPath << ") failed"; -} - -static void run_verify_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) -{ - execl(kIdMapPath, kIdMapPath, "--verify", target_apk, overlay_apk, - StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr); - PLOG(ERROR) << "execl (" << kIdMapPath << ") failed"; -} - -static bool delete_stale_idmap(const char* target_apk, const char* overlay_apk, - const char* idmap_path, int32_t uid) { - int idmap_fd = open(idmap_path, O_RDWR); - if (idmap_fd < 0) { - PLOG(ERROR) << "idmap open failed: " << idmap_path; - unlink(idmap_path); - return true; - } - - pid_t pid; - pid = fork(); - if (pid == 0) { - /* child -- drop privileges before continuing */ - if (setgid(uid) != 0) { - LOG(ERROR) << "setgid(" << uid << ") failed during idmap"; - exit(1); - } - if (setuid(uid) != 0) { - LOG(ERROR) << "setuid(" << uid << ") failed during idmap"; - exit(1); - } - if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) { - PLOG(ERROR) << "flock(" << idmap_path << ") failed during idmap"; - exit(1); - } - - run_verify_idmap(target_apk, overlay_apk, idmap_fd); - exit(1); /* only if exec call to deleting stale idmap failed */ - } else { - int status = wait_child(pid); - close(idmap_fd); - - if (status != 0) { - // Failed on verifying if idmap is made from target_apk and overlay_apk. - LOG(DEBUG) << "delete stale idmap: " << idmap_path; - unlink(idmap_path); - return true; - } - } - return false; -} - -// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix) -// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap -static int flatten_path(const char *prefix, const char *suffix, - const char *overlay_path, char *idmap_path, size_t N) -{ - if (overlay_path == nullptr || idmap_path == nullptr) { - return -1; - } - const size_t len_overlay_path = strlen(overlay_path); - // will access overlay_path + 1 further below; requires absolute path - if (len_overlay_path < 2 || *overlay_path != '/') { - return -1; - } - const size_t len_idmap_root = strlen(prefix); - const size_t len_suffix = strlen(suffix); - if (SIZE_MAX - len_idmap_root < len_overlay_path || - SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) { - // additions below would cause overflow - return -1; - } - if (N < len_idmap_root + len_overlay_path + len_suffix) { - return -1; - } - memset(idmap_path, 0, N); - snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix); - char *ch = idmap_path + len_idmap_root; - while (*ch != '\0') { - if (*ch == '/') { - *ch = '@'; - } - ++ch; - } - return 0; -} - -binder::Status InstalldNativeService::idmap(const std::string& targetApkPath, - const std::string& overlayApkPath, int32_t uid) { - ENFORCE_UID(AID_SYSTEM); - CHECK_ARGUMENT_PATH(targetApkPath); - CHECK_ARGUMENT_PATH(overlayApkPath); - std::lock_guard lock(mLock); - - const char* target_apk = targetApkPath.c_str(); - const char* overlay_apk = overlayApkPath.c_str(); - ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid); - - int idmap_fd = -1; - char idmap_path[PATH_MAX]; - struct stat idmap_stat; - bool outdated = false; - - if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk, - idmap_path, sizeof(idmap_path)) == -1) { - ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk); - goto fail; - } - - if (stat(idmap_path, &idmap_stat) < 0) { - outdated = true; - } else { - outdated = delete_stale_idmap(target_apk, overlay_apk, idmap_path, uid); - } - - if (outdated) { - idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644); - } else { - idmap_fd = open(idmap_path, O_RDWR); - } - - if (idmap_fd < 0) { - ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno)); - goto fail; - } - if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) { - ALOGE("idmap cannot chown '%s'\n", idmap_path); - goto fail; - } - if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { - ALOGE("idmap cannot chmod '%s'\n", idmap_path); - goto fail; - } - - if (!outdated) { - close(idmap_fd); - return ok(); - } - - pid_t pid; - pid = fork(); - if (pid == 0) { - /* child -- drop privileges before continuing */ - if (setgid(uid) != 0) { - ALOGE("setgid(%d) failed during idmap\n", uid); - exit(1); - } - if (setuid(uid) != 0) { - ALOGE("setuid(%d) failed during idmap\n", uid); - exit(1); - } - if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) { - ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno)); - exit(1); - } - - run_idmap(target_apk, overlay_apk, idmap_fd); - exit(1); /* only if exec call to idmap failed */ - } else { - int status = wait_child(pid); - if (status != 0) { - ALOGE("idmap failed, status=0x%04x\n", status); - goto fail; - } - } - - close(idmap_fd); - return ok(); -fail: - if (idmap_fd >= 0) { - close(idmap_fd); - unlink(idmap_path); - } - return error(); -} - -binder::Status InstalldNativeService::removeIdmap(const std::string& overlayApkPath) { - ENFORCE_UID(AID_SYSTEM); - CHECK_ARGUMENT_PATH(overlayApkPath); - std::lock_guard lock(mLock); - - const char* overlay_apk = overlayApkPath.c_str(); - char idmap_path[PATH_MAX]; - - if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk, - idmap_path, sizeof(idmap_path)) == -1) { - ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk); - return error(); - } - if (unlink(idmap_path) < 0) { - ALOGE("couldn't unlink idmap file %s\n", idmap_path); - return error(); - } - return ok(); -} - binder::Status InstalldNativeService::restoreconAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo) { @@ -2965,6 +2868,115 @@ binder::Status InstalldNativeService::invalidateMounts() { return ok(); } +// Mount volume's CE and DE storage to mirror +binder::Status InstalldNativeService::tryMountDataMirror( + const std::optional& uuid) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_UUID(uuid); + if (!sAppDataIsolationEnabled) { + return ok(); + } + if (!uuid) { + return error("Should not happen, mounting uuid == null"); + } + + const char* uuid_ = uuid->c_str(); + + std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_)); + std::lock_guard lock(mLock); + if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + return error("Failed to create CE mirror"); + } + + std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_)); + if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + return error("Failed to create DE mirror"); + } + + auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str()); + auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str()); + + if (access(cePath.c_str(), F_OK) != 0) { + return error("Cannot access CE path: " + cePath); + } + if (access(dePath.c_str(), F_OK) != 0) { + return error("Cannot access DE path: " + dePath); + } + + struct stat ceStat, mirrorCeStat; + if (stat(cePath.c_str(), &ceStat) != 0) { + return error("Failed to stat " + cePath); + } + if (stat(mirrorVolCePath.c_str(), &mirrorCeStat) != 0) { + return error("Failed to stat " + mirrorVolCePath); + } + + if (mirrorCeStat.st_ino == ceStat.st_ino) { + // As it's being called by prepareUserStorage, it can be called multiple times. + // Hence, we if we mount it already, we should skip it. + LOG(WARNING) << "CE dir is mounted already: " + cePath; + return ok(); + } + + // Mount CE mirror + if (TEMP_FAILURE_RETRY(mount(cePath.c_str(), mirrorVolCePath.c_str(), NULL, + MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) { + return error("Failed to mount " + mirrorVolCePath); + } + + // Mount DE mirror + if (TEMP_FAILURE_RETRY(mount(dePath.c_str(), mirrorVolDePath.c_str(), NULL, + MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) { + return error("Failed to mount " + mirrorVolDePath); + } + return ok(); +} + +// Unmount volume's CE and DE storage from mirror +binder::Status InstalldNativeService::onPrivateVolumeRemoved( + const std::optional& uuid) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_UUID(uuid); + if (!sAppDataIsolationEnabled) { + return ok(); + } + if (!uuid) { + // It happens when private volume failed to mount. + LOG(INFO) << "Ignore unmount uuid=null"; + return ok(); + } + const char* uuid_ = uuid->c_str(); + + binder::Status res = ok(); + + std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_)); + std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_)); + + // Unmount CE storage + std::lock_guard lock(mLock); + if (TEMP_FAILURE_RETRY(umount(mirrorCeVolPath.c_str())) != 0) { + if (errno != ENOENT) { + res = error(StringPrintf("Failed to umount %s %s", mirrorCeVolPath.c_str(), + strerror(errno))); + } + } + if (delete_dir_contents_and_dir(mirrorCeVolPath, true) != 0) { + res = error("Failed to delete " + mirrorCeVolPath); + } + + // Unmount DE storage + if (TEMP_FAILURE_RETRY(umount(mirrorDeVolPath.c_str())) != 0) { + if (errno != ENOENT) { + res = error(StringPrintf("Failed to umount %s %s", mirrorDeVolPath.c_str(), + strerror(errno))); + } + } + if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) { + res = error("Failed to delete " + mirrorDeVolPath); + } + return res; +} + std::string InstalldNativeService::findDataMediaPath( const std::optional& uuid, userid_t userid) { std::lock_guard lock(mMountsLock); @@ -2980,8 +2992,7 @@ std::string InstalldNativeService::findDataMediaPath( binder::Status InstalldNativeService::isQuotaSupported( const std::optional& uuid, bool* _aidl_return) { - auto uuidString = uuid.value_or(""); - *_aidl_return = IsQuotaSupported(uuidString); + *_aidl_return = IsQuotaSupported(uuid.value_or("")); return ok(); } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 372fbc5d756435c3e04575c72b3013b4fbf94cba..98193278409384ad5f710888925386ab96e79377 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -88,13 +88,23 @@ public: int32_t userId, int32_t flags, const std::vector& appIds, std::vector* _aidl_return); + binder::Status getAppCrates(const std::optional& uuid, + const std::vector& packageNames, + int32_t userId, + std::optional>>* + _aidl_return); + binder::Status getUserCrates( + const std::optional& uuid, int32_t userId, + std::optional>>* + _aidl_return); + binder::Status setAppQuota(const std::optional& uuid, int32_t userId, int32_t appId, int64_t cacheQuota); binder::Status moveCompleteApp(const std::optional& fromUuid, const std::optional& toUuid, const std::string& packageName, - const std::string& dataAppName, int32_t appId, const std::string& seInfo, - int32_t targetSdkVersion); + int32_t appId, const std::string& seInfo, + int32_t targetSdkVersion, const std::string& fromCodePath); binder::Status dexopt(const std::string& apkPath, int32_t uid, const std::optional& packageName, const std::string& instructionSet, @@ -126,9 +136,6 @@ public: binder::Status destroyProfileSnapshot(const std::string& packageName, const std::string& profileName); - binder::Status idmap(const std::string& targetApkPath, const std::string& overlayApkPath, - int32_t uid); - binder::Status removeIdmap(const std::string& overlayApkPath); binder::Status rmPackageDir(const std::string& packageDir); binder::Status freeCache(const std::optional& uuid, int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags); @@ -155,6 +162,8 @@ public: binder::Status invalidateMounts(); binder::Status isQuotaSupported(const std::optional& volumeUuid, bool* _aidl_return); + binder::Status tryMountDataMirror(const std::optional& volumeUuid); + binder::Status onPrivateVolumeRemoved(const std::optional& volumeUuid); binder::Status prepareAppProfile(const std::string& packageName, int32_t userId, int32_t appId, const std::string& profileName, diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp index f2abf3aea392a1dda647e946ea4d5741f232da29..e0802911ca94f553342812baf8ae62c0bd1e78cb 100644 --- a/cmds/installd/QuotaUtils.cpp +++ b/cmds/installd/QuotaUtils.cpp @@ -61,6 +61,10 @@ bool InvalidateQuotaMounts() { std::getline(in, target, ' '); std::getline(in, ignored); + if (target.compare(0, 13, "/data_mirror/") == 0) { + continue; + } + if (source.compare(0, 11, "/dev/block/") == 0) { struct dqblk dq; if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index f1a87544cf8d0758c6630927c8f5fd5369c7e1aa..4ac70a4857eccdd2f158ed0a1917046a54556ac0 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -43,11 +43,19 @@ interface IInstalld { long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds); long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds); + @nullable + android.os.storage.CrateMetadata[] getAppCrates( + @nullable @utf8InCpp String uuid, in @utf8InCpp String[] packageNames, + int userId); + @nullable + android.os.storage.CrateMetadata[] getUserCrates( + @nullable @utf8InCpp String uuid, int userId); + void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota); void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid, - @utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId, - @utf8InCpp String seInfo, int targetSdkVersion); + @utf8InCpp String packageName, int appId, + @utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath); void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName, @utf8InCpp String instructionSet, int dexoptNeeded, @@ -75,8 +83,6 @@ interface IInstalld { @utf8InCpp String profileName, @utf8InCpp String classpath); void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String profileName); - void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid); - void removeIdmap(@utf8InCpp String overlayApkPath); void rmPackageDir(@utf8InCpp String packageDir); void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes, long cacheReservedBytes, int flags); @@ -115,6 +121,8 @@ interface IInstalld { in int[] retainSnapshotIds); void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName, int userId, long ceSnapshotInode, int snapshotId, int storageFlags); + void tryMountDataMirror(@nullable @utf8InCpp String volumeUuid); + void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid); void migrateLegacyObbData(); diff --git a/cmds/installd/binder/android/os/storage/CrateMetadata.aidl b/cmds/installd/binder/android/os/storage/CrateMetadata.aidl new file mode 100644 index 0000000000000000000000000000000000000000..bd6d12d9ce88e9b6f56da1546f0f19f554397d63 --- /dev/null +++ b/cmds/installd/binder/android/os/storage/CrateMetadata.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os.storage; + +/** {@hide} */ +parcelable CrateMetadata { + /** + * To tell which uid the crate belong to. + *

Because installd query all of crates in specified userId, the install may return the list + * whose elements have the same crate id but different uid and package name. + * It needs to tell the caller the difference between these elements. + */ + int uid; + + /** + * To tell which the package the crate belong to. + *

Because installd query all of crates in specified uid, the install may return the list + * whose elements have the same uid and crate id but different package name. + * It needs to tell the caller the difference between these elements. + */ + @utf8InCpp String packageName; + + /** + * To tell the crate id that is the child directory/folder name in crates + * root. + */ + @utf8InCpp String id; +} diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index d236f7664531be9c94e9a14ce5387e4f33489743..ed87b672ce69fe273b5faf0e025e3164f1ca41bd 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -331,13 +331,6 @@ TEST_F(UtilsTest, CreateDataMediaPath) { create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10)); } -TEST_F(UtilsTest, CreateDataAppPackagePath) { - EXPECT_EQ("/data/app/com.example", create_data_app_package_path(nullptr, "com.example")); - - EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app/com.example", - create_data_app_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example")); -} - TEST_F(UtilsTest, CreateDataUserPackagePath) { EXPECT_EQ("/data/data/com.example", create_data_user_ce_package_path(nullptr, 0, "com.example")); EXPECT_EQ("/data/user/10/com.example", create_data_user_ce_package_path(nullptr, 10, "com.example")); diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index f82afa83b347f97b0c17082ee08da8fb19418eed..c47df52984b8074510681a17fb839f509c718de4 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -102,18 +102,6 @@ static std::string resolve_ce_path_by_inode_or_fallback(const std::string& root_ } } -/** - * Create the path name where package app contents should be stored for - * the given volume UUID and package name. An empty UUID is assumed to - * be internal storage. - */ -std::string create_data_app_package_path(const char* volume_uuid, - const char* package_name) { - check_package_name(package_name); - return StringPrintf("%s/%s", - create_data_app_path(volume_uuid).c_str(), package_name); -} - /** * Create the path name where package data should be stored for the given * volume UUID, package name, and user ID. An empty UUID is assumed to be @@ -281,6 +269,15 @@ std::string create_data_dalvik_cache_path() { return "/data/dalvik-cache"; } +std::string create_system_user_ce_path(userid_t userId) { + return StringPrintf("%s/system_ce/%u", create_data_path(nullptr).c_str(), userId); +} + +std::string create_system_user_ce_package_path(userid_t userId, const char* package_name) { + check_package_name(package_name); + return StringPrintf("%s/%s", create_system_user_ce_path(userId).c_str(), package_name); +} + // Keep profile paths in sync with ActivityThread and LoadedApk. const std::string PROFILE_EXT = ".prof"; const std::string CURRENT_PROFILE_EXT = ".cur"; diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 2503168f1e4009fc9808d55d9155f844d3a622da..549fc6cf0481c1c7256daa3736badfff143d35de 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -47,7 +47,6 @@ constexpr const char* kXattrCacheTombstone = "user.cache_tombstone"; std::string create_data_path(const char* volume_uuid); std::string create_data_app_path(const char* volume_uuid); -std::string create_data_app_package_path(const char* volume_uuid, const char* package_name); std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid); std::string create_data_user_de_path(const char* volume_uuid, userid_t userid); @@ -82,6 +81,10 @@ std::string create_data_misc_legacy_path(userid_t userid); std::string create_data_dalvik_cache_path(); +std::string create_system_user_ce_path(userid_t userId); + +std::string create_system_user_ce_package_path(userid_t userId, const char* package_name); + std::string create_primary_cur_profile_dir_path(userid_t userid); std::string create_primary_current_profile_package_dir_path( userid_t user, const std::string& package_name); diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index c70bc3e5c15d3687817a7983d2fc21d885d64723..b57409867f6ae18f6d5ec5485efdb8121593af8a 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -1,5 +1,6 @@ syntax = "proto2"; option optimize_for = LITE_RUNTIME; +package android.surfaceflinger; message Trace { repeated Increment increment = 1; @@ -46,6 +47,12 @@ message SurfaceChange { SecureFlagChange secure_flag = 14; DeferredTransactionChange deferred_transaction = 15; CornerRadiusChange corner_radius = 16; + ReparentChange reparent = 17; + RelativeParentChange relative_parent = 18; + DetachChildrenChange detach_children = 19; + ReparentChildrenChange reparent_children = 20; + BackgroundBlurRadiusChange background_blur_radius = 21; + ShadowRadiusChange shadow_radius = 22; } } @@ -67,6 +74,10 @@ message CornerRadiusChange { required float corner_radius = 1; } +message BackgroundBlurRadiusChange { + required float background_blur_radius = 1; +} + message LayerChange { required uint32 layer = 1; } @@ -177,3 +188,24 @@ message PowerModeUpdate { required int32 id = 1; required int32 mode = 2; } + +message ReparentChange { + required int32 parent_id = 1; +} + +message ReparentChildrenChange { + required int32 parent_id = 1; +} + +message RelativeParentChange { + required int32 relative_parent_id = 1; + required int32 z = 2; +} + +message DetachChildrenChange { + required bool detach_children = 1; +} + +message ShadowRadiusChange { + required float radius = 1; +} \ No newline at end of file diff --git a/cmds/surfacereplayer/replayer/Event.cpp b/cmds/surfacereplayer/replayer/Event.cpp index 390d3982cae381cbe5e1299c197b6832b4bbf2c5..64db5f07b106cc0b32bf4b0047df99e9e019caa6 100644 --- a/cmds/surfacereplayer/replayer/Event.cpp +++ b/cmds/surfacereplayer/replayer/Event.cpp @@ -17,6 +17,7 @@ #include "Event.h" using namespace android; +using Increment = surfaceflinger::Increment; Event::Event(Increment::IncrementCase type) : mIncrementType(type) {} diff --git a/cmds/surfacereplayer/replayer/Event.h b/cmds/surfacereplayer/replayer/Event.h index 44b60f566af40d355eb4af0b45b40a393e0767dc..09a7c248d57d69ba77ae924d7b10c81b9ab44e44 100644 --- a/cmds/surfacereplayer/replayer/Event.h +++ b/cmds/surfacereplayer/replayer/Event.h @@ -24,6 +24,8 @@ namespace android { +using Increment = surfaceflinger::Increment; + class Event { public: Event(Increment::IncrementCase); diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 34886a99e93d7744524ae4b42861c234ed5b6ba9..2b5667d8fe8f0fa299a2a6c8f692b081cff606f1 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -412,6 +412,21 @@ status_t Replayer::doSurfaceTransaction( setDeferredTransaction(transaction, change.id(), change.deferred_transaction()); break; + case SurfaceChange::SurfaceChangeCase::kReparent: + setReparentChange(transaction, change.id(), change.reparent()); + break; + case SurfaceChange::SurfaceChangeCase::kReparentChildren: + setReparentChildrenChange(transaction, change.id(), change.reparent_children()); + break; + case SurfaceChange::SurfaceChangeCase::kRelativeParent: + setRelativeParentChange(transaction, change.id(), change.relative_parent()); + break; + case SurfaceChange::SurfaceChangeCase::kDetachChildren: + setDetachChildrenChange(transaction, change.id(), change.detach_children()); + break; + case SurfaceChange::SurfaceChangeCase::kShadowRadius: + setShadowRadiusChange(transaction, change.id(), change.shadow_radius()); + break; default: status = 1; break; @@ -495,6 +510,14 @@ void Replayer::setCornerRadius(SurfaceComposerClient::Transaction& t, t.setCornerRadius(mLayers[id], cc.corner_radius()); } +void Replayer::setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t, + layer_id id, const BackgroundBlurRadiusChange& cc) { + ALOGV("Layer %d: Setting Background Blur Radius -- backgroundBlurRadius=%d", id, + cc.background_blur_radius()); + + t.setBackgroundBlurRadius(mLayers[id], cc.background_blur_radius()); +} + void Replayer::setMatrix(SurfaceComposerClient::Transaction& t, layer_id id, const MatrixChange& mc) { ALOGV("Layer %d: Setting Matrix -- dsdx=%f, dtdx=%f, dsdy=%f, dtdy=%f", id, mc.dsdx(), @@ -591,7 +614,7 @@ void Replayer::setDisplayProjection(SurfaceComposerClient::Transaction& t, pc.viewport().bottom()); Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom()); - t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame); + t.setDisplayProjection(mDisplays[id], ui::toRotation(pc.orientation()), viewport, frame); } status_t Replayer::createSurfaceControl( @@ -680,3 +703,40 @@ status_t Replayer::loadSurfaceComposerClient() { mComposerClient = new SurfaceComposerClient; return mComposerClient->initCheck(); } + +void Replayer::setReparentChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ReparentChange& c) { + sp newParentHandle = nullptr; + if (mLayers.count(c.parent_id()) != 0 && mLayers[c.parent_id()] != nullptr) { + newParentHandle = mLayers[c.parent_id()]->getHandle(); + } + t.reparent(mLayers[id], newParentHandle); +} + +void Replayer::setRelativeParentChange(SurfaceComposerClient::Transaction& t, + layer_id id, const RelativeParentChange& c) { + if (mLayers.count(c.relative_parent_id()) == 0 || mLayers[c.relative_parent_id()] == nullptr) { + ALOGE("Layer %d not found in set relative parent transaction", c.relative_parent_id()); + return; + } + t.setRelativeLayer(mLayers[id], mLayers[c.relative_parent_id()]->getHandle(), c.z()); +} + +void Replayer::setDetachChildrenChange(SurfaceComposerClient::Transaction& t, + layer_id id, const DetachChildrenChange& c) { + t.detachChildren(mLayers[id]); +} + +void Replayer::setReparentChildrenChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ReparentChildrenChange& c) { + if (mLayers.count(c.parent_id()) == 0 || mLayers[c.parent_id()] == nullptr) { + ALOGE("Layer %d not found in reparent children transaction", c.parent_id()); + return; + } + t.reparentChildren(mLayers[id], mLayers[c.parent_id()]->getHandle()); +} + +void Replayer::setShadowRadiusChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ShadowRadiusChange& c) { + t.setShadowRadius(mLayers[id], c.radius()); +} diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index ad807ee95051e361337b68436d97a204041ba4cc..95857e1e5b15f41bf0a29608723729fd31a1ed60 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -38,6 +38,8 @@ #include #include +using namespace android::surfaceflinger; + namespace android { const auto DEFAULT_PATH = "/data/local/tmp/SurfaceTrace.dat"; @@ -92,6 +94,8 @@ class Replayer { layer_id id, const CropChange& cc); void setCornerRadius(SurfaceComposerClient::Transaction& t, layer_id id, const CornerRadiusChange& cc); + void setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t, + layer_id id, const BackgroundBlurRadiusChange& cc); void setMatrix(SurfaceComposerClient::Transaction& t, layer_id id, const MatrixChange& mc); void setOverrideScalingMode(SurfaceComposerClient::Transaction& t, @@ -108,6 +112,16 @@ class Replayer { layer_id id, const SecureFlagChange& sfc); void setDeferredTransaction(SurfaceComposerClient::Transaction& t, layer_id id, const DeferredTransactionChange& dtc); + void setReparentChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ReparentChange& c); + void setRelativeParentChange(SurfaceComposerClient::Transaction& t, + layer_id id, const RelativeParentChange& c); + void setDetachChildrenChange(SurfaceComposerClient::Transaction& t, + layer_id id, const DetachChildrenChange& c); + void setReparentChildrenChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ReparentChildrenChange& c); + void setShadowRadiusChange(SurfaceComposerClient::Transaction& t, + layer_id id, const ShadowRadiusChange& c); void setDisplaySurface(SurfaceComposerClient::Transaction& t, display_id id, const DispSurfaceChange& dsc); diff --git a/data/etc/android.hardware.camera.concurrent.xml b/data/etc/android.hardware.camera.concurrent.xml new file mode 100644 index 0000000000000000000000000000000000000000..2cbb263341440a3da074d13b35db325a10800ecd --- /dev/null +++ b/data/etc/android.hardware.camera.concurrent.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/data/etc/android.hardware.context_hub.xml b/data/etc/android.hardware.context_hub.xml new file mode 100644 index 0000000000000000000000000000000000000000..8133e0be057afc73bb16940f48cdd51fe30fbcd3 --- /dev/null +++ b/data/etc/android.hardware.context_hub.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/data/etc/android.hardware.device_unique_attestation.xml b/data/etc/android.hardware.device_unique_attestation.xml new file mode 100644 index 0000000000000000000000000000000000000000..309be7a2c17fb226255ba22686f724f9d867b21f --- /dev/null +++ b/data/etc/android.hardware.device_unique_attestation.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/data/etc/android.hardware.reboot_escrow.xml b/data/etc/android.hardware.reboot_escrow.xml new file mode 100644 index 0000000000000000000000000000000000000000..5db9f4c3ce645352687fb029832c49779d08ee13 --- /dev/null +++ b/data/etc/android.hardware.reboot_escrow.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/data/etc/android.hardware.sensor.hinge_angle.xml b/data/etc/android.hardware.sensor.hinge_angle.xml new file mode 100644 index 0000000000000000000000000000000000000000..d7443058ed98439e49772886a0aff3d0d3500af8 --- /dev/null +++ b/data/etc/android.hardware.sensor.hinge_angle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/data/etc/android.hardware.tv.tuner.xml b/data/etc/android.hardware.tv.tuner.xml new file mode 100644 index 0000000000000000000000000000000000000000..bbf084fabf3f4b66f79a95f12be10afe519c9ff2 --- /dev/null +++ b/data/etc/android.hardware.tv.tuner.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/data/etc/android.software.controls.xml b/data/etc/android.software.controls.xml new file mode 100644 index 0000000000000000000000000000000000000000..2cba34b754691f128c6486c180f048b3b655fd42 --- /dev/null +++ b/data/etc/android.software.controls.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml index 619d017e69adb60b3f5d592019a5a67ac1c31138..dc6963fef14ba05cae214fedaa1b2ca8fe995de2 100644 --- a/data/etc/handheld_core_hardware.xml +++ b/data/etc/handheld_core_hardware.xml @@ -59,6 +59,9 @@ + + + diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml index 52524ca95738a302e8da78d181625ef5c6394a97..e878f86243398d804c21a55ea8464f035d9d16f7 100644 --- a/data/etc/tablet_core_hardware.xml +++ b/data/etc/tablet_core_hardware.xml @@ -59,6 +59,9 @@ + + + +