diff --git a/init/subcontext.h b/init/subcontext.h index e920034bc..eadabee8d 100644 --- a/init/subcontext.h +++ b/init/subcontext.h @@ -35,7 +35,7 @@ extern const std::string kVendorContext; class Subcontext { public: Subcontext(std::string path_prefix, std::string context) - : path_prefix_(std::move(path_prefix)), context_(std::move(context)) { + : path_prefix_(std::move(path_prefix)), context_(std::move(context)), pid_(0) { Fork(); } @@ -55,21 +55,6 @@ class Subcontext { android::base::unique_fd socket_; }; -// For testing, to kill the subcontext after the test has completed. -class SubcontextKiller { - public: - SubcontextKiller(const Subcontext& subcontext) : subcontext_(subcontext) {} - ~SubcontextKiller() { - if (subcontext_.pid() > 0) { - kill(subcontext_.pid(), SIGTERM); - kill(subcontext_.pid(), SIGKILL); - } - } - - private: - const Subcontext& subcontext_; -}; - int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map); std::vector* InitializeSubcontexts(); bool SubcontextChildReap(pid_t pid); diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp index a62b9592e..630799378 100644 --- a/init/subcontext_benchmark.cpp +++ b/init/subcontext_benchmark.cpp @@ -17,6 +17,7 @@ #include "subcontext.h" #include +#include #include "test_function_map.h" @@ -24,12 +25,27 @@ namespace android { namespace init { static void BenchmarkSuccess(benchmark::State& state) { - auto subcontext = Subcontext("path", kVendorContext); - auto subcontext_killer = SubcontextKiller(subcontext); + if (getuid() != 0) { + state.SkipWithError("Skipping benchmark, must be run as root."); + return; + } + char* context; + if (getcon(&context) != 0) { + state.SkipWithError("getcon() failed"); + return; + } + + auto subcontext = Subcontext("path", context); + free(context); while (state.KeepRunning()) { subcontext.Execute(std::vector{"return_success"}); } + + if (subcontext.pid() > 0) { + kill(subcontext.pid(), SIGTERM); + kill(subcontext.pid(), SIGKILL); + } } BENCHMARK(BenchmarkSuccess); diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp index 60b45b9f7..ca45266cc 100644 --- a/init/subcontext_test.cpp +++ b/init/subcontext_test.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "builtin_arguments.h" #include "test_function_map.h" @@ -38,88 +39,108 @@ using android::base::WaitForProperty; namespace android { namespace init { +// I would use test fixtures, but I cannot skip the test if not root with them, so instead we have +// this test runner. +template +void RunTest(F&& test_function) { + if (getuid() != 0) { + GTEST_LOG_(INFO) << "Skipping test, must be run as root."; + return; + } + + char* context; + ASSERT_EQ(0, getcon(&context)); + auto context_string = std::string(context); + free(context); + + auto subcontext = Subcontext("dummy_path", context_string); + ASSERT_NE(0, subcontext.pid()); + + test_function(subcontext, context_string); + + if (subcontext.pid() > 0) { + kill(subcontext.pid(), SIGTERM); + kill(subcontext.pid(), SIGKILL); + } +} + TEST(subcontext, CheckDifferentPid) { - auto subcontext = Subcontext("path", kVendorContext); - auto subcontext_killer = SubcontextKiller(subcontext); + RunTest([](auto& subcontext, auto& context_string) { + auto result = subcontext.Execute(std::vector{"return_pids_as_error"}); + ASSERT_FALSE(result); - auto result = subcontext.Execute(std::vector{"return_pids_as_error"}); - ASSERT_FALSE(result); - - auto pids = Split(result.error_string(), " "); - ASSERT_EQ(2U, pids.size()); - auto our_pid = std::to_string(getpid()); - EXPECT_NE(our_pid, pids[0]); - EXPECT_EQ(our_pid, pids[1]); + auto pids = Split(result.error_string(), " "); + ASSERT_EQ(2U, pids.size()); + auto our_pid = std::to_string(getpid()); + EXPECT_NE(our_pid, pids[0]); + EXPECT_EQ(our_pid, pids[1]); + }); } TEST(subcontext, SetProp) { - auto subcontext = Subcontext("path", kVendorContext); - auto subcontext_killer = SubcontextKiller(subcontext); + RunTest([](auto& subcontext, auto& context_string) { + SetProperty("init.test.subcontext", "fail"); + WaitForProperty("init.test.subcontext", "fail"); - SetProperty("init.test.subcontext", "fail"); - WaitForProperty("init.test.subcontext", "fail"); - - auto args = std::vector{ - "setprop", - "init.test.subcontext", - "success", - }; - auto result = subcontext.Execute(args); - ASSERT_TRUE(result) << result.error(); - - EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s)); -} - -TEST(subcontext, MultipleCommands) { - auto subcontext = Subcontext("path", kVendorContext); - auto subcontext_killer = SubcontextKiller(subcontext); - - auto first_pid = subcontext.pid(); - - auto expected_words = std::vector{ - "this", - "is", - "a", - "test", - }; - - for (const auto& word : expected_words) { auto args = std::vector{ - "add_word", - word, + "setprop", + "init.test.subcontext", + "success", }; auto result = subcontext.Execute(args); ASSERT_TRUE(result) << result.error(); - } - auto result = subcontext.Execute(std::vector{"return_words_as_error"}); - ASSERT_FALSE(result); - EXPECT_EQ(Join(expected_words, " "), result.error_string()); - EXPECT_EQ(first_pid, subcontext.pid()); + EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s)); + }); +} + +TEST(subcontext, MultipleCommands) { + RunTest([](auto& subcontext, auto& context_string) { + auto first_pid = subcontext.pid(); + + auto expected_words = std::vector{ + "this", + "is", + "a", + "test", + }; + + for (const auto& word : expected_words) { + auto args = std::vector{ + "add_word", + word, + }; + auto result = subcontext.Execute(args); + ASSERT_TRUE(result) << result.error(); + } + + auto result = subcontext.Execute(std::vector{"return_words_as_error"}); + ASSERT_FALSE(result); + EXPECT_EQ(Join(expected_words, " "), result.error_string()); + EXPECT_EQ(first_pid, subcontext.pid()); + }); } TEST(subcontext, RecoverAfterAbort) { - auto subcontext = Subcontext("path", kVendorContext); - auto subcontext_killer = SubcontextKiller(subcontext); + RunTest([](auto& subcontext, auto& context_string) { + auto first_pid = subcontext.pid(); - auto first_pid = subcontext.pid(); + auto result = subcontext.Execute(std::vector{"cause_log_fatal"}); + ASSERT_FALSE(result); - auto result = subcontext.Execute(std::vector{"cause_log_fatal"}); - ASSERT_FALSE(result); - - auto result2 = subcontext.Execute(std::vector{"generate_sane_error"}); - ASSERT_FALSE(result2); - EXPECT_EQ("Sane error!", result2.error_string()); - EXPECT_NE(subcontext.pid(), first_pid); + auto result2 = subcontext.Execute(std::vector{"generate_sane_error"}); + ASSERT_FALSE(result2); + EXPECT_EQ("Sane error!", result2.error_string()); + EXPECT_NE(subcontext.pid(), first_pid); + }); } TEST(subcontext, ContextString) { - auto subcontext = Subcontext("path", kVendorContext); - auto subcontext_killer = SubcontextKiller(subcontext); - - auto result = subcontext.Execute(std::vector{"return_context_as_error"}); - ASSERT_FALSE(result); - ASSERT_EQ(kVendorContext, result.error_string()); + RunTest([](auto& subcontext, auto& context_string) { + auto result = subcontext.Execute(std::vector{"return_context_as_error"}); + ASSERT_FALSE(result); + ASSERT_EQ(context_string, result.error_string()); + }); } TestFunctionMap BuildTestFunctionMap() {