class_start_post_data also starts disabled services.

This keyword was introduced to support restarting services on devices
using APEX and FDE. The current implementation is not a restart, but
rather a 'reset' followed by a 'start', because the real /data must be
mounted in-between those two actions. But we effectively want this to be
a restart, which means that we also want to start 'disabled' services
that were running at the time we called 'class_reset_post_data'.

To implement this, keep track of whether a service was running when its
class was reset at post-data, and start all those services.

Bug: 132592548
Test: manual testing on FDE Taimen
Change-Id: I1e81e2c8e0ab2782150073d74e50e4cd734af7b9
This commit is contained in:
Martijn Coenen 2019-05-15 22:04:13 +02:00
parent 122bf2aedf
commit ebce675b17
4 changed files with 31 additions and 13 deletions

View File

@ -414,7 +414,8 @@ Commands
`class_start_post_data <serviceclass>`
> Like `class_start`, but only considers services that were started
after /data was mounted. Only used for FDE devices.
after /data was mounted, and that were running at the time
`class_reset_post_data` was called. Only used for FDE devices.
`class_stop <serviceclass>`
> Stop and disable all services of the specified class if they are

View File

@ -104,35 +104,36 @@ static void ForEachServiceInClass(const std::string& classname, F function) {
}
}
static Result<Success> class_start(const std::string& class_name, bool post_data_only) {
static Result<Success> do_class_start(const BuiltinArguments& args) {
// Do not start a class if it has a property persist.dont_start_class.CLASS set to 1.
if (android::base::GetBoolProperty("persist.init.dont_start_class." + class_name, false))
if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
return Success();
// Starting a class does not start services which are explicitly disabled.
// They must be started individually.
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(class_name)) {
if (post_data_only && !service->is_post_data()) {
continue;
}
if (service->classnames().count(args[1])) {
if (auto result = service->StartIfNotDisabled(); !result) {
LOG(ERROR) << "Could not start service '" << service->name()
<< "' as part of class '" << class_name << "': " << result.error();
<< "' as part of class '" << args[1] << "': " << result.error();
}
}
}
return Success();
}
static Result<Success> do_class_start(const BuiltinArguments& args) {
return class_start(args[1], false /* post_data_only */);
}
static Result<Success> do_class_start_post_data(const BuiltinArguments& args) {
if (args.context != kInitContext) {
return Error() << "command 'class_start_post_data' only available in init context";
}
return class_start(args[1], true /* post_data_only */);
for (const auto& service : ServiceList::GetInstance()) {
if (service->classnames().count(args[1])) {
if (auto result = service->StartIfPostData(); !result) {
LOG(ERROR) << "Could not start service '" << service->name()
<< "' as part of class '" << args[1] << "': " << result.error();
}
}
}
return Success();
}
static Result<Success> do_class_stop(const BuiltinArguments& args) {

View File

@ -1154,10 +1154,23 @@ void Service::Reset() {
void Service::ResetIfPostData() {
if (post_data_) {
if (flags_ & SVC_RUNNING) {
running_at_post_data_reset_ = true;
}
StopOrReset(SVC_RESET);
}
}
Result<Success> Service::StartIfPostData() {
// Start the service, but only if it was started after /data was mounted,
// and it was still running when we reset the post-data services.
if (running_at_post_data_reset_) {
return Start();
}
return Success();
}
void Service::Stop() {
StopOrReset(SVC_DISABLED);
}

View File

@ -79,6 +79,7 @@ class Service {
Result<Success> ExecStart();
Result<Success> Start();
Result<Success> StartIfNotDisabled();
Result<Success> StartIfPostData();
Result<Success> Enable();
void Reset();
void ResetIfPostData();
@ -248,6 +249,8 @@ class Service {
bool pre_apexd_ = false;
bool post_data_ = false;
bool running_at_post_data_reset_ = false;
};
class ServiceList {