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

Commit e055d733 authored by Steven Moreland's avatar Steven Moreland
Browse files

init language extension for lazy HIDL services.

This associates every service with a list of HIDL services
it provides. If these are disabled, hwservicemanager will
request for the service to startup.

Bug: 64678982
Test: manual with the light service
Change-Id: Ibf8a6f1cd38312c91c798b74574fa792f23c2df4
parent 79698748
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ cc_library_static {
    whole_static_libs: ["libcap"],
    static_libs: [
        "libbase",
        "libhidl-gen-utils",
        "libselinux",
        "liblog",
        "libprocessgroup",
@@ -136,6 +137,7 @@ cc_binary {
        "libfs_mgr",
        "libfec",
        "libfec_rs",
        "libhidl-gen-utils",
        "libsquashfs_utils",
        "liblogwrap",
        "libext4_utils",
@@ -185,6 +187,7 @@ cc_test {
    ],
    static_libs: [
        "libinit",
        "libhidl-gen-utils",
        "libselinux",
        "libcrypto",
        "libprotobuf-cpp-lite",
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ LOCAL_STATIC_LIBRARIES := \
    libfs_mgr \
    libfec \
    libfec_rs \
    libhidl-gen-utils \
    libsquashfs_utils \
    liblogwrap \
    libext4_utils \
+78 −12
Original line number Diff line number Diff line
@@ -202,24 +202,90 @@ static std::optional<boot_clock::time_point> RestartProcesses() {
    return next_process_restart_time;
}

static Result<Success> DoControlStart(Service* service) {
    return service->Start();
}

static Result<Success> DoControlStop(Service* service) {
    service->Stop();
    return Success();
}

static Result<Success> DoControlRestart(Service* service) {
    service->Restart();
    return Success();
}

enum class ControlTarget {
    SERVICE,    // function gets called for the named service
    INTERFACE,  // action gets called for every service that holds this interface
};

struct ControlMessageFunction {
    ControlTarget target;
    std::function<Result<Success>(Service*)> action;
};

static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
    // clang-format off
    static const std::map<std::string, ControlMessageFunction> control_message_functions = {
        {"start",             {ControlTarget::SERVICE,   DoControlStart}},
        {"stop",              {ControlTarget::SERVICE,   DoControlStop}},
        {"restart",           {ControlTarget::SERVICE,   DoControlRestart}},
        {"interface_start",   {ControlTarget::INTERFACE, DoControlStart}},
        {"interface_stop",    {ControlTarget::INTERFACE, DoControlStop}},
        {"interface_restart", {ControlTarget::INTERFACE, DoControlRestart}},
    };
    // clang-format on

    return control_message_functions;
}

void handle_control_message(const std::string& msg, const std::string& name) {
    const auto& map = get_control_message_map();
    const auto it = map.find(msg);

    if (it == map.end()) {
        LOG(ERROR) << "Unknown control msg '" << msg << "'";
        return;
    }

    const ControlMessageFunction& function = it->second;

    if (function.target == ControlTarget::SERVICE) {
        Service* svc = ServiceList::GetInstance().FindService(name);
        if (svc == nullptr) {
        LOG(ERROR) << "no such service '" << name << "'";
            LOG(ERROR) << "No such service '" << name << "' for ctl." << msg;
            return;
        }
        if (auto result = function.action(svc); !result) {
            LOG(ERROR) << "Could not ctl." << msg << " for service " << name << ": "
                       << result.error();
        }

    if (msg == "start") {
        if (auto result = svc->Start(); !result) {
            LOG(ERROR) << "Could not ctl.start service '" << name << "': " << result.error();
        return;
    }
    } else if (msg == "stop") {
        svc->Stop();
    } else if (msg == "restart") {
        svc->Restart();
    } else {
        LOG(ERROR) << "unknown control msg '" << msg << "'";

    if (function.target == ControlTarget::INTERFACE) {
        for (const auto& svc : ServiceList::GetInstance()) {
            if (svc->interfaces().count(name) == 0) {
                continue;
            }

            if (auto result = function.action(svc.get()); !result) {
                LOG(ERROR) << "Could not handle ctl." << msg << " for service " << svc->name()
                           << " with interface " << name << ": " << result.error();
            }

            return;
        }

        LOG(ERROR) << "Could not find service hosting interface " << name;
        return;
    }

    LOG(ERROR) << "Invalid function target from static map key '" << msg
               << "': " << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
}

static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
+33 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <hidl-util/FQName.h>
#include <processgroup/processgroup.h>
#include <selinux/selinux.h>
#include <system/thread_defs.h>
@@ -418,6 +419,37 @@ Result<Success> Service::ParsePriority(const std::vector<std::string>& args) {
    return Success();
}

Result<Success> Service::ParseInterface(const std::vector<std::string>& args) {
    const std::string& interface_name = args[1];
    const std::string& instance_name = args[2];

    const FQName fq_name = FQName(interface_name);
    if (!fq_name.isValid()) {
        return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
    }

    if (!fq_name.isFullyQualified()) {
        return Error() << "Interface name not fully-qualified '" << interface_name << "'";
    }

    if (fq_name.isValidValueName()) {
        return Error() << "Interface name must not be a value name '" << interface_name << "'";
    }

    const std::string fullname = interface_name + "/" + instance_name;

    for (const auto& svc : ServiceList::GetInstance()) {
        if (svc->interfaces().count(fullname) > 0) {
            return Error() << "Interface '" << fullname << "' redefined in " << name()
                           << " but is already defined by " << svc->name();
        }
    }

    interfaces_.insert(fullname);

    return Success();
}

Result<Success> Service::ParseIoprio(const std::vector<std::string>& args) {
    if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
        return Error() << "priority value must be range 0 - 7";
@@ -619,6 +651,7 @@ const Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
        {"critical",    {0,     0,    &Service::ParseCritical}},
        {"disabled",    {0,     0,    &Service::ParseDisabled}},
        {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
        {"interface",   {2,     2,    &Service::ParseInterface}},
        {"ioprio",      {2,     2,    &Service::ParseIoprio}},
        {"priority",    {1,     1,    &Service::ParsePriority}},
        {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
+4 −0
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ class Service {
    void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; }
    IoSchedClass ioprio_class() const { return ioprio_class_; }
    int ioprio_pri() const { return ioprio_pri_; }
    const std::set<std::string>& interfaces() const { return interfaces_; }
    int priority() const { return priority_; }
    int oom_score_adjust() const { return oom_score_adjust_; }
    bool process_cgroup_empty() const { return process_cgroup_empty_; }
@@ -132,6 +133,7 @@ class Service {
    Result<Success> ParseDisabled(const std::vector<std::string>& args);
    Result<Success> ParseGroup(const std::vector<std::string>& args);
    Result<Success> ParsePriority(const std::vector<std::string>& args);
    Result<Success> ParseInterface(const std::vector<std::string>& args);
    Result<Success> ParseIoprio(const std::vector<std::string>& args);
    Result<Success> ParseKeycodes(const std::vector<std::string>& args);
    Result<Success> ParseOneshot(const std::vector<std::string>& args);
@@ -181,6 +183,8 @@ class Service {

    std::vector<std::string> writepid_files_;

    std::set<std::string> interfaces_;  // e.g. some.package.foo@1.0::IBaz/instance-name

    // keycodes for triggering this service via /dev/keychord
    std::vector<int> keycodes_;
    int keychord_id_;