diff options
author | Daniel Norman <danielnorman@google.com> | 2019-07-09 11:00:53 -0700 |
---|---|---|
committer | Daniel Norman <danielnorman@google.com> | 2019-07-11 14:43:11 -0700 |
commit | 3f42a767cd478de9cac764d91a2318d86f0671c2 (patch) | |
tree | e7b14913c9fc395def6e5c0f70a3df888aae716a | |
parent | 6da50e319c159e276c6186b319c71b80a5d6998e (diff) |
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
-rw-r--r-- | init/Android.bp | 7 | ||||
-rw-r--r-- | init/host_init_verifier.cpp | 46 | ||||
-rw-r--r-- | init/service_parser.cpp | 40 | ||||
-rw-r--r-- | init/service_parser.h | 11 |
4 files changed, 76 insertions, 28 deletions
diff --git a/init/Android.bp b/init/Android.bp index 86dcb4ca7..1081bdb79 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -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", diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp index 8aa350950..92c2aa52e 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 @@ 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>()); diff --git a/init/service_parser.cpp b/init/service_parser.cpp index ba351046a..88ce364c4 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 @@ 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()) { diff --git a/init/service_parser.h b/init/service_parser.h index 5a1676803..5ad26ef6c 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 @@ 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_; }; |