summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/dumpstate/DumpstateUtil.cpp17
-rw-r--r--cmds/dumpstate/DumpstateUtil.h19
-rw-r--r--cmds/dumpstate/README.md6
-rw-r--r--cmds/dumpstate/tests/dumpstate_test.cpp56
4 files changed, 93 insertions, 5 deletions
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 600a500e86..97c8ae2045 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -101,13 +101,16 @@ CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Al
}
CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() {
- values.account_mode_ = SU_ROOT;
+ if (!PropertiesHelper::IsUnroot()) {
+ values.account_mode_ = SU_ROOT;
+ }
return *this;
}
CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() {
- if (!PropertiesHelper::IsUserBuild())
- values.account_mode_ = SU_ROOT;
+ if (!PropertiesHelper::IsUserBuild()) {
+ return AsRoot();
+ }
return *this;
}
@@ -176,6 +179,7 @@ CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeoutInMs(int64_t ti
std::string PropertiesHelper::build_type_ = "";
int PropertiesHelper::dry_run_ = -1;
+int PropertiesHelper::unroot_ = -1;
bool PropertiesHelper::IsUserBuild() {
if (build_type_.empty()) {
@@ -191,6 +195,13 @@ bool PropertiesHelper::IsDryRun() {
return dry_run_ == 1;
}
+bool PropertiesHelper::IsUnroot() {
+ if (unroot_ == -1) {
+ unroot_ = android::base::GetBoolProperty("dumpstate.unroot", false) ? 1 : 0;
+ }
+ return unroot_ == 1;
+}
+
int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
if (fd.get() < 0) {
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 8342099821..d69ffbfc98 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -97,9 +97,16 @@ class CommandOptions {
public:
/* Sets the command to always run, even on `dry-run` mode. */
CommandOptionsBuilder& Always();
- /* Sets the command's PrivilegeMode as `SU_ROOT` */
+ /*
+ * Sets the command's PrivilegeMode as `SU_ROOT` unless overridden by system property
+ * 'dumpstate.unroot'.
+ */
CommandOptionsBuilder& AsRoot();
- /* If !IsUserBuild(), sets the command's PrivilegeMode as `SU_ROOT` */
+ /*
+ * Runs AsRoot() on userdebug builds. No-op on user builds since 'su' is
+ * not available. This is used for commands that return some useful information even
+ * when run as shell.
+ */
CommandOptionsBuilder& AsRootIfAvailable();
/* Sets the command's PrivilegeMode as `DROP_ROOT` */
CommandOptionsBuilder& DropRoot();
@@ -162,9 +169,17 @@ class PropertiesHelper {
*/
static bool IsDryRun();
+ /**
+ * Checks whether root availability should be overridden.
+ *
+ * Useful to verify how dumpstate would work in a device with an user build.
+ */
+ static bool IsUnroot();
+
private:
static std::string build_type_;
static int dry_run_;
+ static int unroot_;
};
/*
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 0302ea5f7d..6e07b3164b 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -52,6 +52,12 @@ mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dump
adb shell setprop dumpstate.dry_run true
```
+## To emulate a device with user build
+
+```
+adb shell setprop dumpstate.unroot true
+```
+
## To change the `dumpstate` version
```
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index b675c515fe..2cb980002a 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -85,6 +85,10 @@ class DumpstateBaseTest : public Test {
PropertiesHelper::build_type_ = build_type;
}
+ void SetUnroot(bool unroot) const {
+ PropertiesHelper::unroot_ = unroot;
+ }
+
bool IsStandalone() const {
return calls_ == 1;
}
@@ -650,6 +654,32 @@ TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild) {
EXPECT_THAT(err, StrEq("stderr\n"));
}
+TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild_withUnroot) {
+ if (!IsStandalone()) {
+ // TODO: temporarily disabled because it might cause other tests to fail after dropping
+ // to Shell - need to refactor tests to avoid this problem)
+ MYLOGE(
+ "Skipping DumpstateTest.RunCommandAsRootNonUserBuild_withUnroot() "
+ "on test suite\n")
+ return;
+ }
+ if (PropertiesHelper::IsUserBuild()) {
+ ALOGI("Skipping RunCommandAsRootNonUserBuild_withUnroot on user builds\n");
+ return;
+ }
+
+ // Same test as above, but with unroot property set, which will override su availability.
+ SetUnroot(true);
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+ // AsRoot is ineffective.
+ EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+ EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
+}
+
TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
if (!IsStandalone()) {
// TODO: temporarily disabled because it might cause other tests to fail after dropping
@@ -692,6 +722,32 @@ TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild) {
EXPECT_THAT(err, StrEq("stderr\n"));
}
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild_withUnroot) {
+ if (!IsStandalone()) {
+ // TODO: temporarily disabled because it might cause other tests to fail after dropping
+ // to Shell - need to refactor tests to avoid this problem)
+ MYLOGE(
+ "Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild_withUnroot() "
+ "on test suite\n")
+ return;
+ }
+ if (PropertiesHelper::IsUserBuild()) {
+ ALOGI("Skipping RunCommandAsRootIfAvailableOnDebugBuild_withUnroot on user builds\n");
+ return;
+ }
+ // Same test as above, but with unroot property set, which will override su availability.
+ SetUnroot(true);
+
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+ // It's a userdebug build, so "su root" should be available, but unroot=true overrides it.
+ EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+ EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
EXPECT_THAT(out,