Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8d42e65 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I169b52cf,Ieb0e4e24

* changes:
  init: Add test for gentle_kill
  init: Add gentle_kill service property
parents 46134b9c ed8178c8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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
+86 −0
Original line number Diff line number Diff line
@@ -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__
+5 −0
Original line number Diff line number Diff line
@@ -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 {
+2 −0
Original line number Diff line number Diff line
@@ -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

+6 −0
Original line number Diff line number Diff line
@@ -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}},
Loading