Loading cmds/dumpstate/DumpstateUtil.cpp +14 −3 Original line number Diff line number Diff line Loading @@ -101,13 +101,16 @@ CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Al } CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() { 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; } Loading Loading @@ -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()) { Loading @@ -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) { Loading cmds/dumpstate/DumpstateUtil.h +17 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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_; }; /* Loading cmds/dumpstate/README.md +6 −0 Original line number Diff line number Diff line Loading @@ -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 ``` Loading cmds/dumpstate/tests/dumpstate_test.cpp +56 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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, Loading Loading
cmds/dumpstate/DumpstateUtil.cpp +14 −3 Original line number Diff line number Diff line Loading @@ -101,13 +101,16 @@ CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Al } CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() { 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; } Loading Loading @@ -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()) { Loading @@ -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) { Loading
cmds/dumpstate/DumpstateUtil.h +17 −2 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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_; }; /* Loading
cmds/dumpstate/README.md +6 −0 Original line number Diff line number Diff line Loading @@ -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 ``` Loading
cmds/dumpstate/tests/dumpstate_test.cpp +56 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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, Loading