Loading init/subcontext.h +1 −16 Original line number Diff line number Diff line Loading @@ -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(); } Loading @@ -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<Subcontext>* InitializeSubcontexts(); bool SubcontextChildReap(pid_t pid); Loading init/subcontext_benchmark.cpp +18 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "subcontext.h" #include <benchmark/benchmark.h> #include <selinux/selinux.h> #include "test_function_map.h" Loading @@ -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<std::string>{"return_success"}); } if (subcontext.pid() > 0) { kill(subcontext.pid(), SIGTERM); kill(subcontext.pid(), SIGKILL); } } BENCHMARK(BenchmarkSuccess); Loading init/subcontext_test.cpp +82 −61 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <android-base/properties.h> #include <android-base/strings.h> #include <gtest/gtest.h> #include <selinux/selinux.h> #include "builtin_arguments.h" #include "test_function_map.h" Loading @@ -38,10 +39,33 @@ using android::base::WaitForProperty; namespace android { namespace init { TEST(subcontext, CheckDifferentPid) { auto subcontext = Subcontext("path", kVendorContext); auto subcontext_killer = SubcontextKiller(subcontext); // I would use test fixtures, but I cannot skip the test if not root with them, so instead we have // this test runner. template <typename F> 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) { RunTest([](auto& subcontext, auto& context_string) { auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"}); ASSERT_FALSE(result); Loading @@ -50,12 +74,11 @@ TEST(subcontext, CheckDifferentPid) { 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"); Loading @@ -68,12 +91,11 @@ TEST(subcontext, SetProp) { 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); RunTest([](auto& subcontext, auto& context_string) { auto first_pid = subcontext.pid(); auto expected_words = std::vector<std::string>{ Loading @@ -96,12 +118,11 @@ TEST(subcontext, MultipleCommands) { 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 result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"}); Loading @@ -111,15 +132,15 @@ TEST(subcontext, RecoverAfterAbort) { 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); RunTest([](auto& subcontext, auto& context_string) { auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"}); ASSERT_FALSE(result); ASSERT_EQ(kVendorContext, result.error_string()); ASSERT_EQ(context_string, result.error_string()); }); } TestFunctionMap BuildTestFunctionMap() { Loading Loading
init/subcontext.h +1 −16 Original line number Diff line number Diff line Loading @@ -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(); } Loading @@ -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<Subcontext>* InitializeSubcontexts(); bool SubcontextChildReap(pid_t pid); Loading
init/subcontext_benchmark.cpp +18 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include "subcontext.h" #include <benchmark/benchmark.h> #include <selinux/selinux.h> #include "test_function_map.h" Loading @@ -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<std::string>{"return_success"}); } if (subcontext.pid() > 0) { kill(subcontext.pid(), SIGTERM); kill(subcontext.pid(), SIGKILL); } } BENCHMARK(BenchmarkSuccess); Loading
init/subcontext_test.cpp +82 −61 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <android-base/properties.h> #include <android-base/strings.h> #include <gtest/gtest.h> #include <selinux/selinux.h> #include "builtin_arguments.h" #include "test_function_map.h" Loading @@ -38,10 +39,33 @@ using android::base::WaitForProperty; namespace android { namespace init { TEST(subcontext, CheckDifferentPid) { auto subcontext = Subcontext("path", kVendorContext); auto subcontext_killer = SubcontextKiller(subcontext); // I would use test fixtures, but I cannot skip the test if not root with them, so instead we have // this test runner. template <typename F> 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) { RunTest([](auto& subcontext, auto& context_string) { auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"}); ASSERT_FALSE(result); Loading @@ -50,12 +74,11 @@ TEST(subcontext, CheckDifferentPid) { 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"); Loading @@ -68,12 +91,11 @@ TEST(subcontext, SetProp) { 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); RunTest([](auto& subcontext, auto& context_string) { auto first_pid = subcontext.pid(); auto expected_words = std::vector<std::string>{ Loading @@ -96,12 +118,11 @@ TEST(subcontext, MultipleCommands) { 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 result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"}); Loading @@ -111,15 +132,15 @@ TEST(subcontext, RecoverAfterAbort) { 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); RunTest([](auto& subcontext, auto& context_string) { auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"}); ASSERT_FALSE(result); ASSERT_EQ(kVendorContext, result.error_string()); ASSERT_EQ(context_string, result.error_string()); }); } TestFunctionMap BuildTestFunctionMap() { Loading