Split out ServiceList and ServiceParser from service.cpp/.h

These always should have been in their own files.

Test: build
Change-Id: I201109b5ee63016e78901bbfd404846d45e1d4e6
This commit is contained in:
Tom Cherry 2019-06-26 10:46:20 -07:00
parent c0349199db
commit 2aeb1addee
14 changed files with 351 additions and 218 deletions

View file

@ -128,6 +128,8 @@ cc_library_static {
"selabel.cpp",
"selinux.cpp",
"service.cpp",
"service_list.cpp",
"service_parser.cpp",
"service_utils.cpp",
"sigchld_handler.cpp",
"subcontext.cpp",
@ -260,6 +262,8 @@ cc_binary {
"rlimit_parser.cpp",
"tokenizer.cpp",
"service.cpp",
"service_list.cpp",
"service_parser.cpp",
"service_utils.cpp",
"subcontext.cpp",
"subcontext.proto",

View file

@ -73,6 +73,7 @@
#include "selabel.h"
#include "selinux.h"
#include "service.h"
#include "service_list.h"
#include "subcontext.h"
#include "util.h"

View file

@ -36,6 +36,8 @@
#include "parser.h"
#include "result.h"
#include "service.h"
#include "service_list.h"
#include "service_parser.h"
#define EXCLUDE_FS_CONFIG_STRUCTURES
#include "generated_android_ids.h"

View file

@ -67,6 +67,8 @@
#include "security.h"
#include "selabel.h"
#include "selinux.h"
#include "service.h"
#include "service_parser.h"
#include "sigchld_handler.h"
#include "util.h"

View file

@ -26,7 +26,7 @@
#include "action.h"
#include "action_manager.h"
#include "parser.h"
#include "service.h"
#include "service_list.h"
namespace android {
namespace init {

View file

@ -27,6 +27,8 @@
#include "keyword_map.h"
#include "parser.h"
#include "service.h"
#include "service_list.h"
#include "service_parser.h"
#include "test_function_map.h"
#include "util.h"

View file

@ -55,6 +55,7 @@
#include "property_service.h"
#include "reboot_utils.h"
#include "service.h"
#include "service_list.h"
#include "sigchld_handler.h"
#define PROC_SYSRQ "/proc/sysrq-trigger"

View file

@ -40,6 +40,7 @@
#include <system/thread_defs.h>
#include "rlimit_parser.h"
#include "service_list.h"
#include "util.h"
#if defined(__ANDROID__)
@ -1072,17 +1073,6 @@ void Service::StopOrReset(int how) {
}
}
ServiceList::ServiceList() {}
ServiceList& ServiceList::GetInstance() {
static ServiceList instance;
return instance;
}
void ServiceList::AddService(std::unique_ptr<Service> service) {
services_.emplace_back(std::move(service));
}
std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<std::string>& args) {
// Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
// SECLABEL can be a - to denote default
@ -1147,139 +1137,5 @@ std::unique_ptr<Service> Service::MakeTemporaryOneshotService(const std::vector<
nullptr, str_args);
}
// Shutdown services in the opposite order that they were started.
const std::vector<Service*> ServiceList::services_in_shutdown_order() const {
std::vector<Service*> shutdown_services;
for (const auto& service : services_) {
if (service->start_order() > 0) shutdown_services.emplace_back(service.get());
}
std::sort(shutdown_services.begin(), shutdown_services.end(),
[](const auto& a, const auto& b) { return a->start_order() > b->start_order(); });
return shutdown_services;
}
void ServiceList::RemoveService(const Service& svc) {
auto svc_it = std::find_if(services_.begin(), services_.end(),
[&svc] (const std::unique_ptr<Service>& s) {
return svc.name() == s->name();
});
if (svc_it == services_.end()) {
return;
}
services_.erase(svc_it);
}
void ServiceList::DumpState() const {
for (const auto& s : services_) {
s->DumpState();
}
}
void ServiceList::MarkPostData() {
post_data_ = true;
}
bool ServiceList::IsPostData() {
return post_data_;
}
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().message();
}
}
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<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
if (args.size() < 3) {
return Error() << "services must have a name and a program";
}
const std::string& name = args[1];
if (!IsValidName(name)) {
return Error() << "invalid service name '" << name << "'";
}
filename_ = filename;
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
if (StartsWith(filename, subcontext.path_prefix())) {
restart_action_subcontext = &subcontext;
break;
}
}
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) {
if (str_args[0] == "/sbin/watchdogd") {
str_args[0] = "/system/bin/watchdogd";
}
}
service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);
return {};
}
Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
return service_ ? service_->ParseLine(std::move(args)) : Result<void>{};
}
Result<void> ServiceParser::EndSection() {
if (service_) {
Service* old_service = service_list_->FindService(service_->name());
if (old_service) {
if (!service_->is_override()) {
return Error() << "ignored duplicate definition of service '" << service_->name()
<< "'";
}
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;
}
service_list_->AddService(std::move(service_));
}
return {};
}
bool ServiceParser::IsValidName(const std::string& name) const {
// Property names can be any length, but may only contain certain characters.
// Property values can contain any characters, but may only be a certain length.
// (The latter restriction is needed because `start` and `stop` work by writing
// the service name to the "ctl.start" and "ctl.stop" properties.)
return IsLegalPropertyName("init.svc." + name) && name.size() <= PROP_VALUE_MAX;
}
} // namespace init
} // namespace android

View file

@ -238,78 +238,6 @@ class Service {
bool running_at_post_data_reset_ = false;
};
class ServiceList {
public:
static ServiceList& GetInstance();
// Exposed for testing
ServiceList();
void AddService(std::unique_ptr<Service> service);
void RemoveService(const Service& svc);
template <typename T, typename F = decltype(&Service::name)>
Service* FindService(T value, F function = &Service::name) const {
auto svc = std::find_if(services_.begin(), services_.end(),
[&function, &value](const std::unique_ptr<Service>& s) {
return std::invoke(function, s) == value;
});
if (svc != services_.end()) {
return svc->get();
}
return nullptr;
}
Service* FindInterface(const std::string& interface_name) {
for (const auto& svc : services_) {
if (svc->interfaces().count(interface_name) > 0) {
return svc.get();
}
}
return nullptr;
}
void DumpState() const;
auto begin() const { return services_.begin(); }
auto end() const { return services_.end(); }
const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
const std::vector<Service*> services_in_shutdown_order() const;
void MarkPostData();
bool IsPostData();
void MarkServicesUpdate();
bool IsServicesUpdated() const { return services_update_finished_; }
void DelayService(const Service& service);
private:
std::vector<std::unique_ptr<Service>> services_;
bool post_data_ = false;
bool services_update_finished_ = false;
std::vector<std::string> delayed_service_names_;
};
class ServiceParser : public SectionParser {
public:
ServiceParser(ServiceList* service_list, std::vector<Subcontext>* subcontexts)
: service_list_(service_list), subcontexts_(subcontexts), service_(nullptr) {}
Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<void> ParseLineSection(std::vector<std::string>&& args, int line) override;
Result<void> EndSection() override;
void EndFile() override { filename_ = ""; }
private:
bool IsValidName(const std::string& name) const;
ServiceList* service_list_;
std::vector<Subcontext>* subcontexts_;
std::unique_ptr<Service> service_;
std::string filename_;
};
} // namespace init
} // namespace android

98
init/service_list.cpp Normal file
View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "service_list.h"
#include <android-base/logging.h>
namespace android {
namespace init {
ServiceList::ServiceList() {}
ServiceList& ServiceList::GetInstance() {
static ServiceList instance;
return instance;
}
void ServiceList::AddService(std::unique_ptr<Service> service) {
services_.emplace_back(std::move(service));
}
// Shutdown services in the opposite order that they were started.
const std::vector<Service*> ServiceList::services_in_shutdown_order() const {
std::vector<Service*> shutdown_services;
for (const auto& service : services_) {
if (service->start_order() > 0) shutdown_services.emplace_back(service.get());
}
std::sort(shutdown_services.begin(), shutdown_services.end(),
[](const auto& a, const auto& b) { return a->start_order() > b->start_order(); });
return shutdown_services;
}
void ServiceList::RemoveService(const Service& svc) {
auto svc_it = std::find_if(
services_.begin(), services_.end(),
[&svc](const std::unique_ptr<Service>& s) { return svc.name() == s->name(); });
if (svc_it == services_.end()) {
return;
}
services_.erase(svc_it);
}
void ServiceList::DumpState() const {
for (const auto& s : services_) {
s->DumpState();
}
}
void ServiceList::MarkPostData() {
post_data_ = true;
}
bool ServiceList::IsPostData() {
return post_data_;
}
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().message();
}
}
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());
}
} // namespace init
} // namespace android

81
init/service_list.h Normal file
View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <memory>
#include <vector>
#include "service.h"
namespace android {
namespace init {
class ServiceList {
public:
static ServiceList& GetInstance();
// Exposed for testing
ServiceList();
void AddService(std::unique_ptr<Service> service);
void RemoveService(const Service& svc);
template <typename T, typename F = decltype(&Service::name)>
Service* FindService(T value, F function = &Service::name) const {
auto svc = std::find_if(services_.begin(), services_.end(),
[&function, &value](const std::unique_ptr<Service>& s) {
return std::invoke(function, s) == value;
});
if (svc != services_.end()) {
return svc->get();
}
return nullptr;
}
Service* FindInterface(const std::string& interface_name) {
for (const auto& svc : services_) {
if (svc->interfaces().count(interface_name) > 0) {
return svc.get();
}
}
return nullptr;
}
void DumpState() const;
auto begin() const { return services_.begin(); }
auto end() const { return services_.end(); }
const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
const std::vector<Service*> services_in_shutdown_order() const;
void MarkPostData();
bool IsPostData();
void MarkServicesUpdate();
bool IsServicesUpdated() const { return services_update_finished_; }
void DelayService(const Service& service);
private:
std::vector<std::unique_ptr<Service>> services_;
bool post_data_ = false;
bool services_update_finished_ = false;
std::vector<std::string> delayed_service_names_;
};
} // namespace init
} // namespace android

108
init/service_parser.cpp Normal file
View file

@ -0,0 +1,108 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "service_parser.h"
#include <android-base/strings.h>
#include "util.h"
#if defined(__ANDROID__)
#include <sys/system_properties.h>
#include "selinux.h"
#else
#include "host_init_stubs.h"
#endif
using android::base::StartsWith;
namespace android {
namespace init {
Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
if (args.size() < 3) {
return Error() << "services must have a name and a program";
}
const std::string& name = args[1];
if (!IsValidName(name)) {
return Error() << "invalid service name '" << name << "'";
}
filename_ = filename;
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
if (StartsWith(filename, subcontext.path_prefix())) {
restart_action_subcontext = &subcontext;
break;
}
}
}
std::vector<std::string> str_args(args.begin() + 2, args.end());
if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) {
if (str_args[0] == "/sbin/watchdogd") {
str_args[0] = "/system/bin/watchdogd";
}
}
service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);
return {};
}
Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
return service_ ? service_->ParseLine(std::move(args)) : Result<void>{};
}
Result<void> ServiceParser::EndSection() {
if (service_) {
Service* old_service = service_list_->FindService(service_->name());
if (old_service) {
if (!service_->is_override()) {
return Error() << "ignored duplicate definition of service '" << service_->name()
<< "'";
}
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;
}
service_list_->AddService(std::move(service_));
}
return {};
}
bool ServiceParser::IsValidName(const std::string& name) const {
// Property names can be any length, but may only contain certain characters.
// Property values can contain any characters, but may only be a certain length.
// (The latter restriction is needed because `start` and `stop` work by writing
// the service name to the "ctl.start" and "ctl.stop" properties.)
return IsLegalPropertyName("init.svc." + name) && name.size() <= PROP_VALUE_MAX;
}
} // namespace init
} // namespace android

49
init/service_parser.h Normal file
View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <vector>
#include "parser.h"
#include "service.h"
#include "service_list.h"
#include "subcontext.h"
namespace android {
namespace init {
class ServiceParser : public SectionParser {
public:
ServiceParser(ServiceList* service_list, std::vector<Subcontext>* subcontexts)
: service_list_(service_list), subcontexts_(subcontexts), service_(nullptr) {}
Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
Result<void> ParseLineSection(std::vector<std::string>&& args, int line) override;
Result<void> EndSection() override;
void EndFile() override { filename_ = ""; }
private:
bool IsValidName(const std::string& name) const;
ServiceList* service_list_;
std::vector<Subcontext>* subcontexts_;
std::unique_ptr<Service> service_;
std::string filename_;
};
} // namespace init
} // namespace android

View file

@ -30,6 +30,7 @@
#include "init.h"
#include "service.h"
#include "service_list.h"
using android::base::StringPrintf;
using android::base::boot_clock;