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

Commit 8b162ac9 authored by Bart Van Assche's avatar Bart Van Assche Committed by Gerrit Code Review
Browse files

Merge changes I5a6f587e,I972f4e60,Ib8e1e87f

* changes:
  Introduce the RunService() method
  Introduce the ConfigureMemcg() method
  Introduce the Service::CheckConsole() method
parents b99ace4a bd73665e
Loading
Loading
Loading
Loading
+107 −91
Original line number Diff line number Diff line
@@ -405,6 +405,109 @@ static void ClosePipe(const std::array<int, 2>* pipe) {
    }
}

Result<void> Service::CheckConsole() {
    if (!(flags_ & SVC_CONSOLE)) {
        return {};
    }

    if (proc_attr_.console.empty()) {
        proc_attr_.console = "/dev/" + GetProperty("ro.boot.console", "console");
    }

    // Make sure that open call succeeds to ensure a console driver is
    // properly registered for the device node
    int console_fd = open(proc_attr_.console.c_str(), O_RDWR | O_CLOEXEC);
    if (console_fd < 0) {
        flags_ |= SVC_DISABLED;
        return ErrnoError() << "Couldn't open console '" << proc_attr_.console << "'";
    }
    close(console_fd);
    return {};
}

// Configures the memory cgroup properties for the service.
void Service::ConfigureMemcg() {
    if (swappiness_ != -1) {
        if (!setProcessGroupSwappiness(proc_attr_.uid, pid_, swappiness_)) {
            PLOG(ERROR) << "setProcessGroupSwappiness failed";
        }
    }

    if (soft_limit_in_bytes_ != -1) {
        if (!setProcessGroupSoftLimit(proc_attr_.uid, pid_, soft_limit_in_bytes_)) {
            PLOG(ERROR) << "setProcessGroupSoftLimit failed";
        }
    }

    size_t computed_limit_in_bytes = limit_in_bytes_;
    if (limit_percent_ != -1) {
        long page_size = sysconf(_SC_PAGESIZE);
        long num_pages = sysconf(_SC_PHYS_PAGES);
        if (page_size > 0 && num_pages > 0) {
            size_t max_mem = SIZE_MAX;
            if (size_t(num_pages) < SIZE_MAX / size_t(page_size)) {
                max_mem = size_t(num_pages) * size_t(page_size);
            }
            computed_limit_in_bytes =
                    std::min(computed_limit_in_bytes, max_mem / 100 * limit_percent_);
        }
    }

    if (!limit_property_.empty()) {
        // This ends up overwriting computed_limit_in_bytes but only if the
        // property is defined.
        computed_limit_in_bytes =
                android::base::GetUintProperty(limit_property_, computed_limit_in_bytes, SIZE_MAX);
    }

    if (computed_limit_in_bytes != size_t(-1)) {
        if (!setProcessGroupLimit(proc_attr_.uid, pid_, computed_limit_in_bytes)) {
            PLOG(ERROR) << "setProcessGroupLimit failed";
        }
    }
}

// Enters namespaces, sets environment variables, writes PID files and runs the service executable.
void Service::RunService(const std::optional<MountNamespace>& override_mount_namespace,
                         const std::vector<Descriptor>& descriptors,
                         std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd) {
    if (auto result = EnterNamespaces(namespaces_, name_, override_mount_namespace); !result.ok()) {
        LOG(FATAL) << "Service '" << name_ << "' failed to set up namespaces: " << result.error();
    }

    for (const auto& [key, value] : environment_vars_) {
        setenv(key.c_str(), value.c_str(), 1);
    }

    for (const auto& descriptor : descriptors) {
        descriptor.Publish();
    }

    if (auto result = WritePidToFiles(&writepid_files_); !result.ok()) {
        LOG(ERROR) << "failed to write pid to files: " << result.error();
    }

    // Wait until the cgroups have been created and until the cgroup controllers have been
    // activated.
    if (std::byte byte; read((*pipefd)[0], &byte, 1) < 0) {
        PLOG(ERROR) << "failed to read from notification channel";
    }
    pipefd.reset();

    if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
        LOG(ERROR) << "failed to set task profiles";
    }

    // As requested, set our gid, supplemental gids, uid, context, and
    // priority. Aborts on failure.
    SetProcessAttributesAndCaps();

    if (!ExpandArgsAndExecv(args_, sigstop_)) {
        PLOG(ERROR) << "cannot execv('" << args_[0]
                    << "'). See the 'Debugging init' section of init's README.md for tips";
    }
}

Result<void> Service::Start() {
    auto reboot_on_failure = make_scope_guard([this] {
        if (on_failure_reboot_target_) {
@@ -442,20 +545,8 @@ Result<void> Service::Start() {
        return ErrnoError() << "pipe()";
    }

    bool needs_console = (flags_ & SVC_CONSOLE);
    if (needs_console) {
        if (proc_attr_.console.empty()) {
            proc_attr_.console = "/dev/" + GetProperty("ro.boot.console", "console");
        }

        // Make sure that open call succeeds to ensure a console driver is
        // properly registered for the device node
        int console_fd = open(proc_attr_.console.c_str(), O_RDWR | O_CLOEXEC);
        if (console_fd < 0) {
            flags_ |= SVC_DISABLED;
            return ErrnoError() << "Couldn't open console '" << proc_attr_.console << "'";
        }
        close(console_fd);
    if (Result<void> result = CheckConsole(); !result.ok()) {
        return result;
    }

    struct stat sb;
@@ -527,45 +618,7 @@ Result<void> Service::Start() {

    if (pid == 0) {
        umask(077);

        if (auto result = EnterNamespaces(namespaces_, name_, override_mount_namespace);
            !result.ok()) {
            LOG(FATAL) << "Service '" << name_
                       << "' failed to set up namespaces: " << result.error();
        }

        for (const auto& [key, value] : environment_vars_) {
            setenv(key.c_str(), value.c_str(), 1);
        }

        for (const auto& descriptor : descriptors) {
            descriptor.Publish();
        }

        if (auto result = WritePidToFiles(&writepid_files_); !result.ok()) {
            LOG(ERROR) << "failed to write pid to files: " << result.error();
        }

        // Wait until the cgroups have been created and until the cgroup controllers have been
        // activated.
        if (std::byte byte; read((*pipefd)[0], &byte, 1) < 0) {
            PLOG(ERROR) << "failed to read from notification channel";
        }
        pipefd.reset();

        if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
            LOG(ERROR) << "failed to set task profiles";
        }

        // As requested, set our gid, supplemental gids, uid, context, and
        // priority. Aborts on failure.
        SetProcessAttributesAndCaps();

        if (!ExpandArgsAndExecv(args_, sigstop_)) {
            PLOG(ERROR) << "cannot execv('" << args_[0]
                        << "'). See the 'Debugging init' section of init's README.md for tips";
        }

        RunService(override_mount_namespace, descriptors, std::move(pipefd));
        _exit(127);
    }

@@ -595,44 +648,7 @@ Result<void> Service::Start() {
        PLOG(ERROR) << "createProcessGroup(" << proc_attr_.uid << ", " << pid_
                    << ") failed for service '" << name_ << "'";
    } else if (use_memcg) {
        if (swappiness_ != -1) {
            if (!setProcessGroupSwappiness(proc_attr_.uid, pid_, swappiness_)) {
                PLOG(ERROR) << "setProcessGroupSwappiness failed";
            }
        }

        if (soft_limit_in_bytes_ != -1) {
            if (!setProcessGroupSoftLimit(proc_attr_.uid, pid_, soft_limit_in_bytes_)) {
                PLOG(ERROR) << "setProcessGroupSoftLimit failed";
            }
        }

        size_t computed_limit_in_bytes = limit_in_bytes_;
        if (limit_percent_ != -1) {
            long page_size = sysconf(_SC_PAGESIZE);
            long num_pages = sysconf(_SC_PHYS_PAGES);
            if (page_size > 0 && num_pages > 0) {
                size_t max_mem = SIZE_MAX;
                if (size_t(num_pages) < SIZE_MAX / size_t(page_size)) {
                    max_mem = size_t(num_pages) * size_t(page_size);
                }
                computed_limit_in_bytes =
                        std::min(computed_limit_in_bytes, max_mem / 100 * limit_percent_);
            }
        }

        if (!limit_property_.empty()) {
            // This ends up overwriting computed_limit_in_bytes but only if the
            // property is defined.
            computed_limit_in_bytes = android::base::GetUintProperty(
                    limit_property_, computed_limit_in_bytes, SIZE_MAX);
        }

        if (computed_limit_in_bytes != size_t(-1)) {
            if (!setProcessGroupLimit(proc_attr_.uid, pid_, computed_limit_in_bytes)) {
                PLOG(ERROR) << "setProcessGroupLimit failed";
            }
        }
        ConfigureMemcg();
    }

    if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
+6 −0
Original line number Diff line number Diff line
@@ -145,6 +145,12 @@ class Service {
    void KillProcessGroup(int signal, bool report_oneshot = false);
    void SetProcessAttributesAndCaps();
    void ResetFlagsForStart();
    Result<void> CheckConsole();
    void ConfigureMemcg();
    void RunService(
            const std::optional<MountNamespace>& override_mount_namespace,
            const std::vector<Descriptor>& descriptors,
            std::unique_ptr<std::array<int, 2>, void (*)(const std::array<int, 2>* pipe)> pipefd);

    static unsigned long next_start_order_;
    static bool is_exec_service_running_;