Merge "Adds check_interface_{restart,start,stop} check_builtins."
This commit is contained in:
commit
0d061b258a
8 changed files with 244 additions and 65 deletions
|
|
@ -83,6 +83,7 @@ cc_defaults {
|
|||
"libfscrypt",
|
||||
"libgsi",
|
||||
"libhidl-gen-utils",
|
||||
"libjsoncpp",
|
||||
"libkeyutils",
|
||||
"liblog",
|
||||
"liblogwrap",
|
||||
|
|
@ -118,6 +119,7 @@ cc_library_static {
|
|||
"first_stage_mount.cpp",
|
||||
"import_parser.cpp",
|
||||
"init.cpp",
|
||||
"interface_utils.cpp",
|
||||
"keychords.cpp",
|
||||
"modalias_handler.cpp",
|
||||
"mount_handler.cpp",
|
||||
|
|
@ -242,7 +244,10 @@ genrule {
|
|||
name: "generated_stub_builtin_function_map",
|
||||
tool_files: ["host_builtin_map.py"],
|
||||
out: ["generated_stub_builtin_function_map.h"],
|
||||
srcs: ["builtins.cpp", "check_builtins.cpp"],
|
||||
srcs: [
|
||||
"builtins.cpp",
|
||||
"check_builtins.cpp",
|
||||
],
|
||||
cmd: "$(location host_builtin_map.py) --builtins $(location builtins.cpp) --check_builtins $(location check_builtins.cpp) > $(out)",
|
||||
}
|
||||
|
||||
|
|
@ -278,6 +283,7 @@ cc_binary {
|
|||
"epoll.cpp",
|
||||
"keychords.cpp",
|
||||
"import_parser.cpp",
|
||||
"interface_utils.cpp",
|
||||
"host_import_parser.cpp",
|
||||
"host_init_verifier.cpp",
|
||||
"parser.cpp",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <android-base/strings.h>
|
||||
|
||||
#include "builtin_arguments.h"
|
||||
#include "interface_utils.h"
|
||||
#include "rlimit_parser.h"
|
||||
#include "service.h"
|
||||
#include "util.h"
|
||||
|
|
@ -80,6 +81,21 @@ Result<void> check_exec_background(const BuiltinArguments& args) {
|
|||
return check_exec(std::move(args));
|
||||
}
|
||||
|
||||
Result<void> check_interface_restart(const BuiltinArguments& args) {
|
||||
if (auto result = IsKnownInterface(args[1]); !result) {
|
||||
return result.error();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> check_interface_start(const BuiltinArguments& args) {
|
||||
return check_interface_restart(std::move(args));
|
||||
}
|
||||
|
||||
Result<void> check_interface_stop(const BuiltinArguments& args) {
|
||||
return check_interface_restart(std::move(args));
|
||||
}
|
||||
|
||||
Result<void> check_load_system_props(const BuiltinArguments& args) {
|
||||
return Error() << "'load_system_props' is deprecated";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ namespace init {
|
|||
Result<void> check_chown(const BuiltinArguments& args);
|
||||
Result<void> check_exec(const BuiltinArguments& args);
|
||||
Result<void> check_exec_background(const BuiltinArguments& args);
|
||||
Result<void> check_interface_restart(const BuiltinArguments& args);
|
||||
Result<void> check_interface_start(const BuiltinArguments& args);
|
||||
Result<void> check_interface_stop(const BuiltinArguments& args);
|
||||
Result<void> check_load_system_props(const BuiltinArguments& args);
|
||||
Result<void> check_loglevel(const BuiltinArguments& args);
|
||||
Result<void> check_mkdir(const BuiltinArguments& args);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#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"
|
||||
|
|
@ -38,6 +37,7 @@
|
|||
#include "check_builtins.h"
|
||||
#include "host_import_parser.h"
|
||||
#include "host_init_stubs.h"
|
||||
#include "interface_utils.h"
|
||||
#include "parser.h"
|
||||
#include "result.h"
|
||||
#include "service.h"
|
||||
|
|
@ -132,35 +132,6 @@ passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
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 {
|
||||
namespace init {
|
||||
|
||||
|
|
@ -222,16 +193,21 @@ int main(int argc, char** argv) {
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto interface_inheritance_hierarchy_map =
|
||||
ReadInterfaceInheritanceHierarchy(interface_inheritance_hierarchy_file);
|
||||
if (!interface_inheritance_hierarchy_map) {
|
||||
LOG(ERROR) << interface_inheritance_hierarchy_map.error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
SetKnownInterfaces(*interface_inheritance_hierarchy_map);
|
||||
|
||||
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
|
||||
Action::set_function_map(&function_map);
|
||||
ActionManager& am = ActionManager::GetInstance();
|
||||
ServiceList& sl = ServiceList::GetInstance();
|
||||
Parser parser;
|
||||
parser.AddSectionParser(
|
||||
"service",
|
||||
std::make_unique<ServiceParser>(
|
||||
&sl, nullptr,
|
||||
ReadInterfaceInheritanceHierarchy(interface_inheritance_hierarchy_file)));
|
||||
parser.AddSectionParser("service", std::make_unique<ServiceParser>(
|
||||
&sl, nullptr, *interface_inheritance_hierarchy_map));
|
||||
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
|
||||
parser.AddSectionParser("import", std::make_unique<HostImportParser>());
|
||||
|
||||
|
|
|
|||
149
init/interface_utils.cpp
Normal file
149
init/interface_utils.cpp
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "interface_utils.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <android-base/strings.h>
|
||||
#include <hidl-util/FqInstance.h>
|
||||
#include <json/json.h>
|
||||
|
||||
using android::FqInstance;
|
||||
using android::FQName;
|
||||
using android::base::Error;
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string FQNamesToString(const std::set<FQName>& fqnames) {
|
||||
std::set<std::string> fqname_strings;
|
||||
for (const FQName& fqname : fqnames) {
|
||||
fqname_strings.insert(fqname.string());
|
||||
}
|
||||
return android::base::Join(fqname_strings, " ");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result<InterfaceInheritanceHierarchyMap> ReadInterfaceInheritanceHierarchy(
|
||||
const std::string& path) {
|
||||
Json::Value root;
|
||||
Json::Reader reader;
|
||||
std::ifstream stream(path);
|
||||
if (!reader.parse(stream, root)) {
|
||||
return Error() << "Failed to read interface inheritance hierarchy file: " << path << "\n"
|
||||
<< reader.getFormattedErrorMessages();
|
||||
}
|
||||
|
||||
InterfaceInheritanceHierarchyMap result;
|
||||
for (const Json::Value& entry : root) {
|
||||
std::set<FQName> inherited_interfaces;
|
||||
for (const Json::Value& intf : entry["inheritedInterfaces"]) {
|
||||
FQName fqname;
|
||||
if (!fqname.setTo(intf.asString())) {
|
||||
return Error() << "Unable to parse interface '" << intf.asString() << "'";
|
||||
}
|
||||
inherited_interfaces.insert(fqname);
|
||||
}
|
||||
std::string intf_string = entry["interface"].asString();
|
||||
FQName fqname;
|
||||
if (!fqname.setTo(intf_string)) {
|
||||
return Error() << "Unable to parse interface '" << intf_string << "'";
|
||||
}
|
||||
result[fqname] = inherited_interfaces;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<void> CheckInterfaceInheritanceHierarchy(const std::set<std::string>& instances,
|
||||
const InterfaceInheritanceHierarchyMap& hierarchy) {
|
||||
std::set<FQName> interface_fqnames;
|
||||
for (const std::string& instance : instances) {
|
||||
FqInstance fqinstance;
|
||||
if (!fqinstance.setTo(instance)) {
|
||||
return Error() << "Unable to parse interface instance '" << instance << "'";
|
||||
}
|
||||
interface_fqnames.insert(fqinstance.getFqName());
|
||||
}
|
||||
return CheckInterfaceInheritanceHierarchy(interface_fqnames, hierarchy);
|
||||
}
|
||||
|
||||
Result<void> CheckInterfaceInheritanceHierarchy(const std::set<FQName>& interfaces,
|
||||
const InterfaceInheritanceHierarchyMap& hierarchy) {
|
||||
std::ostringstream error_stream;
|
||||
for (const FQName& intf : interfaces) {
|
||||
if (hierarchy.count(intf) == 0) {
|
||||
error_stream << "\nInterface is not in the known set of hidl_interfaces: '"
|
||||
<< intf.string()
|
||||
<< "'. Please ensure the interface is spelled correctly and built "
|
||||
<< "by a hidl_interface target.";
|
||||
continue;
|
||||
}
|
||||
const std::set<FQName>& required_interfaces = hierarchy.at(intf);
|
||||
std::set<FQName> diff;
|
||||
std::set_difference(required_interfaces.begin(), required_interfaces.end(),
|
||||
interfaces.begin(), interfaces.end(),
|
||||
std::inserter(diff, diff.begin()));
|
||||
if (!diff.empty()) {
|
||||
error_stream << "\nInterface '" << intf.string() << "' requires its full inheritance "
|
||||
<< "hierarchy to be listed in this init_rc file. Missing "
|
||||
<< "interfaces: [" << FQNamesToString(diff) << "]";
|
||||
}
|
||||
}
|
||||
const std::string& errors = error_stream.str();
|
||||
if (!errors.empty()) {
|
||||
return Error() << errors;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::set<FQName>> known_interfaces;
|
||||
|
||||
void SetKnownInterfaces(const InterfaceInheritanceHierarchyMap& hierarchy) {
|
||||
known_interfaces = std::set<FQName>();
|
||||
for (const auto& [intf, inherited_interfaces] : hierarchy) {
|
||||
known_interfaces->insert(intf);
|
||||
}
|
||||
}
|
||||
|
||||
Result<void> IsKnownInterface(const std::string& instance) {
|
||||
FqInstance fqinstance;
|
||||
if (!fqinstance.setTo(instance)) {
|
||||
return Error() << "Unable to parse interface instance '" << instance << "'";
|
||||
}
|
||||
return IsKnownInterface(fqinstance.getFqName());
|
||||
}
|
||||
|
||||
Result<void> IsKnownInterface(const FQName& intf) {
|
||||
if (!known_interfaces) {
|
||||
return Error() << "No known interfaces have been loaded.";
|
||||
}
|
||||
if (known_interfaces->count(intf) == 0) {
|
||||
return Error() << "Interface is not in the known set of hidl_interfaces: '" << intf.string()
|
||||
<< "'. Please ensure the interface is spelled correctly and built "
|
||||
<< "by a hidl_interface target.";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
53
init/interface_utils.h
Normal file
53
init/interface_utils.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <hidl-util/FQName.h>
|
||||
|
||||
#include "result.h"
|
||||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
using InterfaceInheritanceHierarchyMap = std::map<android::FQName, std::set<android::FQName>>;
|
||||
|
||||
// Reads the HIDL interface inheritance hierarchy JSON file at the given path.
|
||||
Result<InterfaceInheritanceHierarchyMap> ReadInterfaceInheritanceHierarchy(const std::string& path);
|
||||
|
||||
// For the given set of interfaces / interface instances, checks that each
|
||||
// interface's hierarchy of inherited interfaces is also included in the given
|
||||
// interface set. Uses the provided hierarchy data.
|
||||
Result<void> CheckInterfaceInheritanceHierarchy(const std::set<std::string>& instances,
|
||||
const InterfaceInheritanceHierarchyMap& hierarchy);
|
||||
Result<void> CheckInterfaceInheritanceHierarchy(const std::set<android::FQName>& interfaces,
|
||||
const InterfaceInheritanceHierarchyMap& hierarchy);
|
||||
|
||||
// Saves the set of known interfaces using the provided HIDL interface
|
||||
// inheritance hierarchy.
|
||||
void SetKnownInterfaces(const InterfaceInheritanceHierarchyMap& hierarchy);
|
||||
|
||||
// Checks if the provided interface is in the set of known interfaces. Returns
|
||||
// an empty Result if present, otherwise an Error.
|
||||
Result<void> IsKnownInterface(const std::string& instance);
|
||||
Result<void> IsKnownInterface(const FQName& intf);
|
||||
|
||||
} // namespace init
|
||||
} // namespace android
|
||||
|
|
@ -568,33 +568,10 @@ Result<void> ServiceParser::EndSection() {
|
|||
}
|
||||
|
||||
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;
|
||||
if (const auto& check_hierarchy_result = CheckInterfaceInheritanceHierarchy(
|
||||
service_->interfaces(), *interface_inheritance_hierarchy_);
|
||||
!check_hierarchy_result) {
|
||||
return Error() << check_hierarchy_result.error();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "interface_utils.h"
|
||||
#include "parser.h"
|
||||
#include "service.h"
|
||||
#include "service_list.h"
|
||||
|
|
@ -26,8 +27,6 @@
|
|||
namespace android {
|
||||
namespace init {
|
||||
|
||||
using InterfaceInheritanceHierarchyMap = std::map<std::string, std::set<std::string>>;
|
||||
|
||||
class ServiceParser : public SectionParser {
|
||||
public:
|
||||
ServiceParser(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue