Merge changes Ibd57c103,I81f1e8ac,Ia6e546fe
* changes: init: rename ServiceManager to ServiceList and clean it up init: move reaping from ServiceManager to signal_handler.cpp init: move exec operations out of ServiceManager
This commit is contained in:
commit
2a2a8d9ec0
|
@ -124,31 +124,32 @@ static int reboot_into_recovery(const std::vector<std::string>& options) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
static void ForEachServiceInClass(const std::string& classname, F function) {
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
if (service->classnames().count(classname)) std::invoke(function, service);
|
||||
}
|
||||
}
|
||||
|
||||
static int do_class_start(const std::vector<std::string>& args) {
|
||||
/* Starting a class does not start services
|
||||
* which are explicitly disabled. They must
|
||||
* be started individually.
|
||||
*/
|
||||
ServiceManager::GetInstance().
|
||||
ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
|
||||
// Starting a class does not start services which are explicitly disabled.
|
||||
// They must be started individually.
|
||||
ForEachServiceInClass(args[1], &Service::StartIfNotDisabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_class_stop(const std::vector<std::string>& args) {
|
||||
ServiceManager::GetInstance().
|
||||
ForEachServiceInClass(args[1], [] (Service* s) { s->Stop(); });
|
||||
ForEachServiceInClass(args[1], &Service::Stop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_class_reset(const std::vector<std::string>& args) {
|
||||
ServiceManager::GetInstance().
|
||||
ForEachServiceInClass(args[1], [] (Service* s) { s->Reset(); });
|
||||
ForEachServiceInClass(args[1], &Service::Reset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_class_restart(const std::vector<std::string>& args) {
|
||||
ServiceManager::GetInstance().
|
||||
ForEachServiceInClass(args[1], [] (Service* s) { s->Restart(); });
|
||||
ForEachServiceInClass(args[1], &Service::Restart);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -162,7 +163,7 @@ static int do_domainname(const std::vector<std::string>& args) {
|
|||
}
|
||||
|
||||
static int do_enable(const std::vector<std::string>& args) {
|
||||
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -170,11 +171,30 @@ static int do_enable(const std::vector<std::string>& args) {
|
|||
}
|
||||
|
||||
static int do_exec(const std::vector<std::string>& args) {
|
||||
return ServiceManager::GetInstance().Exec(args) ? 0 : -1;
|
||||
auto service = Service::MakeTemporaryOneshotService(args);
|
||||
if (!service) {
|
||||
LOG(ERROR) << "Failed to create exec service: " << android::base::Join(args, " ");
|
||||
return -1;
|
||||
}
|
||||
if (!service->ExecStart()) {
|
||||
LOG(ERROR) << "Failed to Start exec service";
|
||||
return -1;
|
||||
}
|
||||
ServiceList::GetInstance().AddService(std::move(service));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_exec_start(const std::vector<std::string>& args) {
|
||||
return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1;
|
||||
Service* service = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!service) {
|
||||
LOG(ERROR) << "ExecStart(" << args[1] << "): Service not found";
|
||||
return -1;
|
||||
}
|
||||
if (!service->ExecStart()) {
|
||||
LOG(ERROR) << "ExecStart(" << args[1] << "): Could not start Service";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_export(const std::vector<std::string>& args) {
|
||||
|
@ -389,8 +409,8 @@ exit_success:
|
|||
*/
|
||||
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
|
||||
auto& action_manager = ActionManager::GetInstance();
|
||||
auto& service_manager = ServiceManager::GetInstance();
|
||||
Parser parser = CreateParser(action_manager, service_manager);
|
||||
auto& service_list = ServiceList::GetInstance();
|
||||
Parser parser = CreateParser(action_manager, service_list);
|
||||
if (end_index <= start_index) {
|
||||
// Fallbacks for partitions on which early mount isn't enabled.
|
||||
for (const auto& path : late_import_paths) {
|
||||
|
@ -580,7 +600,7 @@ static int do_setrlimit(const std::vector<std::string>& args) {
|
|||
}
|
||||
|
||||
static int do_start(const std::vector<std::string>& args) {
|
||||
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) {
|
||||
LOG(ERROR) << "do_start: Service " << args[1] << " not found";
|
||||
return -1;
|
||||
|
@ -591,7 +611,7 @@ static int do_start(const std::vector<std::string>& args) {
|
|||
}
|
||||
|
||||
static int do_stop(const std::vector<std::string>& args) {
|
||||
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) {
|
||||
LOG(ERROR) << "do_stop: Service " << args[1] << " not found";
|
||||
return -1;
|
||||
|
@ -601,7 +621,7 @@ static int do_stop(const std::vector<std::string>& args) {
|
|||
}
|
||||
|
||||
static int do_restart(const std::vector<std::string>& args) {
|
||||
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
|
||||
Service* svc = ServiceList::GetInstance().FindService(args[1]);
|
||||
if (!svc) {
|
||||
LOG(ERROR) << "do_restart: Service " << args[1] << " not found";
|
||||
return -1;
|
||||
|
|
|
@ -98,22 +98,22 @@ static bool shutting_down;
|
|||
std::vector<std::string> late_import_paths;
|
||||
|
||||
void DumpState() {
|
||||
ServiceManager::GetInstance().DumpState();
|
||||
ServiceList::GetInstance().DumpState();
|
||||
ActionManager::GetInstance().DumpState();
|
||||
}
|
||||
|
||||
Parser CreateParser(ActionManager& action_manager, ServiceManager& service_manager) {
|
||||
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
|
||||
Parser parser;
|
||||
|
||||
parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_manager));
|
||||
parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list));
|
||||
parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager));
|
||||
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
static void LoadBootScripts(ActionManager& action_manager, ServiceManager& service_manager) {
|
||||
Parser parser = CreateParser(action_manager, service_manager);
|
||||
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
|
||||
Parser parser = CreateParser(action_manager, service_list);
|
||||
|
||||
std::string bootscript = GetProperty("ro.boot.init_rc", "");
|
||||
if (bootscript.empty()) {
|
||||
|
@ -221,8 +221,8 @@ void property_changed(const std::string& name, const std::string& value) {
|
|||
|
||||
static std::optional<boot_clock::time_point> RestartProcesses() {
|
||||
std::optional<boot_clock::time_point> next_process_restart_time;
|
||||
ServiceManager::GetInstance().ForEachService([&next_process_restart_time](Service* s) {
|
||||
if (!(s->flags() & SVC_RESTARTING)) return;
|
||||
for (const auto& s : ServiceList::GetInstance()) {
|
||||
if (!(s->flags() & SVC_RESTARTING)) continue;
|
||||
|
||||
auto restart_time = s->time_started() + 5s;
|
||||
if (boot_clock::now() > restart_time) {
|
||||
|
@ -232,12 +232,12 @@ static std::optional<boot_clock::time_point> RestartProcesses() {
|
|||
next_process_restart_time = restart_time;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return next_process_restart_time;
|
||||
}
|
||||
|
||||
void handle_control_message(const std::string& msg, const std::string& name) {
|
||||
Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
|
||||
Service* svc = ServiceList::GetInstance().FindService(name);
|
||||
if (svc == nullptr) {
|
||||
LOG(ERROR) << "no such service '" << name << "'";
|
||||
return;
|
||||
|
@ -1139,7 +1139,7 @@ int main(int argc, char** argv) {
|
|||
Action::set_function_map(&function_map);
|
||||
|
||||
ActionManager& am = ActionManager::GetInstance();
|
||||
ServiceManager& sm = ServiceManager::GetInstance();
|
||||
ServiceList& sm = ServiceList::GetInstance();
|
||||
|
||||
LoadBootScripts(am, sm);
|
||||
|
||||
|
@ -1180,10 +1180,10 @@ int main(int argc, char** argv) {
|
|||
// By default, sleep until something happens.
|
||||
int epoll_timeout_ms = -1;
|
||||
|
||||
if (!(waiting_for_prop || sm.IsWaitingForExec())) {
|
||||
if (!(waiting_for_prop || Service::is_exec_service_running())) {
|
||||
am.ExecuteOneCommand();
|
||||
}
|
||||
if (!(waiting_for_prop || sm.IsWaitingForExec())) {
|
||||
if (!(waiting_for_prop || Service::is_exec_service_running())) {
|
||||
if (!shutting_down) {
|
||||
auto next_process_restart_time = RestartProcesses();
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ extern struct selabel_handle *sehandle_prop;
|
|||
|
||||
extern std::vector<std::string> late_import_paths;
|
||||
|
||||
Parser CreateParser(ActionManager& action_manager, ServiceManager& service_manager);
|
||||
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
|
||||
|
||||
void handle_control_message(const std::string& msg, const std::string& arg);
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ static void handle_keychord() {
|
|||
// Only handle keychords if adb is enabled.
|
||||
std::string adb_enabled = android::base::GetProperty("init.svc.adbd", "");
|
||||
if (adb_enabled == "running") {
|
||||
Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
|
||||
Service* svc = ServiceList::GetInstance().FindService(id, &Service::keychord_id);
|
||||
if (svc) {
|
||||
LOG(INFO) << "Starting service " << svc->name() << " from keychord " << id;
|
||||
svc->Start();
|
||||
|
@ -92,7 +92,9 @@ static void handle_keychord() {
|
|||
}
|
||||
|
||||
void keychord_init() {
|
||||
ServiceManager::GetInstance().ForEachService(add_service_keycodes);
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
add_service_keycodes(service.get());
|
||||
}
|
||||
|
||||
// Nothing to do if no services require keychords.
|
||||
if (!keychords) {
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "init.h"
|
||||
#include "property_service.h"
|
||||
#include "service.h"
|
||||
#include "signal_handler.h"
|
||||
|
||||
using android::base::StringPrintf;
|
||||
using android::base::Timer;
|
||||
|
@ -373,7 +374,7 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re
|
|||
const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
|
||||
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
|
||||
const std::set<std::string> to_starts{"watchdogd"};
|
||||
ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
|
||||
for (const auto& s : ServiceList::GetInstance()) {
|
||||
if (kill_after_apps.count(s->name())) {
|
||||
s->SetShutdownCritical();
|
||||
} else if (to_starts.count(s->name())) {
|
||||
|
@ -382,14 +383,15 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re
|
|||
} else if (s->IsShutdownCritical()) {
|
||||
s->Start(); // start shutdown critical service if not started
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
|
||||
Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
|
||||
Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
|
||||
Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
|
||||
if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
|
||||
ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
|
||||
s->SetShutdownCritical(); // will not check animation class separately
|
||||
});
|
||||
// will not check animation class separately
|
||||
for (const auto& service : ServiceList::GetInstance()) {
|
||||
if (service->classnames().count("animation")) service->SetShutdownCritical();
|
||||
}
|
||||
}
|
||||
|
||||
// optional shutdown step
|
||||
|
@ -398,18 +400,18 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re
|
|||
LOG(INFO) << "terminating init services";
|
||||
|
||||
// Ask all services to terminate except shutdown critical ones.
|
||||
ServiceManager::GetInstance().ForEachServiceShutdownOrder([](Service* s) {
|
||||
for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
|
||||
if (!s->IsShutdownCritical()) s->Terminate();
|
||||
});
|
||||
}
|
||||
|
||||
int service_count = 0;
|
||||
// Only wait up to half of timeout here
|
||||
auto termination_wait_timeout = shutdown_timeout / 2;
|
||||
while (t.duration() < termination_wait_timeout) {
|
||||
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
|
||||
ReapAnyOutstandingChildren();
|
||||
|
||||
service_count = 0;
|
||||
ServiceManager::GetInstance().ForEachService([&service_count](Service* s) {
|
||||
for (const auto& s : ServiceList::GetInstance()) {
|
||||
// Count the number of services running except shutdown critical.
|
||||
// Exclude the console as it will ignore the SIGTERM signal
|
||||
// and not exit.
|
||||
|
@ -418,7 +420,7 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re
|
|||
if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
|
||||
service_count++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (service_count == 0) {
|
||||
// All terminable services terminated. We can exit early.
|
||||
|
@ -434,13 +436,13 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re
|
|||
|
||||
// minimum safety steps before restarting
|
||||
// 2. kill all services except ones that are necessary for the shutdown sequence.
|
||||
ServiceManager::GetInstance().ForEachServiceShutdownOrder([](Service* s) {
|
||||
for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
|
||||
if (!s->IsShutdownCritical()) s->Stop();
|
||||
});
|
||||
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
|
||||
}
|
||||
ReapAnyOutstandingChildren();
|
||||
|
||||
// 3. send volume shutdown to vold
|
||||
Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
|
||||
Service* voldService = ServiceList::GetInstance().FindService("vold");
|
||||
if (voldService != nullptr && voldService->IsRunning()) {
|
||||
ShutdownVold();
|
||||
voldService->Stop();
|
||||
|
@ -448,9 +450,9 @@ void DoReboot(unsigned int cmd, const std::string& reason, const std::string& re
|
|||
LOG(INFO) << "vold not running, skipping vold shutdown";
|
||||
}
|
||||
// logcat stopped here
|
||||
ServiceManager::GetInstance().ForEachServiceShutdownOrder([&kill_after_apps](Service* s) {
|
||||
for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
|
||||
if (kill_after_apps.count(s->name())) s->Stop();
|
||||
});
|
||||
}
|
||||
// 4. sync, try umount, and optionally run fsck for user shutdown
|
||||
sync();
|
||||
UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
|
||||
|
@ -524,9 +526,9 @@ bool HandlePowerctlMessage(const std::string& command) {
|
|||
// Skip wait for prop if it is in progress
|
||||
ResetWaitForProp();
|
||||
|
||||
// Skip wait for exec if it is in progress
|
||||
if (ServiceManager::GetInstance().IsWaitingForExec()) {
|
||||
ServiceManager::GetInstance().ClearExecWait();
|
||||
// Clear EXEC flag if there is one pending
|
||||
for (const auto& s : ServiceList::GetInstance()) {
|
||||
s->UnSetExec();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
221
init/service.cpp
221
init/service.cpp
|
@ -156,6 +156,7 @@ ServiceEnvironmentInfo::ServiceEnvironmentInfo(const std::string& name,
|
|||
}
|
||||
|
||||
unsigned long Service::next_start_order_ = 1;
|
||||
bool Service::is_exec_service_running_ = false;
|
||||
|
||||
Service::Service(const std::string& name, const std::vector<std::string>& args)
|
||||
: Service(name, 0, 0, 0, {}, 0, 0, "", args) {}
|
||||
|
@ -280,9 +281,9 @@ void Service::Reap() {
|
|||
std::for_each(descriptors_.begin(), descriptors_.end(),
|
||||
std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
|
||||
|
||||
if (flags_ & SVC_TEMPORARY) {
|
||||
return;
|
||||
}
|
||||
if (flags_ & SVC_EXEC) UnSetExec();
|
||||
|
||||
if (flags_ & SVC_TEMPORARY) return;
|
||||
|
||||
pid_ = 0;
|
||||
flags_ &= (~SVC_RUNNING);
|
||||
|
@ -653,15 +654,20 @@ bool Service::ParseLine(const std::vector<std::string>& args, std::string* err)
|
|||
return (this->*parser)(args, err);
|
||||
}
|
||||
|
||||
bool Service::ExecStart(std::unique_ptr<android::base::Timer>* exec_waiter) {
|
||||
flags_ |= SVC_EXEC | SVC_ONESHOT;
|
||||
|
||||
exec_waiter->reset(new android::base::Timer);
|
||||
bool Service::ExecStart() {
|
||||
flags_ |= SVC_ONESHOT;
|
||||
|
||||
if (!Start()) {
|
||||
exec_waiter->reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
flags_ |= SVC_EXEC;
|
||||
is_exec_service_running_ = true;
|
||||
|
||||
LOG(INFO) << "SVC_EXEC pid " << pid_ << " (uid " << uid_ << " gid " << gid_ << "+"
|
||||
<< supp_gids_.size() << " context " << (!seclabel_.empty() ? seclabel_ : "default")
|
||||
<< ") started; waiting...";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -836,12 +842,6 @@ bool Service::Start() {
|
|||
}
|
||||
}
|
||||
|
||||
if ((flags_ & SVC_EXEC) != 0) {
|
||||
LOG(INFO) << "SVC_EXEC pid " << pid_ << " (uid " << uid_ << " gid " << gid_ << "+"
|
||||
<< supp_gids_.size() << " context "
|
||||
<< (!seclabel_.empty() ? seclabel_ : "default") << ") started; waiting...";
|
||||
}
|
||||
|
||||
NotifyStateChange("running");
|
||||
return true;
|
||||
}
|
||||
|
@ -935,50 +935,18 @@ void Service::OpenConsole() const {
|
|||
close(fd);
|
||||
}
|
||||
|
||||
int ServiceManager::exec_count_ = 0;
|
||||
ServiceList::ServiceList() {}
|
||||
|
||||
ServiceManager::ServiceManager() {
|
||||
}
|
||||
|
||||
ServiceManager& ServiceManager::GetInstance() {
|
||||
static ServiceManager instance;
|
||||
ServiceList& ServiceList::GetInstance() {
|
||||
static ServiceList instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ServiceManager::AddService(std::unique_ptr<Service> service) {
|
||||
void ServiceList::AddService(std::unique_ptr<Service> service) {
|
||||
services_.emplace_back(std::move(service));
|
||||
}
|
||||
|
||||
bool ServiceManager::Exec(const std::vector<std::string>& args) {
|
||||
Service* svc = MakeExecOneshotService(args);
|
||||
if (!svc) {
|
||||
LOG(ERROR) << "Could not create exec service";
|
||||
return false;
|
||||
}
|
||||
if (!svc->ExecStart(&exec_waiter_)) {
|
||||
LOG(ERROR) << "Could not start exec service";
|
||||
ServiceManager::GetInstance().RemoveService(*svc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ServiceManager::ExecStart(const std::string& name) {
|
||||
Service* svc = FindServiceByName(name);
|
||||
if (!svc) {
|
||||
LOG(ERROR) << "ExecStart(" << name << "): Service not found";
|
||||
return false;
|
||||
}
|
||||
if (!svc->ExecStart(&exec_waiter_)) {
|
||||
LOG(ERROR) << "ExecStart(" << name << "): Could not start Service";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ServiceManager::IsWaitingForExec() const { return exec_waiter_ != nullptr; }
|
||||
|
||||
Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) {
|
||||
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
|
||||
std::size_t command_arg = 1;
|
||||
|
@ -999,10 +967,11 @@ Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>&
|
|||
}
|
||||
std::vector<std::string> str_args(args.begin() + command_arg, args.end());
|
||||
|
||||
exec_count_++;
|
||||
std::string name = "exec " + std::to_string(exec_count_) + " (" + Join(str_args, " ") + ")";
|
||||
static size_t exec_count = 0;
|
||||
exec_count++;
|
||||
std::string name = "exec " + std::to_string(exec_count) + " (" + Join(str_args, " ") + ")";
|
||||
|
||||
unsigned flags = SVC_EXEC | SVC_ONESHOT | SVC_TEMPORARY;
|
||||
unsigned flags = SVC_ONESHOT | SVC_TEMPORARY;
|
||||
CapSet no_capabilities;
|
||||
unsigned namespace_flags = 0;
|
||||
|
||||
|
@ -1037,77 +1006,22 @@ Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>&
|
|||
}
|
||||
}
|
||||
|
||||
auto svc_p = std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
|
||||
namespace_flags, seclabel, str_args);
|
||||
Service* svc = svc_p.get();
|
||||
services_.emplace_back(std::move(svc_p));
|
||||
|
||||
return svc;
|
||||
}
|
||||
|
||||
Service* ServiceManager::FindServiceByName(const std::string& name) const {
|
||||
auto svc = std::find_if(services_.begin(), services_.end(),
|
||||
[&name] (const std::unique_ptr<Service>& s) {
|
||||
return name == s->name();
|
||||
});
|
||||
if (svc != services_.end()) {
|
||||
return svc->get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Service* ServiceManager::FindServiceByPid(pid_t pid) const {
|
||||
auto svc = std::find_if(services_.begin(), services_.end(),
|
||||
[&pid] (const std::unique_ptr<Service>& s) {
|
||||
return s->pid() == pid;
|
||||
});
|
||||
if (svc != services_.end()) {
|
||||
return svc->get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Service* ServiceManager::FindServiceByKeychord(int keychord_id) const {
|
||||
auto svc = std::find_if(services_.begin(), services_.end(),
|
||||
[&keychord_id] (const std::unique_ptr<Service>& s) {
|
||||
return s->keychord_id() == keychord_id;
|
||||
});
|
||||
|
||||
if (svc != services_.end()) {
|
||||
return svc->get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ServiceManager::ForEachService(const std::function<void(Service*)>& callback) const {
|
||||
for (const auto& s : services_) {
|
||||
callback(s.get());
|
||||
}
|
||||
return std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
|
||||
namespace_flags, seclabel, str_args);
|
||||
}
|
||||
|
||||
// Shutdown services in the opposite order that they were started.
|
||||
void ServiceManager::ForEachServiceShutdownOrder(const std::function<void(Service*)>& callback) const {
|
||||
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(); });
|
||||
for (const auto& service : shutdown_services) {
|
||||
callback(service);
|
||||
}
|
||||
return shutdown_services;
|
||||
}
|
||||
|
||||
void ServiceManager::ForEachServiceInClass(const std::string& classname,
|
||||
void (*func)(Service* svc)) const {
|
||||
for (const auto& s : services_) {
|
||||
if (s->classnames().find(classname) != s->classnames().end()) {
|
||||
func(s.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceManager::RemoveService(const Service& svc) {
|
||||
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();
|
||||
|
@ -1119,85 +1033,12 @@ void ServiceManager::RemoveService(const Service& svc) {
|
|||
services_.erase(svc_it);
|
||||
}
|
||||
|
||||
void ServiceManager::DumpState() const {
|
||||
void ServiceList::DumpState() const {
|
||||
for (const auto& s : services_) {
|
||||
s->DumpState();
|
||||
}
|
||||
}
|
||||
|
||||
bool ServiceManager::ReapOneProcess() {
|
||||
siginfo_t siginfo = {};
|
||||
// This returns a zombie pid or informs us that there are no zombies left to be reaped.
|
||||
// It does NOT reap the pid; that is done below.
|
||||
if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
|
||||
PLOG(ERROR) << "waitid failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pid = siginfo.si_pid;
|
||||
if (pid == 0) return false;
|
||||
|
||||
// At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
|
||||
// whenever the function returns from this point forward.
|
||||
// We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
|
||||
// want the pid to remain valid throughout that (and potentially future) usages.
|
||||
auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
|
||||
|
||||
if (PropertyChildReap(pid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Service* svc = FindServiceByPid(pid);
|
||||
|
||||
std::string name;
|
||||
std::string wait_string;
|
||||
if (svc) {
|
||||
name = StringPrintf("Service '%s' (pid %d)", svc->name().c_str(), pid);
|
||||
if (svc->flags() & SVC_EXEC) {
|
||||
wait_string = StringPrintf(" waiting took %f seconds",
|
||||
exec_waiter_->duration().count() / 1000.0f);
|
||||
}
|
||||
} else {
|
||||
name = StringPrintf("Untracked pid %d", pid);
|
||||
}
|
||||
|
||||
auto status = siginfo.si_status;
|
||||
if (WIFEXITED(status)) {
|
||||
LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
|
||||
}
|
||||
|
||||
if (!svc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
svc->Reap();
|
||||
|
||||
if (svc->flags() & SVC_EXEC) {
|
||||
exec_waiter_.reset();
|
||||
}
|
||||
if (svc->flags() & SVC_TEMPORARY) {
|
||||
RemoveService(*svc);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServiceManager::ReapAnyOutstandingChildren() {
|
||||
while (ReapOneProcess()) {
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceManager::ClearExecWait() {
|
||||
// Clear EXEC flag if there is one pending
|
||||
// And clear the wait flag
|
||||
for (const auto& s : services_) {
|
||||
s->UnSetExec();
|
||||
}
|
||||
exec_waiter_.reset();
|
||||
}
|
||||
|
||||
bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename,
|
||||
int line, std::string* err) {
|
||||
if (args.size() < 3) {
|
||||
|
@ -1211,7 +1052,7 @@ bool ServiceParser::ParseSection(std::vector<std::string>&& args, const std::str
|
|||
return false;
|
||||
}
|
||||
|
||||
Service* old_service = service_manager_->FindServiceByName(name);
|
||||
Service* old_service = service_list_->FindService(name);
|
||||
if (old_service) {
|
||||
*err = "ignored duplicate definition of service '" + name + "'";
|
||||
return false;
|
||||
|
@ -1228,7 +1069,7 @@ bool ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line,
|
|||
|
||||
void ServiceParser::EndSection() {
|
||||
if (service_) {
|
||||
service_manager_->AddService(std::move(service_));
|
||||
service_list_->AddService(std::move(service_));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,9 +73,11 @@ class Service {
|
|||
unsigned namespace_flags, const std::string& seclabel,
|
||||
const std::vector<std::string>& args);
|
||||
|
||||
static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
|
||||
|
||||
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
|
||||
bool ParseLine(const std::vector<std::string>& args, std::string* err);
|
||||
bool ExecStart(std::unique_ptr<android::base::Timer>* exec_waiter);
|
||||
bool ExecStart();
|
||||
bool Start();
|
||||
bool StartIfNotDisabled();
|
||||
bool Enable();
|
||||
|
@ -87,7 +89,12 @@ class Service {
|
|||
void DumpState() const;
|
||||
void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
|
||||
bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
|
||||
void UnSetExec() { flags_ &= ~SVC_EXEC; }
|
||||
void UnSetExec() {
|
||||
is_exec_service_running_ = false;
|
||||
flags_ &= ~SVC_EXEC;
|
||||
}
|
||||
|
||||
static bool is_exec_service_running() { return is_exec_service_running_; }
|
||||
|
||||
const std::string& name() const { return name_; }
|
||||
const std::set<std::string>& classnames() const { return classnames_; }
|
||||
|
@ -151,6 +158,7 @@ class Service {
|
|||
bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
|
||||
|
||||
static unsigned long next_start_order_;
|
||||
static bool is_exec_service_running_;
|
||||
|
||||
std::string name_;
|
||||
std::set<std::string> classnames_;
|
||||
|
@ -198,45 +206,42 @@ class Service {
|
|||
std::vector<std::string> args_;
|
||||
};
|
||||
|
||||
class ServiceManager {
|
||||
class ServiceList {
|
||||
public:
|
||||
static ServiceManager& GetInstance();
|
||||
static ServiceList& GetInstance();
|
||||
|
||||
// Exposed for testing
|
||||
ServiceManager();
|
||||
ServiceList();
|
||||
|
||||
void AddService(std::unique_ptr<Service> service);
|
||||
Service* MakeExecOneshotService(const std::vector<std::string>& args);
|
||||
bool Exec(const std::vector<std::string>& args);
|
||||
bool ExecStart(const std::string& name);
|
||||
bool IsWaitingForExec() const;
|
||||
Service* FindServiceByName(const std::string& name) const;
|
||||
Service* FindServiceByPid(pid_t pid) const;
|
||||
Service* FindServiceByKeychord(int keychord_id) const;
|
||||
void ForEachService(const std::function<void(Service*)>& callback) const;
|
||||
void ForEachServiceShutdownOrder(const std::function<void(Service*)>& callback) const;
|
||||
void ForEachServiceInClass(const std::string& classname,
|
||||
void (*func)(Service* svc)) const;
|
||||
void ReapAnyOutstandingChildren();
|
||||
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;
|
||||
}
|
||||
|
||||
void DumpState() const;
|
||||
void ClearExecWait();
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
// Cleans up a child process that exited.
|
||||
// Returns true iff a children was cleaned up.
|
||||
bool ReapOneProcess();
|
||||
|
||||
static int exec_count_; // Every service needs a unique name.
|
||||
std::unique_ptr<android::base::Timer> exec_waiter_;
|
||||
|
||||
std::vector<std::unique_ptr<Service>> services_;
|
||||
};
|
||||
|
||||
class ServiceParser : public SectionParser {
|
||||
public:
|
||||
ServiceParser(ServiceManager* service_manager)
|
||||
: service_manager_(service_manager), service_(nullptr) {}
|
||||
ServiceParser(ServiceList* service_list) : service_list_(service_list), service_(nullptr) {}
|
||||
bool ParseSection(std::vector<std::string>&& args, const std::string& filename, int line,
|
||||
std::string* err) override;
|
||||
bool ParseLineSection(std::vector<std::string>&& args, int line, std::string* err) override;
|
||||
|
@ -245,7 +250,7 @@ class ServiceParser : public SectionParser {
|
|||
private:
|
||||
bool IsValidName(const std::string& name) const;
|
||||
|
||||
ServiceManager* service_manager_;
|
||||
ServiceList* service_list_;
|
||||
std::unique_ptr<Service> service_;
|
||||
};
|
||||
|
||||
|
|
|
@ -73,23 +73,21 @@ TEST(service, pod_initialized) {
|
|||
EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
|
||||
}
|
||||
|
||||
TEST(service, make_exec_oneshot_service_invalid_syntax) {
|
||||
ServiceManager& sm = ServiceManager::GetInstance();
|
||||
TEST(service, make_temporary_oneshot_service_invalid_syntax) {
|
||||
std::vector<std::string> args;
|
||||
// Nothing.
|
||||
ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
|
||||
ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
|
||||
|
||||
// No arguments to 'exec'.
|
||||
args.push_back("exec");
|
||||
ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
|
||||
ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
|
||||
|
||||
// No command in "exec --".
|
||||
args.push_back("--");
|
||||
ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
|
||||
ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
|
||||
}
|
||||
|
||||
TEST(service, make_exec_oneshot_service_too_many_supplementary_gids) {
|
||||
ServiceManager& sm = ServiceManager::GetInstance();
|
||||
TEST(service, make_temporary_oneshot_service_too_many_supplementary_gids) {
|
||||
std::vector<std::string> args;
|
||||
args.push_back("exec");
|
||||
args.push_back("seclabel");
|
||||
|
@ -100,12 +98,11 @@ TEST(service, make_exec_oneshot_service_too_many_supplementary_gids) {
|
|||
}
|
||||
args.push_back("--");
|
||||
args.push_back("/system/bin/id");
|
||||
ASSERT_EQ(nullptr, sm.MakeExecOneshotService(args));
|
||||
ASSERT_EQ(nullptr, Service::MakeTemporaryOneshotService(args));
|
||||
}
|
||||
|
||||
static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid,
|
||||
bool supplementary_gids) {
|
||||
ServiceManager& sm = ServiceManager::GetInstance();
|
||||
static void Test_make_temporary_oneshot_service(bool dash_dash, bool seclabel, bool uid, bool gid,
|
||||
bool supplementary_gids) {
|
||||
std::vector<std::string> args;
|
||||
args.push_back("exec");
|
||||
if (seclabel) {
|
||||
|
@ -126,7 +123,7 @@ static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool u
|
|||
}
|
||||
args.push_back("/system/bin/toybox");
|
||||
args.push_back("id");
|
||||
Service* svc = sm.MakeExecOneshotService(args);
|
||||
auto svc = Service::MakeTemporaryOneshotService(args);
|
||||
ASSERT_NE(nullptr, svc);
|
||||
|
||||
if (seclabel) {
|
||||
|
@ -167,28 +164,28 @@ static void Test_make_exec_oneshot_service(bool dash_dash, bool seclabel, bool u
|
|||
ASSERT_EQ("id", svc->args()[1]);
|
||||
}
|
||||
|
||||
TEST(service, make_exec_oneshot_service_with_everything) {
|
||||
Test_make_exec_oneshot_service(true, true, true, true, true);
|
||||
TEST(service, make_temporary_oneshot_service_with_everything) {
|
||||
Test_make_temporary_oneshot_service(true, true, true, true, true);
|
||||
}
|
||||
|
||||
TEST(service, make_exec_oneshot_service_with_seclabel_uid_gid) {
|
||||
Test_make_exec_oneshot_service(true, true, true, true, false);
|
||||
TEST(service, make_temporary_oneshot_service_with_seclabel_uid_gid) {
|
||||
Test_make_temporary_oneshot_service(true, true, true, true, false);
|
||||
}
|
||||
|
||||
TEST(service, make_exec_oneshot_service_with_seclabel_uid) {
|
||||
Test_make_exec_oneshot_service(true, true, true, false, false);
|
||||
TEST(service, make_temporary_oneshot_service_with_seclabel_uid) {
|
||||
Test_make_temporary_oneshot_service(true, true, true, false, false);
|
||||
}
|
||||
|
||||
TEST(service, make_exec_oneshot_service_with_seclabel) {
|
||||
Test_make_exec_oneshot_service(true, true, false, false, false);
|
||||
TEST(service, make_temporary_oneshot_service_with_seclabel) {
|
||||
Test_make_temporary_oneshot_service(true, true, false, false, false);
|
||||
}
|
||||
|
||||
TEST(service, make_exec_oneshot_service_with_just_command) {
|
||||
Test_make_exec_oneshot_service(true, false, false, false, false);
|
||||
TEST(service, make_temporary_oneshot_service_with_just_command) {
|
||||
Test_make_temporary_oneshot_service(true, false, false, false, false);
|
||||
}
|
||||
|
||||
TEST(service, make_exec_oneshot_service_with_just_command_no_dash) {
|
||||
Test_make_exec_oneshot_service(false, false, false, false, false);
|
||||
TEST(service, make_temporary_oneshot_service_with_just_command_no_dash) {
|
||||
Test_make_temporary_oneshot_service(false, false, false, false, false);
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
|
|
|
@ -14,29 +14,94 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "signal_handler.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/chrono_utils.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/scopeguard.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include "init.h"
|
||||
#include "property_service.h"
|
||||
#include "service.h"
|
||||
|
||||
using android::base::StringPrintf;
|
||||
using android::base::boot_clock;
|
||||
using android::base::make_scope_guard;
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
static int signal_write_fd = -1;
|
||||
static int signal_read_fd = -1;
|
||||
|
||||
static bool ReapOneProcess() {
|
||||
siginfo_t siginfo = {};
|
||||
// This returns a zombie pid or informs us that there are no zombies left to be reaped.
|
||||
// It does NOT reap the pid; that is done below.
|
||||
if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {
|
||||
PLOG(ERROR) << "waitid failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pid = siginfo.si_pid;
|
||||
if (pid == 0) return false;
|
||||
|
||||
// At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
|
||||
// whenever the function returns from this point forward.
|
||||
// We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we
|
||||
// want the pid to remain valid throughout that (and potentially future) usages.
|
||||
auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });
|
||||
|
||||
if (PropertyChildReap(pid)) return true;
|
||||
|
||||
Service* service = ServiceList::GetInstance().FindService(pid, &Service::pid);
|
||||
|
||||
std::string name;
|
||||
std::string wait_string;
|
||||
if (service) {
|
||||
name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid);
|
||||
if (service->flags() & SVC_EXEC) {
|
||||
auto exec_duration = boot_clock::now() - service->time_started();
|
||||
auto exec_duration_ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count();
|
||||
wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f);
|
||||
}
|
||||
} else {
|
||||
name = StringPrintf("Untracked pid %d", pid);
|
||||
}
|
||||
|
||||
auto status = siginfo.si_status;
|
||||
if (WIFEXITED(status)) {
|
||||
LOG(INFO) << name << " exited with status " << WEXITSTATUS(status) << wait_string;
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
LOG(INFO) << name << " killed by signal " << WTERMSIG(status) << wait_string;
|
||||
}
|
||||
|
||||
if (!service) return true;
|
||||
|
||||
service->Reap();
|
||||
|
||||
if (service->flags() & SVC_TEMPORARY) {
|
||||
ServiceList::GetInstance().RemoveService(*service);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void handle_signal() {
|
||||
// Clear outstanding requests.
|
||||
char buf[32];
|
||||
read(signal_read_fd, buf, sizeof(buf));
|
||||
|
||||
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
|
||||
ReapAnyOutstandingChildren();
|
||||
}
|
||||
|
||||
static void SIGCHLD_handler(int) {
|
||||
|
@ -45,6 +110,11 @@ static void SIGCHLD_handler(int) {
|
|||
}
|
||||
}
|
||||
|
||||
void ReapAnyOutstandingChildren() {
|
||||
while (ReapOneProcess()) {
|
||||
}
|
||||
}
|
||||
|
||||
void signal_handler_init() {
|
||||
// Create a signalling mechanism for SIGCHLD.
|
||||
int s[2];
|
||||
|
@ -63,7 +133,7 @@ void signal_handler_init() {
|
|||
act.sa_flags = SA_NOCLDSTOP;
|
||||
sigaction(SIGCHLD, &act, 0);
|
||||
|
||||
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
|
||||
ReapAnyOutstandingChildren();
|
||||
|
||||
register_epoll_handler(signal_read_fd, handle_signal);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
void ReapAnyOutstandingChildren();
|
||||
|
||||
void signal_handler_init(void);
|
||||
|
||||
} // namespace init
|
||||
|
|
Loading…
Reference in New Issue