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

Commit 2706dc56 authored by Jiyong Park's avatar Jiyong Park Committed by android-build-merger
Browse files

Merge "Add support for updatable services" am: a07d2959

am: 0f638243

Change-Id: I00ec3418842ee6be38a087e12dc115050e1afe53
parents a9317d22 0f638243
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -332,6 +332,13 @@ runs the service.
  This is particularly useful for creating a periodic service combined with the restart_period
  option described above.

`updatable`
> Mark that the service can be overridden (via the 'override' option) later in
  the boot sequence by APEXes. When a service with updatable option is started
  before APEXes are all activated, the execution is delayed until the activation
  is finished. A service that is not marked as updatable cannot be overridden by
  APEXes.

`user <username>`
> Change to 'username' before exec'ing this service.
  Currently defaults to root.  (??? probably should default to nobody)
+1 −0
Original line number Diff line number Diff line
@@ -1079,6 +1079,7 @@ static Result<Success> do_parse_apex_configs(const BuiltinArguments& args) {
        }
        success &= parser.ParseConfigFile(c);
    }
    ServiceList::GetInstance().MarkServicesUpdate();
    if (success) {
        return Success();
    } else {
+53 −0
Original line number Diff line number Diff line
@@ -765,6 +765,11 @@ Result<Success> Service::ParseWritepid(std::vector<std::string>&& args) {
    return Success();
}

Result<Success> Service::ParseUpdatable(std::vector<std::string>&& args) {
    updatable_ = true;
    return Success();
}

class Service::OptionParserMap : public KeywordMap<OptionParser> {
  public:
    OptionParserMap() {}
@@ -817,6 +822,7 @@ const Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
        {"socket",      {3,     6,    &Service::ParseSocket}},
        {"timeout_period",
                        {1,     1,    &Service::ParseTimeoutPeriod}},
        {"updatable",   {0,     0,    &Service::ParseUpdatable}},
        {"user",        {1,     1,    &Service::ParseUser}},
        {"writepid",    {1,     kMax, &Service::ParseWritepid}},
    };
@@ -834,6 +840,13 @@ Result<Success> Service::ParseLine(std::vector<std::string>&& args) {
}

Result<Success> Service::ExecStart() {
    if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
        // Don't delay the service for ExecStart() as the semantic is that
        // the caller might depend on the side effect of the execution.
        return Error() << "Cannot start an updatable service '" << name_
                       << "' before configs from APEXes are all loaded";
    }

    flags_ |= SVC_ONESHOT;

    if (auto result = Start(); !result) {
@@ -851,6 +864,13 @@ Result<Success> Service::ExecStart() {
}

Result<Success> Service::Start() {
    if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
        ServiceList::GetInstance().DelayService(*this);
        return Error() << "Cannot start an updatable service '" << name_
                       << "' before configs from APEXes are all loaded. "
                       << "Queued for execution.";
    }

    bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
    // Starting a service removes it from the disabled or reset state and
    // immediately takes it out of the restarting state if it was in there.
@@ -1280,6 +1300,32 @@ void ServiceList::DumpState() const {
    }
}

void ServiceList::MarkServicesUpdate() {
    services_update_finished_ = true;

    // start the delayed services
    for (const auto& name : delayed_service_names_) {
        Service* service = FindService(name);
        if (service == nullptr) {
            LOG(ERROR) << "delayed service '" << name << "' could not be found.";
            continue;
        }
        if (auto result = service->Start(); !result) {
            LOG(ERROR) << result.error_string();
        }
    }
    delayed_service_names_.clear();
}

void ServiceList::DelayService(const Service& service) {
    if (services_update_finished_) {
        LOG(ERROR) << "Cannot delay the start of service '" << service.name()
                   << "' because all services are already updated. Ignoring.";
        return;
    }
    delayed_service_names_.emplace_back(service.name());
}

Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
                                            const std::string& filename, int line) {
    if (args.size() < 3) {
@@ -1291,6 +1337,8 @@ Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
        return Error() << "invalid service name '" << name << "'";
    }

    filename_ = filename;

    Subcontext* restart_action_subcontext = nullptr;
    if (subcontexts_) {
        for (auto& subcontext : *subcontexts_) {
@@ -1326,6 +1374,11 @@ Result<Success> ServiceParser::EndSection() {
                               << "'";
            }

            if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
                return Error() << "cannot update a non-updatable service '" << service_->name()
                               << "' with a config in APEX";
            }

            service_list_->RemoveService(*old_service);
            old_service = nullptr;
        }
+13 −0
Original line number Diff line number Diff line
@@ -123,6 +123,7 @@ class Service {
    std::chrono::seconds restart_period() const { return restart_period_; }
    std::optional<std::chrono::seconds> timeout_period() const { return timeout_period_; }
    const std::vector<std::string>& args() const { return args_; }
    bool is_updatable() const { return updatable_; }

  private:
    using OptionParser = Result<Success> (Service::*)(std::vector<std::string>&& args);
@@ -170,6 +171,7 @@ class Service {
    Result<Success> ParseFile(std::vector<std::string>&& args);
    Result<Success> ParseUser(std::vector<std::string>&& args);
    Result<Success> ParseWritepid(std::vector<std::string>&& args);
    Result<Success> ParseUpdatable(std::vector<std::string>&& args);

    template <typename T>
    Result<Success> AddDescriptor(std::vector<std::string>&& args);
@@ -235,6 +237,8 @@ class Service {
    std::chrono::seconds restart_period_ = 5s;
    std::optional<std::chrono::seconds> timeout_period_;

    bool updatable_ = false;

    std::vector<std::string> args_;

    std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
@@ -279,8 +283,15 @@ class ServiceList {
    const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
    const std::vector<Service*> services_in_shutdown_order() const;

    void MarkServicesUpdate();
    bool IsServicesUpdated() const { return services_update_finished_; }
    void DelayService(const Service& service);

  private:
    std::vector<std::unique_ptr<Service>> services_;

    bool services_update_finished_ = false;
    std::vector<std::string> delayed_service_names_;
};

class ServiceParser : public SectionParser {
@@ -291,6 +302,7 @@ class ServiceParser : public SectionParser {
                                 int line) override;
    Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
    Result<Success> EndSection() override;
    void EndFile() override { filename_ = ""; }

  private:
    bool IsValidName(const std::string& name) const;
@@ -298,6 +310,7 @@ class ServiceParser : public SectionParser {
    ServiceList* service_list_;
    std::vector<Subcontext>* subcontexts_;
    std::unique_ptr<Service> service_;
    std::string filename_;
};

}  // namespace init