blob: 8ef1ca83d91f9451e562a9b6f057d6d4f84b54c3 [file] [log] [blame]
Yifan Honga72bde72017-09-28 13:36:48 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Yifan Hong69c1b112018-02-27 17:06:00 -080017#include <getopt.h>
Yifan Hong62503e12019-08-26 12:47:41 -070018#include <sysexits.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080019#include <unistd.h>
Yifan Honga72bde72017-09-28 13:36:48 -070020
Yifan Hong69c1b112018-02-27 17:06:00 -080021#include <iostream>
22#include <map>
23
Yifan Hong07292852019-08-21 15:40:30 -070024#include <android-base/file.h>
Yifan Hong6aef2fc2020-01-09 14:41:11 -080025#include <android-base/logging.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080026#include <android-base/parseint.h>
Yifan Hong6e32a5f2020-03-12 16:06:27 -070027#include <android-base/result.h>
Yifan Hong07292852019-08-21 15:40:30 -070028#include <android-base/strings.h>
Yifan Hong28414a12020-03-23 16:32:40 +000029#include <hidl/metadata.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080030#include <utils/Errors.h>
Yifan Hong07292852019-08-21 15:40:30 -070031#include <vintf/KernelConfigParser.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080032#include <vintf/VintfObject.h>
Yifan Hong07292852019-08-21 15:40:30 -070033#include <vintf/parse_string.h>
Yifan Honga72bde72017-09-28 13:36:48 -070034#include <vintf/parse_xml.h>
35#include "utils.h"
36
37namespace android {
38namespace vintf {
Yifan Hong69c1b112018-02-27 17:06:00 -080039namespace details {
Yifan Honga72bde72017-09-28 13:36:48 -070040
Yifan Hong69c1b112018-02-27 17:06:00 -080041// fake sysprops
42using Properties = std::map<std::string, std::string>;
43
Yifan Hong07292852019-08-21 15:40:30 -070044using Dirmap = std::map<std::string, std::string>;
45
Yifan Hong69c1b112018-02-27 17:06:00 -080046enum Option : int {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080047 // Modes
Yifan Hong69c1b112018-02-27 17:06:00 -080048 HELP,
Yifan Hong0dfc3d52020-01-09 14:30:02 -080049 DUMP_FILE_LIST = 1,
Yifan Hong69c1b112018-02-27 17:06:00 -080050 CHECK_COMPAT,
Yifan Hong0dfc3d52020-01-09 14:30:02 -080051 CHECK_ONE,
52
53 // Options
54 ROOTDIR,
55 PROPERTY,
Yifan Hong07292852019-08-21 15:40:30 -070056 DIR_MAP,
57 KERNEL,
Yifan Hong69c1b112018-02-27 17:06:00 -080058};
59// command line arguments
60using Args = std::multimap<Option, std::string>;
61
Yifan Hong07292852019-08-21 15:40:30 -070062class HostFileSystem : public details::FileSystemImpl {
Yifan Hong69c1b112018-02-27 17:06:00 -080063 public:
Yifan Hong0dfc3d52020-01-09 14:30:02 -080064 HostFileSystem(const Dirmap& dirmap, status_t missingError)
65 : mDirMap(dirmap), mMissingError(missingError) {}
Yifan Hong10d86222018-04-06 15:41:05 -070066 status_t fetch(const std::string& path, std::string* fetched,
67 std::string* error) const override {
Yifan Hong6aef2fc2020-01-09 14:41:11 -080068 auto resolved = resolve(path, error);
Yifan Hong07292852019-08-21 15:40:30 -070069 if (resolved.empty()) {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080070 return mMissingError;
Yifan Hong07292852019-08-21 15:40:30 -070071 }
72 status_t status = details::FileSystemImpl::fetch(resolved, fetched, error);
Yifan Hong6aef2fc2020-01-09 14:41:11 -080073 LOG(INFO) << "Fetch '" << resolved << "': " << toString(status);
Yifan Hong10d86222018-04-06 15:41:05 -070074 return status;
Yifan Hong69c1b112018-02-27 17:06:00 -080075 }
Yifan Hong10d86222018-04-06 15:41:05 -070076 status_t listFiles(const std::string& path, std::vector<std::string>* out,
77 std::string* error) const override {
Yifan Hong6aef2fc2020-01-09 14:41:11 -080078 auto resolved = resolve(path, error);
Yifan Hong07292852019-08-21 15:40:30 -070079 if (resolved.empty()) {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080080 return mMissingError;
Yifan Hong07292852019-08-21 15:40:30 -070081 }
82 status_t status = details::FileSystemImpl::listFiles(resolved, out, error);
Yifan Hong6aef2fc2020-01-09 14:41:11 -080083 LOG(INFO) << "List '" << resolved << "': " << toString(status);
Yifan Hong69c1b112018-02-27 17:06:00 -080084 return status;
85 }
86
87 private:
Yifan Hong69c1b112018-02-27 17:06:00 -080088 static std::string toString(status_t status) {
89 return status == OK ? "SUCCESS" : strerror(-status);
90 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -080091 std::string resolve(const std::string& path, std::string* error) const {
Yifan Hong07292852019-08-21 15:40:30 -070092 for (auto [prefix, mappedPath] : mDirMap) {
93 if (path == prefix) {
94 return mappedPath;
95 }
96 if (android::base::StartsWith(path, prefix + "/")) {
97 return mappedPath + "/" + path.substr(prefix.size() + 1);
98 }
99 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800100 if (error) {
101 *error = "Cannot resolve path " + path;
102 } else {
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800103 LOG(mMissingError == NAME_NOT_FOUND ? INFO : ERROR) << "Cannot resolve path " << path;
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800104 }
Yifan Hong07292852019-08-21 15:40:30 -0700105 return "";
106 }
107
108 Dirmap mDirMap;
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800109 status_t mMissingError;
Yifan Hong69c1b112018-02-27 17:06:00 -0800110};
111
112class PresetPropertyFetcher : public PropertyFetcher {
113 public:
114 std::string getProperty(const std::string& key,
115 const std::string& defaultValue) const override {
116 auto it = mProps.find(key);
117 if (it == mProps.end()) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800118 LOG(INFO) << "Sysprop " << key << " is missing, default to '" << defaultValue << "'";
Yifan Hong69c1b112018-02-27 17:06:00 -0800119 return defaultValue;
120 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800121 LOG(INFO) << "Sysprop " << key << "=" << it->second;
Yifan Hong69c1b112018-02-27 17:06:00 -0800122 return it->second;
123 }
124 uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
125 uint64_t max) const override {
126 uint64_t result;
127 std::string value = getProperty(key, "");
128 if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
129 return defaultValue;
130 }
131 bool getBoolProperty(const std::string& key, bool defaultValue) const override {
132 std::string value = getProperty(key, "");
133 if (value == "1" || value == "true") {
134 return true;
135 } else if (value == "0" || value == "false") {
136 return false;
137 }
138 return defaultValue;
139 }
140 void setProperties(const Properties& props) { mProps.insert(props.begin(), props.end()); }
141
142 private:
143 std::map<std::string, std::string> mProps;
144};
145
Yifan Hong07292852019-08-21 15:40:30 -0700146struct StaticRuntimeInfo : public RuntimeInfo {
147 KernelVersion kernelVersion;
148 std::string kernelConfigFile;
149
150 status_t fetchAllInformation(FetchFlags flags) override {
151 if (flags & RuntimeInfo::FetchFlag::CPU_VERSION) {
152 mKernel.mVersion = kernelVersion;
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800153 LOG(INFO) << "fetched kernel version " << kernelVersion;
Yifan Hong07292852019-08-21 15:40:30 -0700154 }
155 if (flags & RuntimeInfo::FetchFlag::CONFIG_GZ) {
156 std::string content;
157 if (!android::base::ReadFileToString(kernelConfigFile, &content)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800158 LOG(ERROR) << "Cannot read " << kernelConfigFile;
Yifan Hong07292852019-08-21 15:40:30 -0700159 return UNKNOWN_ERROR;
160 }
161 KernelConfigParser parser;
162 auto status = parser.processAndFinish(content);
163 if (status != OK) {
164 return status;
165 }
166 mKernel.mConfigs = std::move(parser.configs());
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800167 LOG(INFO) << "read kernel configs from " << kernelConfigFile;
Yifan Hong07292852019-08-21 15:40:30 -0700168 }
169 if (flags & RuntimeInfo::FetchFlag::POLICYVERS) {
170 mKernelSepolicyVersion = SIZE_MAX;
171 }
172 return OK;
173 }
174};
175
176struct StubRuntimeInfo : public RuntimeInfo {
177 status_t fetchAllInformation(FetchFlags) override { return UNKNOWN_ERROR; }
178};
179
180struct StaticRuntimeInfoFactory : public ObjectFactory<RuntimeInfo> {
181 std::shared_ptr<RuntimeInfo> info;
182 StaticRuntimeInfoFactory(std::shared_ptr<RuntimeInfo> i) : info(i) {}
183 std::shared_ptr<RuntimeInfo> make_shared() const override {
184 if (info) return info;
185 return std::make_shared<StubRuntimeInfo>();
186 }
187};
188
Yifan Hong69c1b112018-02-27 17:06:00 -0800189// helper functions
Yifan Honga72bde72017-09-28 13:36:48 -0700190template <typename T>
Yifan Hong9f78c182018-07-12 14:45:52 -0700191std::unique_ptr<T> readObject(FileSystem* fileSystem, const std::string& path,
192 const XmlConverter<T>& converter) {
Yifan Honga72bde72017-09-28 13:36:48 -0700193 std::string xml;
Yifan Hong60217032018-01-08 16:19:42 -0800194 std::string error;
Yifan Hong9f78c182018-07-12 14:45:52 -0700195 status_t err = fileSystem->fetch(path, &xml, &error);
Yifan Honga72bde72017-09-28 13:36:48 -0700196 if (err != OK) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800197 LOG(ERROR) << "Cannot read '" << path << "' (" << strerror(-err) << "): " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700198 return nullptr;
199 }
200 auto ret = std::make_unique<T>();
Yifan Hong94757062018-02-09 16:36:31 -0800201 if (!converter(ret.get(), xml, &error)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800202 LOG(ERROR) << "Cannot parse '" << path << "': " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700203 return nullptr;
204 }
205 return ret;
206}
207
Yifan Hong69c1b112018-02-27 17:06:00 -0800208int checkCompatibilityForFiles(const std::string& manifestPath, const std::string& matrixPath) {
Yifan Hong9f78c182018-07-12 14:45:52 -0700209 auto fileSystem = std::make_unique<FileSystemImpl>();
210 auto manifest = readObject(fileSystem.get(), manifestPath, gHalManifestConverter);
211 auto matrix = readObject(fileSystem.get(), matrixPath, gCompatibilityMatrixConverter);
Yifan Honga72bde72017-09-28 13:36:48 -0700212 if (manifest == nullptr || matrix == nullptr) {
213 return -1;
214 }
215
216 std::string error;
217 if (!manifest->checkCompatibility(*matrix, &error)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800218 LOG(ERROR) << "Incompatible: " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700219 std::cout << "false" << std::endl;
220 return 1;
221 }
222
223 std::cout << "true" << std::endl;
224 return 0;
225}
Yifan Hong69c1b112018-02-27 17:06:00 -0800226
227Args parseArgs(int argc, char** argv) {
228 int longOptFlag;
229 int optionIndex;
230 Args ret;
231 std::vector<struct option> longopts{
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800232 // Modes
Yifan Hong69c1b112018-02-27 17:06:00 -0800233 {"help", no_argument, &longOptFlag, HELP},
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800234 {"dump-file-list", no_argument, &longOptFlag, DUMP_FILE_LIST},
Yifan Hong69c1b112018-02-27 17:06:00 -0800235 {"check-compat", no_argument, &longOptFlag, CHECK_COMPAT},
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800236 {"check-one", no_argument, &longOptFlag, CHECK_ONE},
237 // Options
238 {"rootdir", required_argument, &longOptFlag, ROOTDIR},
239 {"property", required_argument, &longOptFlag, PROPERTY},
Yifan Hong07292852019-08-21 15:40:30 -0700240 {"dirmap", required_argument, &longOptFlag, DIR_MAP},
241 {"kernel", required_argument, &longOptFlag, KERNEL},
Yifan Hong69c1b112018-02-27 17:06:00 -0800242 {0, 0, 0, 0}};
243 std::map<int, Option> shortopts{
244 {'h', HELP}, {'D', PROPERTY}, {'c', CHECK_COMPAT},
245 };
246 for (;;) {
247 int c = getopt_long(argc, argv, "hcD:", longopts.data(), &optionIndex);
248 if (c == -1) {
249 break;
250 }
251 std::string argValue = optarg ? optarg : std::string{};
252 if (c == 0) {
253 ret.emplace(static_cast<Option>(longOptFlag), std::move(argValue));
254 } else {
255 ret.emplace(shortopts[c], std::move(argValue));
256 }
257 }
258 if (optind < argc) {
259 // see non option
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800260 LOG(ERROR) << "unrecognized option `" << argv[optind] << "'";
Yifan Hong69c1b112018-02-27 17:06:00 -0800261 return {{HELP, ""}};
262 }
263 return ret;
264}
265
266template <typename T>
Yifan Hong07292852019-08-21 15:40:30 -0700267std::map<std::string, std::string> splitArgs(const T& args, char split) {
268 std::map<std::string, std::string> ret;
Yifan Hong69c1b112018-02-27 17:06:00 -0800269 for (const auto& arg : args) {
Yifan Hong07292852019-08-21 15:40:30 -0700270 auto pos = arg.find(split);
Yifan Hong69c1b112018-02-27 17:06:00 -0800271 auto key = arg.substr(0, pos);
272 auto value = pos == std::string::npos ? std::string{} : arg.substr(pos + 1);
273 ret[key] = value;
274 }
275 return ret;
276}
Yifan Hong07292852019-08-21 15:40:30 -0700277template <typename T>
278Properties getProperties(const T& args) {
279 return splitArgs(args, '=');
280}
281
282template <typename T>
283Dirmap getDirmap(const T& args) {
284 return splitArgs(args, ':');
285}
286
287template <typename T>
288std::shared_ptr<StaticRuntimeInfo> getRuntimeInfo(const T& args) {
289 auto ret = std::make_shared<StaticRuntimeInfo>();
290 if (std::distance(args.begin(), args.end()) > 1) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800291 LOG(ERROR) << "Can't have multiple --kernel options";
Yifan Hong07292852019-08-21 15:40:30 -0700292 return nullptr;
293 }
294 auto pair = android::base::Split(*args.begin(), ":");
295 if (pair.size() != 2) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800296 LOG(ERROR) << "Invalid --kernel";
Yifan Hong07292852019-08-21 15:40:30 -0700297 return nullptr;
298 }
299 if (!parse(pair[0], &ret->kernelVersion)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800300 LOG(ERROR) << "Cannot parse " << pair[0] << " as kernel version";
Yifan Hong07292852019-08-21 15:40:30 -0700301 return nullptr;
302 }
303 ret->kernelConfigFile = std::move(pair[1]);
304 return ret;
305}
Yifan Hong69c1b112018-02-27 17:06:00 -0800306
307int usage(const char* me) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800308 LOG(ERROR)
Yifan Hong69c1b112018-02-27 17:06:00 -0800309 << me << ": check VINTF metadata." << std::endl
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800310 << " Modes:" << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800311 << " --dump-file-list: Dump a list of directories / files on device" << std::endl
312 << " that is required to be used by --check-compat." << std::endl
313 << " -c, --check-compat: check compatibility for files under the root" << std::endl
314 << " directory specified by --root-dir." << std::endl
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800315 << " --check-one: check consistency of VINTF metadata for a single partition."
316 << std::endl
317 << std::endl
318 << " Options:" << std::endl
Yifan Hong07292852019-08-21 15:40:30 -0700319 << " --rootdir=<dir>: specify root directory for all metadata. Same as " << std::endl
320 << " --dirmap /:<dir>" << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800321 << " -D, --property <key>=<value>: specify sysprops." << std::endl
Yifan Hong07292852019-08-21 15:40:30 -0700322 << " --dirmap </system:/dir/to/system> [--dirmap </vendor:/dir/to/vendor>[...]]"
323 << std::endl
324 << " Map partitions to directories. Cannot be specified with --rootdir."
325 << " --kernel <x.y.z:path/to/config>" << std::endl
326 << " Use the given kernel version and config to check. If" << std::endl
327 << " unspecified, kernel requirements are skipped." << std::endl
328 << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800329 << " --help: show this message." << std::endl
330 << std::endl
331 << " Example:" << std::endl
332 << " # Get the list of required files." << std::endl
333 << " " << me << " --dump-file-list > /tmp/files.txt" << std::endl
334 << " # Pull from ADB, or use your own command to extract files from images"
335 << std::endl
336 << " ROOTDIR=/tmp/device/" << std::endl
337 << " cat /tmp/files.txt | xargs -I{} bash -c \"mkdir -p $ROOTDIR`dirname {}` && adb "
338 "pull {} $ROOTDIR{}\""
339 << std::endl
340 << " # Check compatibility." << std::endl
341 << " " << me << " --check-compat --rootdir=$ROOTDIR \\" << std::endl
342 << " --property ro.product.first_api_level=`adb shell getprop "
343 "ro.product.first_api_level` \\"
344 << std::endl
345 << " --property ro.boot.product.hardware.sku=`adb shell getprop "
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800346 "ro.boot.product.hardware.sku`";
Yifan Hong62503e12019-08-26 12:47:41 -0700347 return EX_USAGE;
Yifan Hong69c1b112018-02-27 17:06:00 -0800348}
349
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700350android::base::Result<void> checkAllFiles(const Dirmap& dirmap, const Properties& props,
351 std::shared_ptr<StaticRuntimeInfo> runtimeInfo) {
Yifan Hong9f78c182018-07-12 14:45:52 -0700352 auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
353 hostPropertyFetcher->setProperties(props);
Yifan Hong07292852019-08-21 15:40:30 -0700354
355 CheckFlags::Type flags = CheckFlags::DEFAULT;
356 if (!runtimeInfo) flags = flags.disableRuntimeInfo();
357
358 auto vintfObject =
359 VintfObject::Builder()
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800360 .setFileSystem(std::make_unique<HostFileSystem>(dirmap, UNKNOWN_ERROR))
Yifan Hong07292852019-08-21 15:40:30 -0700361 .setPropertyFetcher(std::move(hostPropertyFetcher))
362 .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(runtimeInfo))
363 .build();
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700364
365 std::string error;
366 int compatibleResult = vintfObject->checkCompatibility(&error, flags);
367 if (compatibleResult == INCOMPATIBLE) {
368 return android::base::Error() << error;
369 }
370 if (compatibleResult != COMPATIBLE) {
371 return android::base::Error(-compatibleResult) << error;
372 }
373
374 auto hasFcmExt = vintfObject->hasFrameworkCompatibilityMatrixExtensions();
375 if (!hasFcmExt.has_value()) {
376 return hasFcmExt.error();
377 }
Yifan Hong76f85852020-03-23 16:32:40 +0000378 auto deviceManifest = vintfObject->getDeviceHalManifest();
379 if (deviceManifest == nullptr) {
380 return android::base::Error(-NAME_NOT_FOUND) << "No device HAL manifest";
381 }
382 auto targetFcm = deviceManifest->level();
383 if (*hasFcmExt || (targetFcm != Level::UNSPECIFIED && targetFcm >= Level::R)) {
Yifan Hong28414a12020-03-23 16:32:40 +0000384 auto hidlMetadata = HidlInterfaceMetadata::all();
385 return vintfObject->checkUnusedHals(hidlMetadata);
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700386 }
387 LOG(INFO) << "Skip checking unused HALs.";
388 return {};
Yifan Hong69c1b112018-02-27 17:06:00 -0800389}
390
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700391int checkDirmaps(const Dirmap& dirmap, const Properties& props) {
392 auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
393 hostPropertyFetcher->setProperties(props);
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800394 auto exitCode = EX_OK;
395 for (auto&& [prefix, mappedPath] : dirmap) {
396 auto vintfObject =
397 VintfObject::Builder()
398 .setFileSystem(std::make_unique<HostFileSystem>(dirmap, NAME_NOT_FOUND))
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700399 .setPropertyFetcher(std::move(hostPropertyFetcher))
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800400 .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(nullptr))
401 .build();
402
403 if (android::base::StartsWith(prefix, "/system")) {
404 LOG(INFO) << "Checking system manifest.";
405 auto manifest = vintfObject->getFrameworkHalManifest();
406 if (!manifest) {
407 LOG(ERROR) << "Cannot fetch system manifest.";
408 exitCode = EX_SOFTWARE;
409 }
410 LOG(INFO) << "Checking system matrix.";
411 auto matrix = vintfObject->getFrameworkCompatibilityMatrix();
412 if (!matrix) {
413 LOG(ERROR) << "Cannot fetch system matrix.";
414 exitCode = EX_SOFTWARE;
415 }
416 continue;
417 }
418
419 if (android::base::StartsWith(prefix, "/vendor")) {
420 LOG(INFO) << "Checking vendor manifest.";
421 auto manifest = vintfObject->getDeviceHalManifest();
422 if (!manifest) {
423 LOG(ERROR) << "Cannot fetch vendor manifest.";
424 exitCode = EX_SOFTWARE;
425 }
426 LOG(INFO) << "Checking vendor matrix.";
427 auto matrix = vintfObject->getDeviceCompatibilityMatrix();
428 if (!matrix) {
429 LOG(ERROR) << "Cannot fetch vendor matrix.";
430 exitCode = EX_SOFTWARE;
431 }
432 continue;
433 }
434
435 LOG(ERROR) << "--check-one does not work with --dirmap " << prefix;
436 exitCode = EX_SOFTWARE;
437 }
438 return exitCode;
439}
440
Yifan Hong69c1b112018-02-27 17:06:00 -0800441} // namespace details
442} // namespace vintf
443} // namespace android
444
445int main(int argc, char** argv) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800446 android::base::SetLogger(android::base::StderrLogger);
447
Yifan Hong69c1b112018-02-27 17:06:00 -0800448 using namespace android::vintf;
449 using namespace android::vintf::details;
450 // legacy usage: check_vintf <manifest.xml> <matrix.xml>
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800451 if (argc == 3 && *argv[1] != '-' && *argv[2] != '-') {
Yifan Hong69c1b112018-02-27 17:06:00 -0800452 int ret = checkCompatibilityForFiles(argv[1], argv[2]);
453 if (ret >= 0) return ret;
454 }
455
456 Args args = parseArgs(argc, argv);
457
458 if (!iterateValues(args, HELP).empty()) {
459 return usage(argv[0]);
460 }
461
462 if (!iterateValues(args, DUMP_FILE_LIST).empty()) {
463 for (const auto& file : dumpFileList()) {
464 std::cout << file << std::endl;
465 }
466 return 0;
467 }
468
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800469 auto dirmap = getDirmap(iterateValues(args, DIR_MAP));
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700470 auto properties = getProperties(iterateValues(args, PROPERTY));
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800471
472 if (!iterateValues(args, CHECK_ONE).empty()) {
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700473 return checkDirmaps(dirmap, properties);
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800474 }
475
Yifan Hong69c1b112018-02-27 17:06:00 -0800476 auto checkCompat = iterateValues(args, CHECK_COMPAT);
Yifan Hong07292852019-08-21 15:40:30 -0700477 if (checkCompat.empty()) {
478 return usage(argv[0]);
Yifan Hong69c1b112018-02-27 17:06:00 -0800479 }
480
Yifan Hong07292852019-08-21 15:40:30 -0700481 auto rootdirs = iterateValues(args, ROOTDIR);
482 if (!rootdirs.empty()) {
483 if (std::distance(rootdirs.begin(), rootdirs.end()) > 1) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800484 LOG(ERROR) << "Can't have multiple --rootdir options";
Yifan Hong07292852019-08-21 15:40:30 -0700485 return usage(argv[0]);
486 }
487 args.emplace(DIR_MAP, "/:" + *rootdirs.begin());
488 }
489
Yifan Hong07292852019-08-21 15:40:30 -0700490 std::shared_ptr<StaticRuntimeInfo> runtimeInfo;
491 auto kernelArgs = iterateValues(args, KERNEL);
492 if (!kernelArgs.empty()) {
493 runtimeInfo = getRuntimeInfo(kernelArgs);
494 if (runtimeInfo == nullptr) {
495 return usage(argv[0]);
496 }
497 }
498
Yifan Hong07292852019-08-21 15:40:30 -0700499 if (dirmap.empty()) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800500 LOG(ERROR) << "Missing --rootdir or --dirmap option.";
Yifan Hong07292852019-08-21 15:40:30 -0700501 return usage(argv[0]);
502 }
503
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700504 auto compat = checkAllFiles(dirmap, properties, runtimeInfo);
Yifan Hong62503e12019-08-26 12:47:41 -0700505
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700506 if (compat.ok()) {
Yifan Hong62503e12019-08-26 12:47:41 -0700507 std::cout << "COMPATIBLE" << std::endl;
508 return EX_OK;
509 }
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700510 if (compat.error().code() == 0) {
511 LOG(ERROR) << "files are incompatible: " << compat.error();
Yifan Hong62503e12019-08-26 12:47:41 -0700512 std::cout << "INCOMPATIBLE" << std::endl;
513 return EX_DATAERR;
514 }
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700515 LOG(ERROR) << strerror(compat.error().code()) << ": " << compat.error();
Yifan Hong62503e12019-08-26 12:47:41 -0700516 return EX_SOFTWARE;
Yifan Hong69c1b112018-02-27 17:06:00 -0800517}