Merge "Checks the interface inheritance hierarchy in init_rc files."
diff --git a/init/Android.bp b/init/Android.bp
index 6985677..ee339dd 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -242,11 +242,12 @@
     ],
     whole_static_libs: ["libcap"],
     shared_libs: [
-        "libprotobuf-cpp-lite",
-        "libhidl-gen-utils",
-        "libprocessgroup",
-        "liblog",
         "libcutils",
+        "libhidl-gen-utils",
+        "libjsoncpp",
+        "liblog",
+        "libprocessgroup",
+        "libprotobuf-cpp-lite",
     ],
     srcs: [
         "action.cpp",
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 8aa3509..92c2aa5 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <fstream>
 #include <iostream>
 #include <iterator>
 #include <string>
@@ -29,6 +30,7 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
+#include <json/json.h>
 
 #include "action.h"
 #include "action_manager.h"
@@ -129,21 +131,33 @@
     return nullptr;
 }
 
-static std::optional<std::set<std::string>> ReadKnownInterfaces(
-        const std::string& known_interfaces_file) {
-    if (known_interfaces_file.empty()) {
-        LOG(WARNING) << "Missing a known interfaces file.";
+static std::optional<android::init::InterfaceInheritanceHierarchyMap>
+ReadInterfaceInheritanceHierarchy(const std::string& interface_inheritance_hierarchy_file) {
+    if (interface_inheritance_hierarchy_file.empty()) {
+        LOG(WARNING) << "Missing an interface inheritance hierarchy file.";
         return {};
     }
 
-    std::string known_interfaces;
-    if (!ReadFileToString(known_interfaces_file, &known_interfaces)) {
-        LOG(ERROR) << "Failed to read known interfaces file '" << known_interfaces_file << "'";
+    Json::Value root;
+    Json::Reader reader;
+    std::ifstream stream(interface_inheritance_hierarchy_file);
+    if (!reader.parse(stream, root)) {
+        LOG(ERROR) << "Failed to read interface inheritance hierarchy file: "
+                   << interface_inheritance_hierarchy_file << "\n"
+                   << reader.getFormattedErrorMessages();
         return {};
     }
 
-    auto interfaces = Split(known_interfaces, " ");
-    return std::set<std::string>(interfaces.begin(), interfaces.end());
+    android::init::InterfaceInheritanceHierarchyMap result;
+    for (const Json::Value& entry : root) {
+        std::set<std::string> inherited_interfaces;
+        for (const Json::Value& intf : entry["inheritedInterfaces"]) {
+            inherited_interfaces.insert(intf.asString());
+        }
+        result[entry["interface"].asString()] = inherited_interfaces;
+    }
+
+    return result;
 }
 
 namespace android {
@@ -169,7 +183,7 @@
     android::base::InitLogging(argv, &android::base::StdioLogger);
     android::base::SetMinimumLogSeverity(android::base::ERROR);
 
-    std::string known_interfaces_file;
+    std::string interface_inheritance_hierarchy_file;
 
     while (true) {
         static const struct option long_options[] = {
@@ -177,7 +191,7 @@
                 {nullptr, 0, nullptr, 0},
         };
 
-        int arg = getopt_long(argc, argv, "p:k:", long_options, nullptr);
+        int arg = getopt_long(argc, argv, "p:i:", long_options, nullptr);
 
         if (arg == -1) {
             break;
@@ -190,8 +204,8 @@
             case 'p':
                 passwd_files.emplace_back(optarg);
                 break;
-            case 'k':
-                known_interfaces_file = optarg;
+            case 'i':
+                interface_inheritance_hierarchy_file = optarg;
                 break;
             default:
                 std::cerr << "getprop: getopt returned invalid result: " << arg << std::endl;
@@ -213,8 +227,10 @@
     ServiceList& sl = ServiceList::GetInstance();
     Parser parser;
     parser.AddSectionParser(
-            "service", std::make_unique<ServiceParser>(&sl, nullptr,
-                                                       ReadKnownInterfaces(known_interfaces_file)));
+            "service",
+            std::make_unique<ServiceParser>(
+                    &sl, nullptr,
+                    ReadInterfaceInheritanceHierarchy(interface_inheritance_hierarchy_file)));
     parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
     parser.AddSectionParser("import", std::make_unique<HostImportParser>());
 
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index ba35104..88ce364 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -18,6 +18,9 @@
 
 #include <linux/input.h>
 
+#include <algorithm>
+#include <sstream>
+
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
@@ -152,12 +155,6 @@
         return Error() << "Interface name must not be a value name '" << interface_name << "'";
     }
 
-    if (known_interfaces_ && known_interfaces_->count(interface_name) == 0) {
-        return Error() << "Interface is not in the known set of hidl_interfaces: '"
-                       << interface_name << "'. Please ensure the interface is built "
-                       << "by a hidl_interface target.";
-    }
-
     const std::string fullname = interface_name + "/" + instance_name;
 
     for (const auto& svc : *service_list_) {
@@ -540,6 +537,37 @@
         return {};
     }
 
+    if (interface_inheritance_hierarchy_) {
+        std::set<std::string> interface_names;
+        for (const std::string& intf : service_->interfaces()) {
+            interface_names.insert(Split(intf, "/")[0]);
+        }
+        std::ostringstream error_stream;
+        for (const std::string& intf : interface_names) {
+            if (interface_inheritance_hierarchy_->count(intf) == 0) {
+                error_stream << "\nInterface is not in the known set of hidl_interfaces: '" << intf
+                             << "'. Please ensure the interface is spelled correctly and built "
+                             << "by a hidl_interface target.";
+                continue;
+            }
+            const std::set<std::string>& required_interfaces =
+                    (*interface_inheritance_hierarchy_)[intf];
+            std::set<std::string> diff;
+            std::set_difference(required_interfaces.begin(), required_interfaces.end(),
+                                interface_names.begin(), interface_names.end(),
+                                std::inserter(diff, diff.begin()));
+            if (!diff.empty()) {
+                error_stream << "\nInterface '" << intf << "' requires its full inheritance "
+                             << "hierarchy to be listed in this init_rc file. Missing "
+                             << "interfaces: [" << base::Join(diff, " ") << "]";
+            }
+        }
+        const std::string& errors = error_stream.str();
+        if (!errors.empty()) {
+            return Error() << errors;
+        }
+    }
+
     Service* old_service = service_list_->FindService(service_->name());
     if (old_service) {
         if (!service_->is_override()) {
diff --git a/init/service_parser.h b/init/service_parser.h
index 5a16768..5ad26ef 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -26,13 +26,16 @@
 namespace android {
 namespace init {
 
+using InterfaceInheritanceHierarchyMap = std::map<std::string, std::set<std::string>>;
+
 class ServiceParser : public SectionParser {
   public:
-    ServiceParser(ServiceList* service_list, std::vector<Subcontext>* subcontexts,
-                  const std::optional<std::set<std::string>>& known_interfaces)
+    ServiceParser(
+            ServiceList* service_list, std::vector<Subcontext>* subcontexts,
+            const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy)
         : service_list_(service_list),
           subcontexts_(subcontexts),
-          known_interfaces_(known_interfaces),
+          interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
           service_(nullptr) {}
     Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
                               int line) override;
@@ -85,7 +88,7 @@
 
     ServiceList* service_list_;
     std::vector<Subcontext>* subcontexts_;
-    std::optional<std::set<std::string>> known_interfaces_;
+    std::optional<InterfaceInheritanceHierarchyMap> interface_inheritance_hierarchy_;
     std::unique_ptr<Service> service_;
     std::string filename_;
 };