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
This commit is contained in:
parent
6da50e319c
commit
3f42a767cd
|
@ -243,11 +243,12 @@ cc_binary {
|
|||
],
|
||||
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",
|
||||
|
|
|
@ -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>());
|
||||
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue