Loading init/README.md +4 −0 Original line number Diff line number Diff line Loading @@ -244,6 +244,10 @@ runs the service. "r", "w" or "rw". For native executables see libcutils android\_get\_control\_file(). `gentle_kill` > This service will be sent SIGTERM instead of SIGKILL when stopped. After a 200 ms timeout, it will be sent SIGKILL. `group <groupname> [ <groupname>\* ]` > Change to 'groupname' before exec'ing this service. Additional groupnames beyond the (required) first one are used to set the Loading init/init_test.cpp +86 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <functional> #include <string_view> #include <thread> #include <type_traits> #include <android-base/file.h> Loading Loading @@ -642,6 +643,91 @@ TEST(init, MemLockLimit) { ASSERT_LE(curr_limit.rlim_max, max_limit); } static std::vector<const char*> ConvertToArgv(const std::vector<std::string>& args) { std::vector<const char*> argv; argv.reserve(args.size() + 1); for (const auto& arg : args) { if (argv.empty()) { LOG(DEBUG) << arg; } else { LOG(DEBUG) << " " << arg; } argv.emplace_back(arg.data()); } argv.emplace_back(nullptr); return argv; } pid_t ForkExecvpAsync(const std::vector<std::string>& args) { auto argv = ConvertToArgv(args); pid_t pid = fork(); if (pid == 0) { close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); execvp(argv[0], const_cast<char**>(argv.data())); PLOG(ERROR) << "exec in ForkExecvpAsync init test"; _exit(EXIT_FAILURE); } if (pid == -1) { PLOG(ERROR) << "fork in ForkExecvpAsync init test"; return -1; } return pid; } TEST(init, GentleKill) { std::string init_script = R"init( service test_gentle_kill /system/bin/sleep 1000 disabled oneshot gentle_kill user root group root seclabel u:r:toolbox:s0 )init"; ActionManager action_manager; ServiceList service_list; TestInitText(init_script, BuiltinFunctionMap(), {}, &action_manager, &service_list); ASSERT_EQ(std::distance(service_list.begin(), service_list.end()), 1); auto service = service_list.begin()->get(); ASSERT_NE(service, nullptr); ASSERT_RESULT_OK(service->Start()); const pid_t pid = service->pid(); ASSERT_GT(pid, 0); EXPECT_NE(getsid(pid), 0); TemporaryFile logfile; logfile.DoNotRemove(); ASSERT_TRUE(logfile.fd != -1); std::vector<std::string> cmd; cmd.push_back("system/bin/strace"); cmd.push_back("-o"); cmd.push_back(logfile.path); cmd.push_back("-e"); cmd.push_back("signal"); cmd.push_back("-p"); cmd.push_back(std::to_string(pid)); pid_t strace_pid = ForkExecvpAsync(cmd); // Give strace a moment to connect std::this_thread::sleep_for(1s); service->Stop(); int status; waitpid(strace_pid, &status, 0); std::string logs; android::base::ReadFdToString(logfile.fd, &logs); int pos = logs.find("killed by SIGTERM"); ASSERT_NE(pos, (int)std::string::npos); } class TestCaseLogger : public ::testing::EmptyTestEventListener { void OnTestStart(const ::testing::TestInfo& test_info) override { #ifdef __ANDROID__ Loading init/service.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <sys/time.h> #include <termios.h> #include <unistd.h> #include <thread> #include <android-base/file.h> #include <android-base/logging.h> Loading Loading @@ -887,6 +888,10 @@ void Service::StopOrReset(int how) { } if (pid_) { if (flags_ & SVC_GENTLE_KILL) { KillProcessGroup(SIGTERM); if (!process_cgroup_empty()) std::this_thread::sleep_for(200ms); } KillProcessGroup(SIGKILL); NotifyStateChange("stopping"); } else { Loading init/service.h +2 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ // should not be killed during shutdown #define SVC_TEMPORARY 0x1000 // This service was started by 'exec' and should be removed from the // service list once it is reaped. #define SVC_GENTLE_KILL 0x2000 // This service should be stopped with SIGTERM instead of SIGKILL // Will still be SIGKILLed after timeout period of 200 ms #define NR_SVC_SUPP_GIDS 12 // twelve supplementary groups Loading init/service_parser.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,11 @@ Result<void> ServiceParser::ParseEnterNamespace(std::vector<std::string>&& args) return {}; } Result<void> ServiceParser::ParseGentleKill(std::vector<std::string>&& args) { service_->flags_ |= SVC_GENTLE_KILL; return {}; } Result<void> ServiceParser::ParseGroup(std::vector<std::string>&& args) { auto gid = DecodeUid(args[1]); if (!gid.ok()) { Loading Loading @@ -584,6 +589,7 @@ const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() con {"disabled", {0, 0, &ServiceParser::ParseDisabled}}, {"enter_namespace", {2, 2, &ServiceParser::ParseEnterNamespace}}, {"file", {2, 2, &ServiceParser::ParseFile}}, {"gentle_kill", {0, 0, &ServiceParser::ParseGentleKill}}, {"group", {1, NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}}, {"interface", {2, 2, &ServiceParser::ParseInterface}}, {"ioprio", {2, 2, &ServiceParser::ParseIoprio}}, Loading Loading
init/README.md +4 −0 Original line number Diff line number Diff line Loading @@ -244,6 +244,10 @@ runs the service. "r", "w" or "rw". For native executables see libcutils android\_get\_control\_file(). `gentle_kill` > This service will be sent SIGTERM instead of SIGKILL when stopped. After a 200 ms timeout, it will be sent SIGKILL. `group <groupname> [ <groupname>\* ]` > Change to 'groupname' before exec'ing this service. Additional groupnames beyond the (required) first one are used to set the Loading
init/init_test.cpp +86 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <functional> #include <string_view> #include <thread> #include <type_traits> #include <android-base/file.h> Loading Loading @@ -642,6 +643,91 @@ TEST(init, MemLockLimit) { ASSERT_LE(curr_limit.rlim_max, max_limit); } static std::vector<const char*> ConvertToArgv(const std::vector<std::string>& args) { std::vector<const char*> argv; argv.reserve(args.size() + 1); for (const auto& arg : args) { if (argv.empty()) { LOG(DEBUG) << arg; } else { LOG(DEBUG) << " " << arg; } argv.emplace_back(arg.data()); } argv.emplace_back(nullptr); return argv; } pid_t ForkExecvpAsync(const std::vector<std::string>& args) { auto argv = ConvertToArgv(args); pid_t pid = fork(); if (pid == 0) { close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); execvp(argv[0], const_cast<char**>(argv.data())); PLOG(ERROR) << "exec in ForkExecvpAsync init test"; _exit(EXIT_FAILURE); } if (pid == -1) { PLOG(ERROR) << "fork in ForkExecvpAsync init test"; return -1; } return pid; } TEST(init, GentleKill) { std::string init_script = R"init( service test_gentle_kill /system/bin/sleep 1000 disabled oneshot gentle_kill user root group root seclabel u:r:toolbox:s0 )init"; ActionManager action_manager; ServiceList service_list; TestInitText(init_script, BuiltinFunctionMap(), {}, &action_manager, &service_list); ASSERT_EQ(std::distance(service_list.begin(), service_list.end()), 1); auto service = service_list.begin()->get(); ASSERT_NE(service, nullptr); ASSERT_RESULT_OK(service->Start()); const pid_t pid = service->pid(); ASSERT_GT(pid, 0); EXPECT_NE(getsid(pid), 0); TemporaryFile logfile; logfile.DoNotRemove(); ASSERT_TRUE(logfile.fd != -1); std::vector<std::string> cmd; cmd.push_back("system/bin/strace"); cmd.push_back("-o"); cmd.push_back(logfile.path); cmd.push_back("-e"); cmd.push_back("signal"); cmd.push_back("-p"); cmd.push_back(std::to_string(pid)); pid_t strace_pid = ForkExecvpAsync(cmd); // Give strace a moment to connect std::this_thread::sleep_for(1s); service->Stop(); int status; waitpid(strace_pid, &status, 0); std::string logs; android::base::ReadFdToString(logfile.fd, &logs); int pos = logs.find("killed by SIGTERM"); ASSERT_NE(pos, (int)std::string::npos); } class TestCaseLogger : public ::testing::EmptyTestEventListener { void OnTestStart(const ::testing::TestInfo& test_info) override { #ifdef __ANDROID__ Loading
init/service.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include <sys/time.h> #include <termios.h> #include <unistd.h> #include <thread> #include <android-base/file.h> #include <android-base/logging.h> Loading Loading @@ -887,6 +888,10 @@ void Service::StopOrReset(int how) { } if (pid_) { if (flags_ & SVC_GENTLE_KILL) { KillProcessGroup(SIGTERM); if (!process_cgroup_empty()) std::this_thread::sleep_for(200ms); } KillProcessGroup(SIGKILL); NotifyStateChange("stopping"); } else { Loading
init/service.h +2 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ // should not be killed during shutdown #define SVC_TEMPORARY 0x1000 // This service was started by 'exec' and should be removed from the // service list once it is reaped. #define SVC_GENTLE_KILL 0x2000 // This service should be stopped with SIGTERM instead of SIGKILL // Will still be SIGKILLed after timeout period of 200 ms #define NR_SVC_SUPP_GIDS 12 // twelve supplementary groups Loading
init/service_parser.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,11 @@ Result<void> ServiceParser::ParseEnterNamespace(std::vector<std::string>&& args) return {}; } Result<void> ServiceParser::ParseGentleKill(std::vector<std::string>&& args) { service_->flags_ |= SVC_GENTLE_KILL; return {}; } Result<void> ServiceParser::ParseGroup(std::vector<std::string>&& args) { auto gid = DecodeUid(args[1]); if (!gid.ok()) { Loading Loading @@ -584,6 +589,7 @@ const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() con {"disabled", {0, 0, &ServiceParser::ParseDisabled}}, {"enter_namespace", {2, 2, &ServiceParser::ParseEnterNamespace}}, {"file", {2, 2, &ServiceParser::ParseFile}}, {"gentle_kill", {0, 0, &ServiceParser::ParseGentleKill}}, {"group", {1, NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}}, {"interface", {2, 2, &ServiceParser::ParseInterface}}, {"ioprio", {2, 2, &ServiceParser::ParseIoprio}}, Loading