blob: d38d1368ca222579c0d642f8c6c3ebc6c1c31ef6 [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>
Yifan Hongb67b9472020-04-07 14:27:00 -070023#include <optional>
Yifan Hong69c1b112018-02-27 17:06:00 -080024
Yifan Hong07292852019-08-21 15:40:30 -070025#include <android-base/file.h>
Yifan Hong6aef2fc2020-01-09 14:41:11 -080026#include <android-base/logging.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080027#include <android-base/parseint.h>
Yifan Hong6e32a5f2020-03-12 16:06:27 -070028#include <android-base/result.h>
Yifan Hong07292852019-08-21 15:40:30 -070029#include <android-base/strings.h>
Yifan Hong28414a12020-03-23 16:32:40 +000030#include <hidl/metadata.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080031#include <utils/Errors.h>
Yifan Hong07292852019-08-21 15:40:30 -070032#include <vintf/KernelConfigParser.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080033#include <vintf/VintfObject.h>
Yifan Hong07292852019-08-21 15:40:30 -070034#include <vintf/parse_string.h>
Yifan Honga72bde72017-09-28 13:36:48 -070035#include <vintf/parse_xml.h>
36#include "utils.h"
37
38namespace android {
39namespace vintf {
Yifan Hong69c1b112018-02-27 17:06:00 -080040namespace details {
Yifan Honga72bde72017-09-28 13:36:48 -070041
Yifan Hong69c1b112018-02-27 17:06:00 -080042// fake sysprops
43using Properties = std::map<std::string, std::string>;
44
Yifan Hong07292852019-08-21 15:40:30 -070045using Dirmap = std::map<std::string, std::string>;
46
Yifan Hong69c1b112018-02-27 17:06:00 -080047enum Option : int {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080048 // Modes
Yifan Hong69c1b112018-02-27 17:06:00 -080049 HELP,
Yifan Hong0dfc3d52020-01-09 14:30:02 -080050 DUMP_FILE_LIST = 1,
Yifan Hong69c1b112018-02-27 17:06:00 -080051 CHECK_COMPAT,
Yifan Hong0dfc3d52020-01-09 14:30:02 -080052 CHECK_ONE,
53
54 // Options
55 ROOTDIR,
56 PROPERTY,
Yifan Hong07292852019-08-21 15:40:30 -070057 DIR_MAP,
58 KERNEL,
Yifan Hong69c1b112018-02-27 17:06:00 -080059};
60// command line arguments
61using Args = std::multimap<Option, std::string>;
62
Yifan Hong07292852019-08-21 15:40:30 -070063class HostFileSystem : public details::FileSystemImpl {
Yifan Hong69c1b112018-02-27 17:06:00 -080064 public:
Yifan Hong0dfc3d52020-01-09 14:30:02 -080065 HostFileSystem(const Dirmap& dirmap, status_t missingError)
66 : mDirMap(dirmap), mMissingError(missingError) {}
Yifan Hong10d86222018-04-06 15:41:05 -070067 status_t fetch(const std::string& path, std::string* fetched,
68 std::string* error) const override {
Yifan Hong6aef2fc2020-01-09 14:41:11 -080069 auto resolved = resolve(path, error);
Yifan Hong07292852019-08-21 15:40:30 -070070 if (resolved.empty()) {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080071 return mMissingError;
Yifan Hong07292852019-08-21 15:40:30 -070072 }
73 status_t status = details::FileSystemImpl::fetch(resolved, fetched, error);
Yifan Hong6aef2fc2020-01-09 14:41:11 -080074 LOG(INFO) << "Fetch '" << resolved << "': " << toString(status);
Yifan Hong10d86222018-04-06 15:41:05 -070075 return status;
Yifan Hong69c1b112018-02-27 17:06:00 -080076 }
Yifan Hong10d86222018-04-06 15:41:05 -070077 status_t listFiles(const std::string& path, std::vector<std::string>* out,
78 std::string* error) const override {
Yifan Hong6aef2fc2020-01-09 14:41:11 -080079 auto resolved = resolve(path, error);
Yifan Hong07292852019-08-21 15:40:30 -070080 if (resolved.empty()) {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080081 return mMissingError;
Yifan Hong07292852019-08-21 15:40:30 -070082 }
83 status_t status = details::FileSystemImpl::listFiles(resolved, out, error);
Yifan Hong6aef2fc2020-01-09 14:41:11 -080084 LOG(INFO) << "List '" << resolved << "': " << toString(status);
Yifan Hong69c1b112018-02-27 17:06:00 -080085 return status;
86 }
87
88 private:
Yifan Hong69c1b112018-02-27 17:06:00 -080089 static std::string toString(status_t status) {
90 return status == OK ? "SUCCESS" : strerror(-status);
91 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -080092 std::string resolve(const std::string& path, std::string* error) const {
Yifan Hong07292852019-08-21 15:40:30 -070093 for (auto [prefix, mappedPath] : mDirMap) {
94 if (path == prefix) {
95 return mappedPath;
96 }
97 if (android::base::StartsWith(path, prefix + "/")) {
98 return mappedPath + "/" + path.substr(prefix.size() + 1);
99 }
100 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800101 if (error) {
102 *error = "Cannot resolve path " + path;
103 } else {
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800104 LOG(mMissingError == NAME_NOT_FOUND ? INFO : ERROR) << "Cannot resolve path " << path;
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800105 }
Yifan Hong07292852019-08-21 15:40:30 -0700106 return "";
107 }
108
109 Dirmap mDirMap;
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800110 status_t mMissingError;
Yifan Hong69c1b112018-02-27 17:06:00 -0800111};
112
113class PresetPropertyFetcher : public PropertyFetcher {
114 public:
115 std::string getProperty(const std::string& key,
116 const std::string& defaultValue) const override {
117 auto it = mProps.find(key);
118 if (it == mProps.end()) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800119 LOG(INFO) << "Sysprop " << key << " is missing, default to '" << defaultValue << "'";
Yifan Hong69c1b112018-02-27 17:06:00 -0800120 return defaultValue;
121 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800122 LOG(INFO) << "Sysprop " << key << "=" << it->second;
Yifan Hong69c1b112018-02-27 17:06:00 -0800123 return it->second;
124 }
125 uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
126 uint64_t max) const override {
127 uint64_t result;
128 std::string value = getProperty(key, "");
129 if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
130 return defaultValue;
131 }
132 bool getBoolProperty(const std::string& key, bool defaultValue) const override {
133 std::string value = getProperty(key, "");
134 if (value == "1" || value == "true") {
135 return true;
136 } else if (value == "0" || value == "false") {
137 return false;
138 }
139 return defaultValue;
140 }
141 void setProperties(const Properties& props) { mProps.insert(props.begin(), props.end()); }
142
143 private:
144 std::map<std::string, std::string> mProps;
145};
146
Yifan Hong07292852019-08-21 15:40:30 -0700147struct StaticRuntimeInfo : public RuntimeInfo {
148 KernelVersion kernelVersion;
149 std::string kernelConfigFile;
150
151 status_t fetchAllInformation(FetchFlags flags) override {
152 if (flags & RuntimeInfo::FetchFlag::CPU_VERSION) {
153 mKernel.mVersion = kernelVersion;
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800154 LOG(INFO) << "fetched kernel version " << kernelVersion;
Yifan Hong07292852019-08-21 15:40:30 -0700155 }
156 if (flags & RuntimeInfo::FetchFlag::CONFIG_GZ) {
157 std::string content;
158 if (!android::base::ReadFileToString(kernelConfigFile, &content)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800159 LOG(ERROR) << "Cannot read " << kernelConfigFile;
Yifan Hong07292852019-08-21 15:40:30 -0700160 return UNKNOWN_ERROR;
161 }
162 KernelConfigParser parser;
163 auto status = parser.processAndFinish(content);
164 if (status != OK) {
165 return status;
166 }
167 mKernel.mConfigs = std::move(parser.configs());
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800168 LOG(INFO) << "read kernel configs from " << kernelConfigFile;
Yifan Hong07292852019-08-21 15:40:30 -0700169 }
170 if (flags & RuntimeInfo::FetchFlag::POLICYVERS) {
171 mKernelSepolicyVersion = SIZE_MAX;
172 }
173 return OK;
174 }
175};
176
177struct StubRuntimeInfo : public RuntimeInfo {
178 status_t fetchAllInformation(FetchFlags) override { return UNKNOWN_ERROR; }
179};
180
181struct StaticRuntimeInfoFactory : public ObjectFactory<RuntimeInfo> {
182 std::shared_ptr<RuntimeInfo> info;
183 StaticRuntimeInfoFactory(std::shared_ptr<RuntimeInfo> i) : info(i) {}
184 std::shared_ptr<RuntimeInfo> make_shared() const override {
185 if (info) return info;
186 return std::make_shared<StubRuntimeInfo>();
187 }
188};
189
Yifan Hong69c1b112018-02-27 17:06:00 -0800190// helper functions
Yifan Honga72bde72017-09-28 13:36:48 -0700191template <typename T>
Yifan Hong9f78c182018-07-12 14:45:52 -0700192std::unique_ptr<T> readObject(FileSystem* fileSystem, const std::string& path,
193 const XmlConverter<T>& converter) {
Yifan Honga72bde72017-09-28 13:36:48 -0700194 std::string xml;
Yifan Hong60217032018-01-08 16:19:42 -0800195 std::string error;
Yifan Hong9f78c182018-07-12 14:45:52 -0700196 status_t err = fileSystem->fetch(path, &xml, &error);
Yifan Honga72bde72017-09-28 13:36:48 -0700197 if (err != OK) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800198 LOG(ERROR) << "Cannot read '" << path << "' (" << strerror(-err) << "): " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700199 return nullptr;
200 }
201 auto ret = std::make_unique<T>();
Yifan Hong94757062018-02-09 16:36:31 -0800202 if (!converter(ret.get(), xml, &error)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800203 LOG(ERROR) << "Cannot parse '" << path << "': " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700204 return nullptr;
205 }
206 return ret;
207}
208
Yifan Hong69c1b112018-02-27 17:06:00 -0800209int checkCompatibilityForFiles(const std::string& manifestPath, const std::string& matrixPath) {
Yifan Hong9f78c182018-07-12 14:45:52 -0700210 auto fileSystem = std::make_unique<FileSystemImpl>();
211 auto manifest = readObject(fileSystem.get(), manifestPath, gHalManifestConverter);
212 auto matrix = readObject(fileSystem.get(), matrixPath, gCompatibilityMatrixConverter);
Yifan Honga72bde72017-09-28 13:36:48 -0700213 if (manifest == nullptr || matrix == nullptr) {
214 return -1;
215 }
216
217 std::string error;
218 if (!manifest->checkCompatibility(*matrix, &error)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800219 LOG(ERROR) << "Incompatible: " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700220 std::cout << "false" << std::endl;
221 return 1;
222 }
223
224 std::cout << "true" << std::endl;
225 return 0;
226}
Yifan Hong69c1b112018-02-27 17:06:00 -0800227
228Args parseArgs(int argc, char** argv) {
229 int longOptFlag;
230 int optionIndex;
231 Args ret;
232 std::vector<struct option> longopts{
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800233 // Modes
Yifan Hong69c1b112018-02-27 17:06:00 -0800234 {"help", no_argument, &longOptFlag, HELP},
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800235 {"dump-file-list", no_argument, &longOptFlag, DUMP_FILE_LIST},
Yifan Hong69c1b112018-02-27 17:06:00 -0800236 {"check-compat", no_argument, &longOptFlag, CHECK_COMPAT},
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800237 {"check-one", no_argument, &longOptFlag, CHECK_ONE},
238 // Options
239 {"rootdir", required_argument, &longOptFlag, ROOTDIR},
240 {"property", required_argument, &longOptFlag, PROPERTY},
Yifan Hong07292852019-08-21 15:40:30 -0700241 {"dirmap", required_argument, &longOptFlag, DIR_MAP},
242 {"kernel", required_argument, &longOptFlag, KERNEL},
Yifan Hong69c1b112018-02-27 17:06:00 -0800243 {0, 0, 0, 0}};
244 std::map<int, Option> shortopts{
245 {'h', HELP}, {'D', PROPERTY}, {'c', CHECK_COMPAT},
246 };
247 for (;;) {
248 int c = getopt_long(argc, argv, "hcD:", longopts.data(), &optionIndex);
249 if (c == -1) {
250 break;
251 }
252 std::string argValue = optarg ? optarg : std::string{};
253 if (c == 0) {
254 ret.emplace(static_cast<Option>(longOptFlag), std::move(argValue));
255 } else {
256 ret.emplace(shortopts[c], std::move(argValue));
257 }
258 }
259 if (optind < argc) {
260 // see non option
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800261 LOG(ERROR) << "unrecognized option `" << argv[optind] << "'";
Yifan Hong69c1b112018-02-27 17:06:00 -0800262 return {{HELP, ""}};
263 }
264 return ret;
265}
266
267template <typename T>
Yifan Hong07292852019-08-21 15:40:30 -0700268std::map<std::string, std::string> splitArgs(const T& args, char split) {
269 std::map<std::string, std::string> ret;
Yifan Hong69c1b112018-02-27 17:06:00 -0800270 for (const auto& arg : args) {
Yifan Hong07292852019-08-21 15:40:30 -0700271 auto pos = arg.find(split);
Yifan Hong69c1b112018-02-27 17:06:00 -0800272 auto key = arg.substr(0, pos);
273 auto value = pos == std::string::npos ? std::string{} : arg.substr(pos + 1);
274 ret[key] = value;
275 }
276 return ret;
277}
Yifan Hong07292852019-08-21 15:40:30 -0700278template <typename T>
279Properties getProperties(const T& args) {
280 return splitArgs(args, '=');
281}
282
283template <typename T>
284Dirmap getDirmap(const T& args) {
285 return splitArgs(args, ':');
286}
287
288template <typename T>
289std::shared_ptr<StaticRuntimeInfo> getRuntimeInfo(const T& args) {
290 auto ret = std::make_shared<StaticRuntimeInfo>();
291 if (std::distance(args.begin(), args.end()) > 1) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800292 LOG(ERROR) << "Can't have multiple --kernel options";
Yifan Hong07292852019-08-21 15:40:30 -0700293 return nullptr;
294 }
295 auto pair = android::base::Split(*args.begin(), ":");
296 if (pair.size() != 2) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800297 LOG(ERROR) << "Invalid --kernel";
Yifan Hong07292852019-08-21 15:40:30 -0700298 return nullptr;
299 }
300 if (!parse(pair[0], &ret->kernelVersion)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800301 LOG(ERROR) << "Cannot parse " << pair[0] << " as kernel version";
Yifan Hong07292852019-08-21 15:40:30 -0700302 return nullptr;
303 }
304 ret->kernelConfigFile = std::move(pair[1]);
305 return ret;
306}
Yifan Hong69c1b112018-02-27 17:06:00 -0800307
308int usage(const char* me) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800309 LOG(ERROR)
Yifan Hong69c1b112018-02-27 17:06:00 -0800310 << me << ": check VINTF metadata." << std::endl
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800311 << " Modes:" << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800312 << " --dump-file-list: Dump a list of directories / files on device" << std::endl
313 << " that is required to be used by --check-compat." << std::endl
314 << " -c, --check-compat: check compatibility for files under the root" << std::endl
315 << " directory specified by --root-dir." << std::endl
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800316 << " --check-one: check consistency of VINTF metadata for a single partition."
317 << std::endl
318 << std::endl
319 << " Options:" << std::endl
Yifan Hong07292852019-08-21 15:40:30 -0700320 << " --rootdir=<dir>: specify root directory for all metadata. Same as " << std::endl
321 << " --dirmap /:<dir>" << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800322 << " -D, --property <key>=<value>: specify sysprops." << std::endl
Yifan Hong07292852019-08-21 15:40:30 -0700323 << " --dirmap </system:/dir/to/system> [--dirmap </vendor:/dir/to/vendor>[...]]"
324 << std::endl
325 << " Map partitions to directories. Cannot be specified with --rootdir."
326 << " --kernel <x.y.z:path/to/config>" << std::endl
327 << " Use the given kernel version and config to check. If" << std::endl
328 << " unspecified, kernel requirements are skipped." << std::endl
329 << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800330 << " --help: show this message." << std::endl
331 << std::endl
332 << " Example:" << std::endl
333 << " # Get the list of required files." << std::endl
334 << " " << me << " --dump-file-list > /tmp/files.txt" << std::endl
335 << " # Pull from ADB, or use your own command to extract files from images"
336 << std::endl
337 << " ROOTDIR=/tmp/device/" << std::endl
338 << " cat /tmp/files.txt | xargs -I{} bash -c \"mkdir -p $ROOTDIR`dirname {}` && adb "
339 "pull {} $ROOTDIR{}\""
340 << std::endl
341 << " # Check compatibility." << std::endl
342 << " " << me << " --check-compat --rootdir=$ROOTDIR \\" << std::endl
343 << " --property ro.product.first_api_level=`adb shell getprop "
344 "ro.product.first_api_level` \\"
345 << std::endl
346 << " --property ro.boot.product.hardware.sku=`adb shell getprop "
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800347 "ro.boot.product.hardware.sku`";
Yifan Hong62503e12019-08-26 12:47:41 -0700348 return EX_USAGE;
Yifan Hong69c1b112018-02-27 17:06:00 -0800349}
350
Yifan Hongb67b9472020-04-07 14:27:00 -0700351// If |result| is already an error, don't do anything. Otherwise, set it to
352// an error with |errorCode|. Return reference to Error object for appending
353// additional error messages.
354android::base::Error& SetErrorCode(std::optional<android::base::Error>* retError,
355 int errorCode = 0) {
356 if (!retError->has_value()) {
357 retError->emplace(errorCode);
358 } else {
359 // Use existing error code.
360 // There should already been an error message appended. Add a new line char for
361 // additional messages.
362 (**retError) << "\n";
363 }
364 return **retError;
365}
366
367// If |other| is an error, add it to |retError|.
368template <typename T>
369void AddResult(std::optional<android::base::Error>* retError,
370 const android::base::Result<T>& other) {
371 if (other.ok()) return;
372 SetErrorCode(retError, other.error().code()) << other.error();
373}
374
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700375android::base::Result<void> checkAllFiles(const Dirmap& dirmap, const Properties& props,
376 std::shared_ptr<StaticRuntimeInfo> runtimeInfo) {
Yifan Hong9f78c182018-07-12 14:45:52 -0700377 auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
378 hostPropertyFetcher->setProperties(props);
Yifan Hong07292852019-08-21 15:40:30 -0700379
380 CheckFlags::Type flags = CheckFlags::DEFAULT;
381 if (!runtimeInfo) flags = flags.disableRuntimeInfo();
382
383 auto vintfObject =
384 VintfObject::Builder()
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800385 .setFileSystem(std::make_unique<HostFileSystem>(dirmap, UNKNOWN_ERROR))
Yifan Hong07292852019-08-21 15:40:30 -0700386 .setPropertyFetcher(std::move(hostPropertyFetcher))
387 .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(runtimeInfo))
388 .build();
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700389
Yifan Hongb67b9472020-04-07 14:27:00 -0700390 std::optional<android::base::Error> retError = std::nullopt;
391
392 std::string compatibleError;
393 int compatibleResult = vintfObject->checkCompatibility(&compatibleError, flags);
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700394 if (compatibleResult == INCOMPATIBLE) {
Yifan Hongb67b9472020-04-07 14:27:00 -0700395 SetErrorCode(&retError) << compatibleError;
396 } else if (compatibleResult != COMPATIBLE) {
397 SetErrorCode(&retError, -compatibleResult) << compatibleError;
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700398 }
399
Yifan Hong4b52dfa2020-04-07 15:22:24 -0700400 auto hidlMetadata = HidlInterfaceMetadata::all();
401
402 std::string deprecateError;
403 int deprecateResult = vintfObject->checkDeprecation(hidlMetadata, &deprecateError);
404 if (deprecateResult == DEPRECATED) {
405 SetErrorCode(&retError) << deprecateError;
406 } else if (deprecateResult != NO_DEPRECATED_HALS) {
407 SetErrorCode(&retError, -deprecateResult) << deprecateError;
408 }
409
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700410 auto hasFcmExt = vintfObject->hasFrameworkCompatibilityMatrixExtensions();
Yifan Hongb67b9472020-04-07 14:27:00 -0700411 AddResult(&retError, hasFcmExt);
412
Yifan Hong76f85852020-03-23 16:32:40 +0000413 auto deviceManifest = vintfObject->getDeviceHalManifest();
Yifan Hongb67b9472020-04-07 14:27:00 -0700414 Level targetFcm = Level::UNSPECIFIED;
Yifan Hong76f85852020-03-23 16:32:40 +0000415 if (deviceManifest == nullptr) {
Yifan Hongb67b9472020-04-07 14:27:00 -0700416 SetErrorCode(&retError, -NAME_NOT_FOUND) << "No device HAL manifest";
417 } else {
418 targetFcm = deviceManifest->level();
Yifan Hong76f85852020-03-23 16:32:40 +0000419 }
Yifan Hongb67b9472020-04-07 14:27:00 -0700420
421 if (hasFcmExt.value_or(false) || (targetFcm != Level::UNSPECIFIED && targetFcm >= Level::R)) {
Yifan Hongb67b9472020-04-07 14:27:00 -0700422 AddResult(&retError, vintfObject->checkUnusedHals(hidlMetadata));
423 } else {
424 LOG(INFO) << "Skip checking unused HALs.";
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700425 }
Yifan Hongb67b9472020-04-07 14:27:00 -0700426
427 if (retError.has_value()) {
428 return *retError;
429 } else {
430 return {};
431 }
Yifan Hong69c1b112018-02-27 17:06:00 -0800432}
433
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700434int checkDirmaps(const Dirmap& dirmap, const Properties& props) {
435 auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
436 hostPropertyFetcher->setProperties(props);
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800437 auto exitCode = EX_OK;
438 for (auto&& [prefix, mappedPath] : dirmap) {
439 auto vintfObject =
440 VintfObject::Builder()
441 .setFileSystem(std::make_unique<HostFileSystem>(dirmap, NAME_NOT_FOUND))
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700442 .setPropertyFetcher(std::move(hostPropertyFetcher))
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800443 .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(nullptr))
444 .build();
445
446 if (android::base::StartsWith(prefix, "/system")) {
447 LOG(INFO) << "Checking system manifest.";
448 auto manifest = vintfObject->getFrameworkHalManifest();
449 if (!manifest) {
450 LOG(ERROR) << "Cannot fetch system manifest.";
451 exitCode = EX_SOFTWARE;
452 }
453 LOG(INFO) << "Checking system matrix.";
454 auto matrix = vintfObject->getFrameworkCompatibilityMatrix();
455 if (!matrix) {
456 LOG(ERROR) << "Cannot fetch system matrix.";
457 exitCode = EX_SOFTWARE;
458 }
459 continue;
460 }
461
462 if (android::base::StartsWith(prefix, "/vendor")) {
463 LOG(INFO) << "Checking vendor manifest.";
464 auto manifest = vintfObject->getDeviceHalManifest();
465 if (!manifest) {
466 LOG(ERROR) << "Cannot fetch vendor manifest.";
467 exitCode = EX_SOFTWARE;
468 }
469 LOG(INFO) << "Checking vendor matrix.";
470 auto matrix = vintfObject->getDeviceCompatibilityMatrix();
471 if (!matrix) {
472 LOG(ERROR) << "Cannot fetch vendor matrix.";
473 exitCode = EX_SOFTWARE;
474 }
475 continue;
476 }
477
478 LOG(ERROR) << "--check-one does not work with --dirmap " << prefix;
479 exitCode = EX_SOFTWARE;
480 }
481 return exitCode;
482}
483
Yifan Hong69c1b112018-02-27 17:06:00 -0800484} // namespace details
485} // namespace vintf
486} // namespace android
487
488int main(int argc, char** argv) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800489 android::base::SetLogger(android::base::StderrLogger);
490
Yifan Hong69c1b112018-02-27 17:06:00 -0800491 using namespace android::vintf;
492 using namespace android::vintf::details;
493 // legacy usage: check_vintf <manifest.xml> <matrix.xml>
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800494 if (argc == 3 && *argv[1] != '-' && *argv[2] != '-') {
Yifan Hong69c1b112018-02-27 17:06:00 -0800495 int ret = checkCompatibilityForFiles(argv[1], argv[2]);
496 if (ret >= 0) return ret;
497 }
498
499 Args args = parseArgs(argc, argv);
500
501 if (!iterateValues(args, HELP).empty()) {
502 return usage(argv[0]);
503 }
504
505 if (!iterateValues(args, DUMP_FILE_LIST).empty()) {
506 for (const auto& file : dumpFileList()) {
507 std::cout << file << std::endl;
508 }
509 return 0;
510 }
511
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800512 auto dirmap = getDirmap(iterateValues(args, DIR_MAP));
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700513 auto properties = getProperties(iterateValues(args, PROPERTY));
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800514
515 if (!iterateValues(args, CHECK_ONE).empty()) {
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700516 return checkDirmaps(dirmap, properties);
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800517 }
518
Yifan Hong69c1b112018-02-27 17:06:00 -0800519 auto checkCompat = iterateValues(args, CHECK_COMPAT);
Yifan Hong07292852019-08-21 15:40:30 -0700520 if (checkCompat.empty()) {
521 return usage(argv[0]);
Yifan Hong69c1b112018-02-27 17:06:00 -0800522 }
523
Yifan Hong07292852019-08-21 15:40:30 -0700524 auto rootdirs = iterateValues(args, ROOTDIR);
525 if (!rootdirs.empty()) {
526 if (std::distance(rootdirs.begin(), rootdirs.end()) > 1) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800527 LOG(ERROR) << "Can't have multiple --rootdir options";
Yifan Hong07292852019-08-21 15:40:30 -0700528 return usage(argv[0]);
529 }
530 args.emplace(DIR_MAP, "/:" + *rootdirs.begin());
531 }
532
Yifan Hong07292852019-08-21 15:40:30 -0700533 std::shared_ptr<StaticRuntimeInfo> runtimeInfo;
534 auto kernelArgs = iterateValues(args, KERNEL);
535 if (!kernelArgs.empty()) {
536 runtimeInfo = getRuntimeInfo(kernelArgs);
537 if (runtimeInfo == nullptr) {
538 return usage(argv[0]);
539 }
540 }
541
Yifan Hong07292852019-08-21 15:40:30 -0700542 if (dirmap.empty()) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800543 LOG(ERROR) << "Missing --rootdir or --dirmap option.";
Yifan Hong07292852019-08-21 15:40:30 -0700544 return usage(argv[0]);
545 }
546
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700547 auto compat = checkAllFiles(dirmap, properties, runtimeInfo);
Yifan Hong62503e12019-08-26 12:47:41 -0700548
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700549 if (compat.ok()) {
Yifan Hong62503e12019-08-26 12:47:41 -0700550 std::cout << "COMPATIBLE" << std::endl;
551 return EX_OK;
552 }
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700553 if (compat.error().code() == 0) {
554 LOG(ERROR) << "files are incompatible: " << compat.error();
Yifan Hong62503e12019-08-26 12:47:41 -0700555 std::cout << "INCOMPATIBLE" << std::endl;
556 return EX_DATAERR;
557 }
Yifan Hong6e32a5f2020-03-12 16:06:27 -0700558 LOG(ERROR) << strerror(compat.error().code()) << ": " << compat.error();
Yifan Hong62503e12019-08-26 12:47:41 -0700559 return EX_SOFTWARE;
Yifan Hong69c1b112018-02-27 17:06:00 -0800560}