Merge changes I169b52cf,Ieb0e4e24

* changes:
  init: Add test for gentle_kill
  init: Add gentle_kill service property
This commit is contained in:
Treehugger Robot 2023-01-11 23:16:55 +00:00 committed by Gerrit Code Review
commit e8d42e65c8
6 changed files with 104 additions and 0 deletions

View file

@ -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

View file

@ -16,6 +16,7 @@
#include <functional>
#include <string_view>
#include <thread>
#include <type_traits>
#include <android-base/file.h>
@ -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__

View file

@ -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>
@ -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 {

View file

@ -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

View file

@ -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()) {
@ -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}},

View file

@ -53,6 +53,7 @@ class ServiceParser : public SectionParser {
Result<void> ParseDisabled(std::vector<std::string>&& args);
Result<void> ParseEnterNamespace(std::vector<std::string>&& args);
Result<void> ParseGroup(std::vector<std::string>&& args);
Result<void> ParseGentleKill(std::vector<std::string>&& args);
Result<void> ParsePriority(std::vector<std::string>&& args);
Result<void> ParseInterface(std::vector<std::string>&& args);
Result<void> ParseIoprio(std::vector<std::string>&& args);