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
Merged-In: I1e81e2c8e0ab2782150073d74e50e4cd734af7b9
diff --git a/init/README.md b/init/README.md
index c4505fe..806bfa7 100644
--- a/init/README.md
+++ b/init/README.md
@@ -414,7 +414,8 @@
 
 `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
diff --git a/init/builtins.cpp b/init/builtins.cpp
index ba1c94d..6ce7736 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -104,35 +104,36 @@
     }
 }
 
-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) {
diff --git a/init/service.cpp b/init/service.cpp
index 2f96681..ccc37b7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -1154,10 +1154,23 @@
 
 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);
 }
diff --git a/init/service.h b/init/service.h
index dc2b128..ae29f28 100644
--- a/init/service.h
+++ b/init/service.h
@@ -79,6 +79,7 @@
     Result<Success> ExecStart();
     Result<Success> Start();
     Result<Success> StartIfNotDisabled();
+    Result<Success> StartIfPostData();
     Result<Success> Enable();
     void Reset();
     void ResetIfPostData();
@@ -248,6 +249,8 @@
     bool pre_apexd_ = false;
 
     bool post_data_ = false;
+
+    bool running_at_post_data_reset_ = false;
 };
 
 class ServiceList {