init parses *.rc files from APEXes

Init now parses *.rc files from the APEXs when the apexd notifies the
mount event via apexd.status sysprop.

Bug: 117403679
Test: m apex.test; adb root; adb push <builtfile> /data/apex; adb reboot
adb root; adb shell setprop ctl.start apex.test; dmesg shows that init
tries to start the service which doesn't exist.

[   47.979657] init: Could not ctl.start for 'apex.test': Cannot find '/apex/com.android.example.apex/bin/test': No such file or directory

Change-Id: I3f12355346eeb212eca4de85b6b73257283fa054
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 5d62c0b..8660d2a 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <fts.h>
+#include <glob.h>
 #include <linux/loop.h>
 #include <linux/module.h>
 #include <mntent.h>
@@ -1053,6 +1054,38 @@
         {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
 }
 
+static Result<Success> do_parse_apex_configs(const BuiltinArguments& args) {
+    glob_t glob_result;
+    // @ is added to filter out the later paths, which are bind mounts of the places
+    // where the APEXes are really mounted at. Otherwise, we will parse the
+    // same file twice.
+    static constexpr char glob_pattern[] = "/apex/*@*/etc/*.rc";
+    if (glob(glob_pattern, GLOB_MARK, nullptr, &glob_result) != 0) {
+        globfree(&glob_result);
+        return Error() << "glob pattern '" << glob_pattern << "' failed";
+    }
+    std::vector<std::string> configs;
+    Parser parser = CreateServiceOnlyParser(ServiceList::GetInstance());
+    for (size_t i = 0; i < glob_result.gl_pathc; i++) {
+        configs.emplace_back(glob_result.gl_pathv[i]);
+    }
+    globfree(&glob_result);
+
+    bool success = true;
+    for (const auto& c : configs) {
+        if (c.back() == '/') {
+            // skip if directory
+            continue;
+        }
+        success &= parser.ParseConfigFile(c);
+    }
+    if (success) {
+        return Success();
+    } else {
+        return Error() << "Could not parse apex configs";
+    }
+}
+
 // Builtin-function-map start
 const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1090,6 +1123,7 @@
         // mount and umount are run in the same context as mount_all for symmetry.
         {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
         {"mount",                   {3,     kMax, {false,  do_mount}}},
+        {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
         {"readahead",               {1,     2,    {true,   do_readahead}}},
         {"restart",                 {1,     1,    {false,  do_restart}}},