Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f42a767 authored by Daniel Norman's avatar Daniel Norman
Browse files

Checks the interface inheritance hierarchy in init_rc files.

Bug: 118016875
Test: Added 'interface' lines to an init_rc file and observed errors
when misspelled or missing entire inheritance hierarchy.
Change-Id: I681420f15539742d8415808b2a0dcbf0bf6faaf1
parent 6da50e31
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -243,11 +243,12 @@ cc_binary {
    ],
    whole_static_libs: ["libcap"],
    shared_libs: [
        "libprotobuf-cpp-lite",
        "libcutils",
        "libhidl-gen-utils",
        "libprocessgroup",
        "libjsoncpp",
        "liblog",
        "libcutils",
        "libprocessgroup",
        "libprotobuf-cpp-lite",
    ],
    srcs: [
        "action.cpp",
+31 −15
Original line number Diff line number Diff line
@@ -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 @@ passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
    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 @@ int main(int argc, char** argv) {
    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 @@ int main(int argc, char** argv) {
                {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 @@ int main(int argc, char** argv) {
            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 @@ int main(int argc, char** argv) {
    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>());

+34 −6
Original line number Diff line number Diff line
@@ -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 @@ Result<void> ServiceParser::ParseInterface(std::vector<std::string>&& args) {
        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 @@ Result<void> ServiceParser::EndSection() {
        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()) {
+7 −4
Original line number Diff line number Diff line
@@ -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 @@ class ServiceParser : public SectionParser {

    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_;
};