Use subcontext for APEX configs from /{vendor, odm}

Instead of using config file path, use APEX's preinstalled path to
determine whether to use subcontext or not for APEX configs.

Bug: 232021354
Test: CtsInitTestCases, CtsBluetoothTestCases
Change-Id: Iba603f09602f0bec3113e2be3d15c62055c09e72
diff --git a/init/init.cpp b/init/init.cpp
index fd8ee0f..4955bc5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -85,6 +85,10 @@
 #include "system/core/init/property_service.pb.h"
 #include "util.h"
 
+#ifndef RECOVERY
+#include "com_android_apex.h"
+#endif  // RECOVERY
+
 using namespace std::chrono_literals;
 using namespace std::string_literals;
 
@@ -293,14 +297,58 @@
     return parser;
 }
 
+#ifndef RECOVERY
+template <typename T>
+struct LibXmlErrorHandler {
+    T handler_;
+    template <typename Handler>
+    LibXmlErrorHandler(Handler&& handler) : handler_(std::move(handler)) {
+        xmlSetGenericErrorFunc(nullptr, &ErrorHandler);
+    }
+    ~LibXmlErrorHandler() { xmlSetGenericErrorFunc(nullptr, nullptr); }
+    static void ErrorHandler(void*, const char* msg, ...) {
+        va_list args;
+        va_start(args, msg);
+        char* formatted;
+        if (vasprintf(&formatted, msg, args) >= 0) {
+            LOG(ERROR) << formatted;
+        }
+        free(formatted);
+        va_end(args);
+    }
+};
+
+template <typename Handler>
+LibXmlErrorHandler(Handler&&) -> LibXmlErrorHandler<Handler>;
+#endif  // RECOVERY
+
 // Returns a Parser that accepts scripts from APEX modules. It supports `service` and `on`.
 Parser CreateApexConfigParser(ActionManager& action_manager, ServiceList& service_list) {
     Parser parser;
-
-    parser.AddSectionParser(
-            "service", std::make_unique<ServiceParser>(&service_list, GetSubcontext(), std::nullopt,
-                                                       /*from_apex=*/true));
-    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, GetSubcontext()));
+    auto subcontext = GetSubcontext();
+#ifndef RECOVERY
+    if (subcontext) {
+        const auto apex_info_list_file = "/apex/apex-info-list.xml";
+        auto error_handler = LibXmlErrorHandler([&](const auto& error_message) {
+            LOG(ERROR) << "Failed to read " << apex_info_list_file << ":" << error_message;
+        });
+        const auto apex_info_list = com::android::apex::readApexInfoList(apex_info_list_file);
+        if (apex_info_list.has_value()) {
+            std::vector<std::string> subcontext_apexes;
+            for (const auto& info : apex_info_list->getApexInfo()) {
+                if (info.hasPreinstalledModulePath() &&
+                    subcontext->PathMatchesSubcontext(info.getPreinstalledModulePath())) {
+                    subcontext_apexes.push_back(info.getModuleName());
+                }
+            }
+            subcontext->SetApexList(std::move(subcontext_apexes));
+        }
+    }
+#endif  // RECOVERY
+    parser.AddSectionParser("service",
+                            std::make_unique<ServiceParser>(&service_list, subcontext, std::nullopt,
+                                                            /*from_apex=*/true));
+    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontext));
 
     return parser;
 }
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 7aa4a9d..bb3967e 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -250,7 +250,14 @@
     Fork();
 }
 
-bool Subcontext::PathMatchesSubcontext(const std::string& path) {
+bool Subcontext::PathMatchesSubcontext(const std::string& path) const {
+    static const std::string kApexDir = "/apex/";
+    if (StartsWith(path, kApexDir)) {
+        auto begin = kApexDir.size();
+        auto end = path.find('/', begin);
+        auto apex_name = path.substr(begin, end - begin);
+        return std::find(apex_list_.begin(), apex_list_.end(), apex_name) != apex_list_.end();
+    }
     for (const auto& prefix : path_prefixes_) {
         if (StartsWith(path, prefix)) {
             return true;
@@ -259,6 +266,10 @@
     return false;
 }
 
+void Subcontext::SetApexList(std::vector<std::string>&& apex_list) {
+    apex_list_ = std::move(apex_list);
+}
+
 Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
     if (auto result = SendMessage(socket_, subcontext_command); !result.ok()) {
         Restart();
diff --git a/init/subcontext.h b/init/subcontext.h
index cb4138e..8acc032 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -46,7 +46,8 @@
     Result<void> Execute(const std::vector<std::string>& args);
     Result<std::vector<std::string>> ExpandArgs(const std::vector<std::string>& args);
     void Restart();
-    bool PathMatchesSubcontext(const std::string& path);
+    bool PathMatchesSubcontext(const std::string& path) const;
+    void SetApexList(std::vector<std::string>&& apex_list);
 
     const std::string& context() const { return context_; }
     pid_t pid() const { return pid_; }
@@ -56,6 +57,7 @@
     Result<SubcontextReply> TransmitMessage(const SubcontextCommand& subcontext_command);
 
     std::vector<std::string> path_prefixes_;
+    std::vector<std::string> apex_list_;
     std::string context_;
     pid_t pid_;
     android::base::unique_fd socket_;