checkvintf: add --dirmap and --kernel options
Add these options so that checkvintf can run against a target
files package.
Bug: 131425279
Test: build/make/tools/releasetools/check_target_files_vintf.py
Change-Id: I82ecefda98caf2f0d3df314e8be14f7f525454ab
diff --git a/check_vintf.cpp b/check_vintf.cpp
index c605053..e2fdb58 100644
--- a/check_vintf.cpp
+++ b/check_vintf.cpp
@@ -20,9 +20,13 @@
#include <iostream>
#include <map>
+#include <android-base/file.h>
#include <android-base/parseint.h>
+#include <android-base/strings.h>
#include <utils/Errors.h>
+#include <vintf/KernelConfigParser.h>
#include <vintf/VintfObject.h>
+#include <vintf/parse_string.h>
#include <vintf/parse_xml.h>
#include "utils.h"
@@ -33,31 +37,43 @@
// fake sysprops
using Properties = std::map<std::string, std::string>;
+using Dirmap = std::map<std::string, std::string>;
+
enum Option : int {
DUMP_FILE_LIST = 1,
ROOTDIR,
HELP,
PROPERTY,
CHECK_COMPAT,
+ DIR_MAP,
+ KERNEL,
};
// command line arguments
using Args = std::multimap<Option, std::string>;
-class HostFileSystem : public FileSystemUnderPath {
+class HostFileSystem : public details::FileSystemImpl {
public:
- HostFileSystem(const std::string& rootdir) : FileSystemUnderPath(rootdir) {}
+ HostFileSystem(const Dirmap& dirmap) : mDirMap(dirmap) {}
status_t fetch(const std::string& path, std::string* fetched,
std::string* error) const override {
- status_t status = FileSystemUnderPath::fetch(path, fetched, error);
- std::cerr << "Debug: Fetch '" << getRootDir() << path << "': " << toString(status)
- << std::endl;
+ auto resolved = resolve(path);
+ if (resolved.empty()) {
+ std::cerr << "Error: Cannot resolve path " << path;
+ return UNKNOWN_ERROR;
+ }
+ status_t status = details::FileSystemImpl::fetch(resolved, fetched, error);
+ std::cerr << "Debug: Fetch '" << resolved << "': " << toString(status) << std::endl;
return status;
}
status_t listFiles(const std::string& path, std::vector<std::string>* out,
std::string* error) const override {
- status_t status = FileSystemUnderPath::listFiles(path, out, error);
- std::cerr << "Debug: List '" << getRootDir() << path << "': " << toString(status)
- << std::endl;
+ auto resolved = resolve(path);
+ if (resolved.empty()) {
+ std::cerr << "Error: Cannot resolve path " << path;
+ return UNKNOWN_ERROR;
+ }
+ status_t status = details::FileSystemImpl::listFiles(resolved, out, error);
+ std::cerr << "Debug: List '" << resolved << "': " << toString(status) << std::endl;
return status;
}
@@ -65,6 +81,19 @@
static std::string toString(status_t status) {
return status == OK ? "SUCCESS" : strerror(-status);
}
+ std::string resolve(const std::string& path) const {
+ for (auto [prefix, mappedPath] : mDirMap) {
+ if (path == prefix) {
+ return mappedPath;
+ }
+ if (android::base::StartsWith(path, prefix + "/")) {
+ return mappedPath + "/" + path.substr(prefix.size() + 1);
+ }
+ }
+ return "";
+ }
+
+ Dirmap mDirMap;
};
class PresetPropertyFetcher : public PropertyFetcher {
@@ -102,6 +131,49 @@
std::map<std::string, std::string> mProps;
};
+struct StaticRuntimeInfo : public RuntimeInfo {
+ KernelVersion kernelVersion;
+ std::string kernelConfigFile;
+
+ status_t fetchAllInformation(FetchFlags flags) override {
+ if (flags & RuntimeInfo::FetchFlag::CPU_VERSION) {
+ mKernel.mVersion = kernelVersion;
+ std::cerr << "Debug: fetched kernel version " << kernelVersion << std::endl;
+ }
+ if (flags & RuntimeInfo::FetchFlag::CONFIG_GZ) {
+ std::string content;
+ if (!android::base::ReadFileToString(kernelConfigFile, &content)) {
+ std::cerr << "Error: Cannot read " << kernelConfigFile << std::endl;
+ return UNKNOWN_ERROR;
+ }
+ KernelConfigParser parser;
+ auto status = parser.processAndFinish(content);
+ if (status != OK) {
+ return status;
+ }
+ mKernel.mConfigs = std::move(parser.configs());
+ std::cerr << "Debug: read kernel configs from " << kernelConfigFile << std::endl;
+ }
+ if (flags & RuntimeInfo::FetchFlag::POLICYVERS) {
+ mKernelSepolicyVersion = SIZE_MAX;
+ }
+ return OK;
+ }
+};
+
+struct StubRuntimeInfo : public RuntimeInfo {
+ status_t fetchAllInformation(FetchFlags) override { return UNKNOWN_ERROR; }
+};
+
+struct StaticRuntimeInfoFactory : public ObjectFactory<RuntimeInfo> {
+ std::shared_ptr<RuntimeInfo> info;
+ StaticRuntimeInfoFactory(std::shared_ptr<RuntimeInfo> i) : info(i) {}
+ std::shared_ptr<RuntimeInfo> make_shared() const override {
+ if (info) return info;
+ return std::make_shared<StubRuntimeInfo>();
+ }
+};
+
// helper functions
template <typename T>
std::unique_ptr<T> readObject(FileSystem* fileSystem, const std::string& path,
@@ -151,6 +223,8 @@
{"help", no_argument, &longOptFlag, HELP},
{"property", required_argument, &longOptFlag, PROPERTY},
{"check-compat", no_argument, &longOptFlag, CHECK_COMPAT},
+ {"dirmap", required_argument, &longOptFlag, DIR_MAP},
+ {"kernel", required_argument, &longOptFlag, KERNEL},
{0, 0, 0, 0}};
std::map<int, Option> shortopts{
{'h', HELP}, {'D', PROPERTY}, {'c', CHECK_COMPAT},
@@ -176,16 +250,45 @@
}
template <typename T>
-Properties getProperties(const T& args) {
- Properties ret;
+std::map<std::string, std::string> splitArgs(const T& args, char split) {
+ std::map<std::string, std::string> ret;
for (const auto& arg : args) {
- auto pos = arg.find('=');
+ auto pos = arg.find(split);
auto key = arg.substr(0, pos);
auto value = pos == std::string::npos ? std::string{} : arg.substr(pos + 1);
ret[key] = value;
}
return ret;
}
+template <typename T>
+Properties getProperties(const T& args) {
+ return splitArgs(args, '=');
+}
+
+template <typename T>
+Dirmap getDirmap(const T& args) {
+ return splitArgs(args, ':');
+}
+
+template <typename T>
+std::shared_ptr<StaticRuntimeInfo> getRuntimeInfo(const T& args) {
+ auto ret = std::make_shared<StaticRuntimeInfo>();
+ if (std::distance(args.begin(), args.end()) > 1) {
+ std::cerr << "Error: Can't have multiple --kernel options" << std::endl;
+ return nullptr;
+ }
+ auto pair = android::base::Split(*args.begin(), ":");
+ if (pair.size() != 2) {
+ std::cerr << "Error: Invalid --kernel" << std::endl;
+ return nullptr;
+ }
+ if (!parse(pair[0], &ret->kernelVersion)) {
+ std::cerr << "Error: Cannot parse " << pair[0] << " as kernel version" << std::endl;
+ return nullptr;
+ }
+ ret->kernelConfigFile = std::move(pair[1]);
+ return ret;
+}
int usage(const char* me) {
std::cerr
@@ -195,8 +298,16 @@
<< " that is required to be used by --check-compat." << std::endl
<< " -c, --check-compat: check compatibility for files under the root" << std::endl
<< " directory specified by --root-dir." << std::endl
- << " --rootdir=<dir>: specify root directory for all metadata." << std::endl
+ << " --rootdir=<dir>: specify root directory for all metadata. Same as " << std::endl
+ << " --dirmap /:<dir>" << std::endl
<< " -D, --property <key>=<value>: specify sysprops." << std::endl
+ << " --dirmap </system:/dir/to/system> [--dirmap </vendor:/dir/to/vendor>[...]]"
+ << std::endl
+ << " Map partitions to directories. Cannot be specified with --rootdir."
+ << " --kernel <x.y.z:path/to/config>" << std::endl
+ << " Use the given kernel version and config to check. If" << std::endl
+ << " unspecified, kernel requirements are skipped." << std::endl
+ << std::endl
<< " --help: show this message." << std::endl
<< std::endl
<< " Example:" << std::endl
@@ -219,14 +330,21 @@
return 1;
}
-int checkAllFiles(const std::string& rootdir, const Properties& props, std::string* error) {
+int checkAllFiles(const Dirmap& dirmap, const Properties& props,
+ std::shared_ptr<StaticRuntimeInfo> runtimeInfo, std::string* error) {
auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
hostPropertyFetcher->setProperties(props);
- auto vintfObject = VintfObject::Builder()
- .setFileSystem(std::make_unique<HostFileSystem>(rootdir))
- .setPropertyFetcher(std::move(hostPropertyFetcher))
- .build();
- return vintfObject->checkCompatibility(error, CheckFlags::DISABLE_RUNTIME_INFO);
+
+ CheckFlags::Type flags = CheckFlags::DEFAULT;
+ if (!runtimeInfo) flags = flags.disableRuntimeInfo();
+
+ auto vintfObject =
+ VintfObject::Builder()
+ .setFileSystem(std::make_unique<HostFileSystem>(dirmap))
+ .setPropertyFetcher(std::move(hostPropertyFetcher))
+ .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(runtimeInfo))
+ .build();
+ return vintfObject->checkCompatibility(error, flags);
}
} // namespace details
@@ -255,32 +373,44 @@
return 0;
}
- auto rootdirs = iterateValues(args, ROOTDIR);
- auto properties = getProperties(iterateValues(args, PROPERTY));
-
auto checkCompat = iterateValues(args, CHECK_COMPAT);
- if (!checkCompat.empty()) {
- if (rootdirs.empty()) {
- std::cerr << "Missing --rootdir option." << std::endl;
- return usage(argv[0]);
- }
- int ret = COMPATIBLE;
- for (const auto& rootdir : rootdirs) {
- std::cerr << "Debug: checking files under " << rootdir << "..." << std::endl;
- std::string error;
- int compat = checkAllFiles(rootdir, properties, &error);
- std::cerr << "Debug: files under " << rootdir
- << (compat == COMPATIBLE
- ? " is compatible"
- : compat == INCOMPATIBLE ? " are incompatible"
- : (" has encountered an error: " + error))
- << std::endl;
- }
- if (ret == COMPATIBLE) {
- std::cout << "true" << std::endl;
- }
- return ret;
+ if (checkCompat.empty()) {
+ return usage(argv[0]);
}
- return usage(argv[0]);
+ auto rootdirs = iterateValues(args, ROOTDIR);
+ if (!rootdirs.empty()) {
+ if (std::distance(rootdirs.begin(), rootdirs.end()) > 1) {
+ std::cerr << "Error: Can't have multiple --rootdir options" << std::endl;
+ return usage(argv[0]);
+ }
+ args.emplace(DIR_MAP, "/:" + *rootdirs.begin());
+ }
+
+ auto properties = getProperties(iterateValues(args, PROPERTY));
+ auto dirmap = getDirmap(iterateValues(args, DIR_MAP));
+
+ std::shared_ptr<StaticRuntimeInfo> runtimeInfo;
+ auto kernelArgs = iterateValues(args, KERNEL);
+ if (!kernelArgs.empty()) {
+ runtimeInfo = getRuntimeInfo(kernelArgs);
+ if (runtimeInfo == nullptr) {
+ return usage(argv[0]);
+ }
+ }
+
+ std::string error;
+ if (dirmap.empty()) {
+ std::cerr << "Missing --rootdir or --dirmap option." << std::endl;
+ return usage(argv[0]);
+ }
+
+ int compat = checkAllFiles(dirmap, properties, runtimeInfo, &error);
+ std::cerr << "Debug: "
+ << (compat == COMPATIBLE
+ ? "files are compatible"
+ : compat == INCOMPATIBLE ? "files are incompatible"
+ : ("Encountered an error: " + error))
+ << std::endl;
+ return compat;
}