summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
author Xin Li <delphij@google.com> 2020-09-10 17:22:18 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2020-09-10 17:22:18 +0000
commitcdb6b16dec3a541b455be99d075004cb2f0a0cd7 (patch)
treef7110d50445c67a337105034b1f2db3946a88fef /cmds
parent171cac1b603e4bb83412eb596d05a500af5d7a76 (diff)
parentac07d0f5ab16bb9e8bbbabb589d1c7d36817baa9 (diff)
Merge "Merge Android R"
Diffstat (limited to 'cmds')
-rw-r--r--cmds/atrace/atrace.rc2
-rw-r--r--cmds/dumpstate/Android.bp2
-rw-r--r--cmds/dumpstate/DumpstateService.cpp57
-rw-r--r--cmds/dumpstate/DumpstateService.h7
-rw-r--r--cmds/dumpstate/README.md6
-rw-r--r--cmds/dumpstate/binder/android/os/IDumpstate.aidl16
-rw-r--r--cmds/dumpstate/binder/android/os/IDumpstateListener.aidl16
-rw-r--r--cmds/dumpstate/binder/android/os/IDumpstateToken.aidl24
-rw-r--r--cmds/dumpstate/dumpstate.cpp730
-rw-r--r--cmds/dumpstate/dumpstate.h68
-rw-r--r--cmds/dumpstate/dumpstate.rc3
-rw-r--r--cmds/dumpstate/main.cpp2
-rw-r--r--cmds/dumpstate/tests/dumpstate_smoke_test.cpp30
-rw-r--r--cmds/dumpstate/tests/dumpstate_test.cpp269
-rw-r--r--cmds/flatland/GLHelper.cpp19
-rw-r--r--cmds/installd/.gitignore2
-rw-r--r--cmds/installd/Android.bp2
-rw-r--r--cmds/installd/CrateManager.cpp133
-rw-r--r--cmds/installd/CrateManager.h89
-rw-r--r--cmds/installd/InstalldNativeService.cpp461
-rw-r--r--cmds/installd/InstalldNativeService.h19
-rw-r--r--cmds/installd/QuotaUtils.cpp4
-rw-r--r--cmds/installd/binder/android/os/IInstalld.aidl16
-rw-r--r--cmds/installd/binder/android/os/storage/CrateMetadata.aidl41
-rw-r--r--cmds/installd/tests/installd_utils_test.cpp7
-rw-r--r--cmds/installd/utils.cpp21
-rw-r--r--cmds/installd/utils.h5
-rw-r--r--cmds/surfacereplayer/proto/src/trace.proto32
-rw-r--r--cmds/surfacereplayer/replayer/Event.cpp1
-rw-r--r--cmds/surfacereplayer/replayer/Event.h2
-rw-r--r--cmds/surfacereplayer/replayer/Replayer.cpp62
-rw-r--r--cmds/surfacereplayer/replayer/Replayer.h14
32 files changed, 1239 insertions, 923 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 0637693c9d..994375b30e 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 ba54d13436..ead491e4dd 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 10d3d1756b..bfcc058c1b 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<IDumpstateListener>& listener,
- bool getSectionDetails,
- sp<IDumpstateToken>* 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<std::mutex> 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<IDumpstateListener>& listener) {
+ const sp<IDumpstateListener>& 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<std::mutex> 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<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
options->Initialize(static_cast<Dumpstate::BugreportMode>(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<std::mutex> lock(lock_);
+ ds_->Cancel();
return binder::Status::ok();
}
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
+ std::lock_guard<std::mutex> 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<String16>&) {
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 aaaa4286cc..ac8d3acbb5 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -24,7 +24,6 @@
#include <binder/BinderService.h>
#include "android/os/BnDumpstate.h"
-#include "android/os/BnDumpstateToken.h"
#include "dumpstate.h"
namespace android {
@@ -38,14 +37,12 @@ class DumpstateService : public BinderService<DumpstateService>, public BnDumpst
static char const* getServiceName();
status_t dump(int fd, const Vector<String16>& args) override;
- binder::Status setListener(const std::string& name, const sp<IDumpstateListener>& listener,
- bool getSectionDetails,
- sp<IDumpstateToken>* 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<IDumpstateListener>& listener) override;
+ const sp<IDumpstateListener>& listener,
+ bool is_screenshot_requested) override;
// No-op
binder::Status cancelBugreport();
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index c818c05117..26dabbbcef 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 cb2d8b8d2c..ba008bb27e 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 e486460753..a5e6c68363 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/binder/android/os/IDumpstateToken.aidl b/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
deleted file mode 100644
index 7f74ceb539..0000000000
--- a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2016, 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;
-
-/**
- * Token used by the IDumpstateListener to watch for dumpstate death.
- * {@hide}
- */
-interface IDumpstateToken {
-}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e2884e578c..af41643d5d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -64,6 +64,8 @@
#include <android-base/unique_fd.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
+#include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
+#include <android/hardware/dumpstate/1.1/types.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <android/os/IIncidentCompanion.h>
#include <binder/IServiceManager.h>
@@ -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<DumpData> GetDumpFds(const std::string& dir_path,
const std::string& file_prefix,
@@ -357,6 +380,10 @@ static std::vector<DumpData> 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<std::mutex> 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<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
- if (dumpstate_device == nullptr) {
+ sp<IDumpstateDevice_1_0> 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<bool()>
- dumpstate_task([paths, dumpstate_device, &handle]() -> bool {
- android::hardware::Return<void> 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<bool()>;
+ DumpstateBoardTask dumpstate_board_task;
+ sp<IDumpstateDevice_1_1> 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<DumpstateStatus> 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<void> 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<uint8_t> 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<std::string>& args) {
// clang-format off
std::vector<std::string> 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<std::string> 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<DumpOptions> 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<std::string> 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<std::string> 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<android::IBinder> 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<android::os::IIncidentCompanion>(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 82bf8219a2..0d25d307a6 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -27,6 +27,7 @@
#include <android-base/macros.h>
#include <android-base/unique_fd.h>
+#include <android/hardware/dumpstate/1.1/types.h>
#include <android/os/BnIncidentAuthListener.h>
#include <android/os/IDumpstate.h>
#include <android/os/IDumpstateListener.h>
@@ -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<DumpOptions> options);
@@ -344,6 +356,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.
*/
struct DumpOptions {
@@ -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<android::os::IDumpstateListener> listener_;
- std::string listener_name_;
- bool report_section_;
// List of open tombstone dump files.
std::vector<DumpData> 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 14937b80b9..e491a4b614 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 68d373377c..ec89c0dd6e 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 256dc055e1..6f2d75403d 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<std::mutex> 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 <std::mutex> 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<std::mutex> 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<DumpstateListener> 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<DumpstateListener> 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<DumpstateListener> 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<DumpstateListener> 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 99d482f034..c7df1bb6a3 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -36,19 +36,22 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/dumpstate/1.1/types.h>
#include <cutils/properties.h>
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<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-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<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-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<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-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<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-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<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-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<char*>("bugreport"),
+ const_cast<char*>("dumpstatez"),
+ const_cast<char*>("-S"),
const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
const_cast<char*>("-z"),
+ const_cast<char*>("-q"),
+ const_cast<char*>("-L"),
+ const_cast<char*>("-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<char*>("bugreport"),
const_cast<char*>("-d"),
const_cast<char*>("-p"),
- const_cast<char*>("-B"),
const_cast<char*>("-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<char*>("-p"),
const_cast<char*>("-P"),
const_cast<char*>("-R"),
- const_cast<char*>("-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<DumpstateListenerMock> 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<DumpstateListenerMock> 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<DumpstateListenerMock> listener(new DumpstateListenerMock());
- sp<IDumpstateToken> token;
- EXPECT_TRUE(dss.setListener("", listener, /* getSectionDetails = */ false, &token).isOk());
- ASSERT_THAT(token, IsNull());
-}
-
-TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
- sp<IDumpstateToken> token;
- EXPECT_TRUE(
- dss.setListener("whatever", nullptr, /* getSectionDetails = */ false, &token).isOk());
- ASSERT_THAT(token, IsNull());
-}
-
-TEST_F(DumpstateServiceTest, SetListenerTwice) {
- sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- sp<IDumpstateToken> 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<DumpstateListenerMock> listener(new DumpstateListenerMock());
- sp<IDumpstateToken> 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 d398559ee8..3a3df08534 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -14,15 +14,14 @@
* limitations under the License.
*/
+#include "GLHelper.h"
+
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
-
-#include <ui/DisplayInfo.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
-#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<float>(config.resolution.getWidth()) / w;
+ float scaleY = static_cast<float>(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 0000000000..abc921ce64
--- /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 2754571b08..523115f476 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 0000000000..b17cba15d5
--- /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 <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/log.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <string>
+#include <utils.h>
+
+#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<void(FTSENT*)>& 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<std::string>& uuid, userid_t userId,
+ std::function<void(FTSENT*)>& 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<void(CratedFolder, CrateMetadata&&)>& 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<void(CratedFolder, CrateMetadata&&)>& onCreateCrate) {
+ std::function<void(FTSENT*)> 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 0000000000..1f30b5dc79
--- /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 <android/os/storage/CrateMetadata.h>
+#include <cutils/multiuser.h>
+#include <fts.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <optional>
+#include <string>
+#include <vector>
+
+#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<void(CratedFolder, CrateMetadata&&)>& onCreateCrate);
+
+ static void traverseChildDir(const std::string& targetDir,
+ std::function<void(FTSENT*)>& onVisitChildDir);
+
+ static void traverseAllPackagesForUser(
+ const std::optional<std::string>& uuid,
+ userid_t userId,
+ std::function<void(FTSENT*)>& 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<void(CratedFolder, CrateMetadata&&)>& onCreateCrate);
+};
+
+} // namespace installd
+} // namespace android
+
+#else // ENABLE_STORAGE_CRATES
+#include <android/os/storage/CrateMetadata.h>
+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 43c4900382..0782b430a3 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -24,7 +24,6 @@
#include <fts.h>
#include <functional>
#include <inttypes.h>
-#include <memory>
#include <regex>
#include <stdlib.h>
#include <string.h>
@@ -32,6 +31,7 @@
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <sys/mount.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@@ -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<bool> sAppDataIsolationEnabled(false);
+
namespace {
constexpr const char* kDump = "android.permission.DUMP";
@@ -269,6 +275,8 @@ status_t InstalldNativeService::start() {
sp<ProcessState> 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<std::str
// And return the CE inode of the top-level data directory so we can
// clear contents while CE storage is locked
- if ((_aidl_return != nullptr)
- && get_path_inode(path, reinterpret_cast<ino_t*>(_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<uint64_t>(result);
}
}
if (flags & FLAG_STORAGE_DE) {
@@ -1161,8 +1172,8 @@ binder::Status InstalldNativeService::destroyCeSnapshotsNotSpecified(
binder::Status InstalldNativeService::moveCompleteApp(const std::optional<std::string>& fromUuid,
const std::optional<std::string>& 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::optional<std::s
const char* from_uuid = fromUuid ? fromUuid->c_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<userid_t> 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<std::s
fail:
// Nuke everything we might have already copied
{
- auto to = create_data_app_package_path(to_uuid, data_app_name);
- if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
- LOG(WARNING) << "Failed to rollback " << to;
+ if (delete_dir_contents(to_app_package_path.c_str(), 1, nullptr) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to_app_package_path;
}
}
for (auto user : users) {
@@ -2203,6 +2212,100 @@ binder::Status InstalldNativeService::getExternalSize(const std::optional<std::s
return ok();
}
+binder::Status InstalldNativeService::getAppCrates(
+ const std::optional<std::string>& uuid,
+ const std::vector<std::string>& packageNames, int32_t userId,
+ std::optional<std::vector<std::optional<CrateMetadata>>>* _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<std::recursive_mutex> lock(mLock);
+
+ auto retVector = std::vector<std::optional<CrateMetadata>>();
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ std::function<void(CratedFolder, CrateMetadata&&)> 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<CrateManager>(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<std::string>& uuid, int32_t userId,
+ std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+#ifdef ENABLE_STORAGE_CRATES
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ auto retVector = std::vector<std::optional<CrateMetadata>>();
+
+ std::function<void(CratedFolder, CrateMetadata&&)> onCreateCrate =
+ [&](CratedFolder cratedFolder, CrateMetadata&& crateMetadata) -> void {
+ if (cratedFolder == nullptr) {
+ return;
+ }
+ retVector->push_back(std::move(crateMetadata));
+ };
+
+ std::function<void(FTSENT*)> onHandingPackage = [&](FTSENT* packageDir) -> void {
+ auto crateManager = std::make_unique<CrateManager>(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<std::string>& 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<std::string>& 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<std::string>& 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::string>& 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<std::string>& 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<std::recursive_mutex> 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<std::string>& 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<std::recursive_mutex> 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<std::string>& uuid, userid_t userid) {
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
@@ -2980,8 +2992,7 @@ std::string InstalldNativeService::findDataMediaPath(
binder::Status InstalldNativeService::isQuotaSupported(
const std::optional<std::string>& 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 372fbc5d75..9819327840 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<int32_t>& appIds,
std::vector<int64_t>* _aidl_return);
+ binder::Status getAppCrates(const std::optional<std::string>& uuid,
+ const std::vector<std::string>& packageNames,
+ int32_t userId,
+ std::optional<std::vector<std::optional<android::os::storage::CrateMetadata>>>*
+ _aidl_return);
+ binder::Status getUserCrates(
+ const std::optional<std::string>& uuid, int32_t userId,
+ std::optional<std::vector<std::optional<android::os::storage::CrateMetadata>>>*
+ _aidl_return);
+
binder::Status setAppQuota(const std::optional<std::string>& uuid,
int32_t userId, int32_t appId, int64_t cacheQuota);
binder::Status moveCompleteApp(const std::optional<std::string>& fromUuid,
const std::optional<std::string>& 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<std::string>& 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<std::string>& uuid, int64_t targetFreeBytes,
int64_t cacheReservedBytes, int32_t flags);
@@ -155,6 +162,8 @@ public:
binder::Status invalidateMounts();
binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
bool* _aidl_return);
+ binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
+ binder::Status onPrivateVolumeRemoved(const std::optional<std::string>& 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 f2abf3aea3..e0802911ca 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 f1a87544cf..4ac70a4857 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 0000000000..bd6d12d9ce
--- /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.
+ * <p>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.
+ * <p>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 d236f76645..ed87b672ce 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 f82afa83b3..c47df52984 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -103,18 +103,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
* internal storage.
@@ -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 2503168f1e..549fc6cf04 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 c70bc3e5c1..b57409867f 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 390d3982ca..64db5f07b1 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 44b60f566a..09a7c248d5 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 34886a99e9..2b5667d8fe 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<IBinder> 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 ad807ee950..95857e1e5b 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -38,6 +38,8 @@
#include <unordered_map>
#include <utility>
+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);