xref: /aosp_15_r20/system/libvintf/check_vintf.cpp (revision 70a7ec852fcefd15a4fb57f8f183a8b1c3aacb08)
1*70a7ec85SAndroid Build Coastguard Worker /*
2*70a7ec85SAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*70a7ec85SAndroid Build Coastguard Worker  *
4*70a7ec85SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*70a7ec85SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*70a7ec85SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*70a7ec85SAndroid Build Coastguard Worker  *
8*70a7ec85SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*70a7ec85SAndroid Build Coastguard Worker  *
10*70a7ec85SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*70a7ec85SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*70a7ec85SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*70a7ec85SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*70a7ec85SAndroid Build Coastguard Worker  * limitations under the License.
15*70a7ec85SAndroid Build Coastguard Worker  */
16*70a7ec85SAndroid Build Coastguard Worker 
17*70a7ec85SAndroid Build Coastguard Worker #include <getopt.h>
18*70a7ec85SAndroid Build Coastguard Worker #include <sysexits.h>
19*70a7ec85SAndroid Build Coastguard Worker #include <unistd.h>
20*70a7ec85SAndroid Build Coastguard Worker 
21*70a7ec85SAndroid Build Coastguard Worker #include <algorithm>
22*70a7ec85SAndroid Build Coastguard Worker #include <functional>
23*70a7ec85SAndroid Build Coastguard Worker #include <iostream>
24*70a7ec85SAndroid Build Coastguard Worker #include <map>
25*70a7ec85SAndroid Build Coastguard Worker #include <optional>
26*70a7ec85SAndroid Build Coastguard Worker 
27*70a7ec85SAndroid Build Coastguard Worker #include <aidl/metadata.h>
28*70a7ec85SAndroid Build Coastguard Worker #include <android-base/file.h>
29*70a7ec85SAndroid Build Coastguard Worker #include <android-base/logging.h>
30*70a7ec85SAndroid Build Coastguard Worker #include <android-base/parseint.h>
31*70a7ec85SAndroid Build Coastguard Worker #include <android-base/result.h>
32*70a7ec85SAndroid Build Coastguard Worker #include <android-base/strings.h>
33*70a7ec85SAndroid Build Coastguard Worker #include <hidl/metadata.h>
34*70a7ec85SAndroid Build Coastguard Worker #include <kver/kernel_release.h>
35*70a7ec85SAndroid Build Coastguard Worker #include <utils/Errors.h>
36*70a7ec85SAndroid Build Coastguard Worker #include <vintf/Dirmap.h>
37*70a7ec85SAndroid Build Coastguard Worker #include <vintf/HostFileSystem.h>
38*70a7ec85SAndroid Build Coastguard Worker #include <vintf/KernelConfigParser.h>
39*70a7ec85SAndroid Build Coastguard Worker #include <vintf/VintfObject.h>
40*70a7ec85SAndroid Build Coastguard Worker #include <vintf/fcm_exclude.h>
41*70a7ec85SAndroid Build Coastguard Worker #include <vintf/parse_string.h>
42*70a7ec85SAndroid Build Coastguard Worker #include <vintf/parse_xml.h>
43*70a7ec85SAndroid Build Coastguard Worker #include "constants-private.h"
44*70a7ec85SAndroid Build Coastguard Worker #include "utils.h"
45*70a7ec85SAndroid Build Coastguard Worker 
46*70a7ec85SAndroid Build Coastguard Worker using android::kver::KernelRelease;
47*70a7ec85SAndroid Build Coastguard Worker 
48*70a7ec85SAndroid Build Coastguard Worker namespace android {
49*70a7ec85SAndroid Build Coastguard Worker namespace vintf {
50*70a7ec85SAndroid Build Coastguard Worker namespace details {
51*70a7ec85SAndroid Build Coastguard Worker 
52*70a7ec85SAndroid Build Coastguard Worker // fake sysprops
53*70a7ec85SAndroid Build Coastguard Worker using Properties = std::map<std::string, std::string>;
54*70a7ec85SAndroid Build Coastguard Worker 
55*70a7ec85SAndroid Build Coastguard Worker enum Option : int {
56*70a7ec85SAndroid Build Coastguard Worker     // Modes
57*70a7ec85SAndroid Build Coastguard Worker     HELP,
58*70a7ec85SAndroid Build Coastguard Worker     DUMP_FILE_LIST = 1,
59*70a7ec85SAndroid Build Coastguard Worker     CHECK_COMPAT,
60*70a7ec85SAndroid Build Coastguard Worker     CHECK_ONE,
61*70a7ec85SAndroid Build Coastguard Worker 
62*70a7ec85SAndroid Build Coastguard Worker     // Options
63*70a7ec85SAndroid Build Coastguard Worker     ROOTDIR,
64*70a7ec85SAndroid Build Coastguard Worker     PROPERTY,
65*70a7ec85SAndroid Build Coastguard Worker     DIR_MAP,
66*70a7ec85SAndroid Build Coastguard Worker     KERNEL,
67*70a7ec85SAndroid Build Coastguard Worker };
68*70a7ec85SAndroid Build Coastguard Worker // command line arguments
69*70a7ec85SAndroid Build Coastguard Worker using Args = std::multimap<Option, std::string>;
70*70a7ec85SAndroid Build Coastguard Worker 
71*70a7ec85SAndroid Build Coastguard Worker class PresetPropertyFetcher : public PropertyFetcher {
72*70a7ec85SAndroid Build Coastguard Worker    public:
getProperty(const std::string & key,const std::string & defaultValue) const73*70a7ec85SAndroid Build Coastguard Worker     std::string getProperty(const std::string& key,
74*70a7ec85SAndroid Build Coastguard Worker                             const std::string& defaultValue) const override {
75*70a7ec85SAndroid Build Coastguard Worker         auto it = mProps.find(key);
76*70a7ec85SAndroid Build Coastguard Worker         if (it == mProps.end()) {
77*70a7ec85SAndroid Build Coastguard Worker             LOG(INFO) << "Sysprop " << key << " is missing, default to '" << defaultValue << "'";
78*70a7ec85SAndroid Build Coastguard Worker             return defaultValue;
79*70a7ec85SAndroid Build Coastguard Worker         }
80*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "Sysprop " << key << "=" << it->second;
81*70a7ec85SAndroid Build Coastguard Worker         return it->second;
82*70a7ec85SAndroid Build Coastguard Worker     }
getUintProperty(const std::string & key,uint64_t defaultValue,uint64_t max) const83*70a7ec85SAndroid Build Coastguard Worker     uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
84*70a7ec85SAndroid Build Coastguard Worker                              uint64_t max) const override {
85*70a7ec85SAndroid Build Coastguard Worker         uint64_t result;
86*70a7ec85SAndroid Build Coastguard Worker         std::string value = getProperty(key, "");
87*70a7ec85SAndroid Build Coastguard Worker         if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
88*70a7ec85SAndroid Build Coastguard Worker         return defaultValue;
89*70a7ec85SAndroid Build Coastguard Worker     }
getBoolProperty(const std::string & key,bool defaultValue) const90*70a7ec85SAndroid Build Coastguard Worker     bool getBoolProperty(const std::string& key, bool defaultValue) const override {
91*70a7ec85SAndroid Build Coastguard Worker         std::string value = getProperty(key, "");
92*70a7ec85SAndroid Build Coastguard Worker         if (value == "1" || value == "true") {
93*70a7ec85SAndroid Build Coastguard Worker             return true;
94*70a7ec85SAndroid Build Coastguard Worker         } else if (value == "0" || value == "false") {
95*70a7ec85SAndroid Build Coastguard Worker             return false;
96*70a7ec85SAndroid Build Coastguard Worker         }
97*70a7ec85SAndroid Build Coastguard Worker         return defaultValue;
98*70a7ec85SAndroid Build Coastguard Worker     }
setProperties(const Properties & props)99*70a7ec85SAndroid Build Coastguard Worker     void setProperties(const Properties& props) { mProps.insert(props.begin(), props.end()); }
100*70a7ec85SAndroid Build Coastguard Worker 
101*70a7ec85SAndroid Build Coastguard Worker    private:
102*70a7ec85SAndroid Build Coastguard Worker     std::map<std::string, std::string> mProps;
103*70a7ec85SAndroid Build Coastguard Worker };
104*70a7ec85SAndroid Build Coastguard Worker 
105*70a7ec85SAndroid Build Coastguard Worker struct StaticRuntimeInfo : public RuntimeInfo {
106*70a7ec85SAndroid Build Coastguard Worker     KernelVersion kernelVersion;
107*70a7ec85SAndroid Build Coastguard Worker     Level kernelLevel = Level::UNSPECIFIED;
108*70a7ec85SAndroid Build Coastguard Worker     std::string kernelConfigFile;
109*70a7ec85SAndroid Build Coastguard Worker 
fetchAllInformationandroid::vintf::details::StaticRuntimeInfo110*70a7ec85SAndroid Build Coastguard Worker     status_t fetchAllInformation(FetchFlags flags) override {
111*70a7ec85SAndroid Build Coastguard Worker         if (flags & RuntimeInfo::FetchFlag::CPU_VERSION) {
112*70a7ec85SAndroid Build Coastguard Worker             mKernel.mVersion = kernelVersion;
113*70a7ec85SAndroid Build Coastguard Worker             LOG(INFO) << "fetched kernel version " << kernelVersion;
114*70a7ec85SAndroid Build Coastguard Worker         }
115*70a7ec85SAndroid Build Coastguard Worker         if (flags & RuntimeInfo::FetchFlag::KERNEL_FCM) {
116*70a7ec85SAndroid Build Coastguard Worker             mKernel.mLevel = kernelLevel;
117*70a7ec85SAndroid Build Coastguard Worker             LOG(INFO) << "fetched kernel level from RuntimeInfo '" << kernelLevel << "'";
118*70a7ec85SAndroid Build Coastguard Worker         }
119*70a7ec85SAndroid Build Coastguard Worker         if (flags & RuntimeInfo::FetchFlag::CONFIG_GZ) {
120*70a7ec85SAndroid Build Coastguard Worker             std::string content;
121*70a7ec85SAndroid Build Coastguard Worker             if (!android::base::ReadFileToString(kernelConfigFile, &content)) {
122*70a7ec85SAndroid Build Coastguard Worker                 LOG(ERROR) << "ERROR: Cannot read " << kernelConfigFile;
123*70a7ec85SAndroid Build Coastguard Worker                 return UNKNOWN_ERROR;
124*70a7ec85SAndroid Build Coastguard Worker             }
125*70a7ec85SAndroid Build Coastguard Worker             KernelConfigParser parser;
126*70a7ec85SAndroid Build Coastguard Worker             auto status = parser.processAndFinish(content);
127*70a7ec85SAndroid Build Coastguard Worker             if (status != OK) {
128*70a7ec85SAndroid Build Coastguard Worker                 return status;
129*70a7ec85SAndroid Build Coastguard Worker             }
130*70a7ec85SAndroid Build Coastguard Worker             mKernel.mConfigs = std::move(parser.configs());
131*70a7ec85SAndroid Build Coastguard Worker             LOG(INFO) << "read kernel configs from " << kernelConfigFile;
132*70a7ec85SAndroid Build Coastguard Worker         }
133*70a7ec85SAndroid Build Coastguard Worker         if (flags & RuntimeInfo::FetchFlag::POLICYVERS) {
134*70a7ec85SAndroid Build Coastguard Worker             mKernelSepolicyVersion = SIZE_MAX;
135*70a7ec85SAndroid Build Coastguard Worker         }
136*70a7ec85SAndroid Build Coastguard Worker         return OK;
137*70a7ec85SAndroid Build Coastguard Worker     }
138*70a7ec85SAndroid Build Coastguard Worker 
setIsMainlineandroid::vintf::details::StaticRuntimeInfo139*70a7ec85SAndroid Build Coastguard Worker     void setIsMainline(bool value) { mIsMainline = value; }
140*70a7ec85SAndroid Build Coastguard Worker };
141*70a7ec85SAndroid Build Coastguard Worker 
142*70a7ec85SAndroid Build Coastguard Worker struct StubRuntimeInfo : public RuntimeInfo {
fetchAllInformationandroid::vintf::details::StubRuntimeInfo143*70a7ec85SAndroid Build Coastguard Worker     status_t fetchAllInformation(FetchFlags) override { return UNKNOWN_ERROR; }
144*70a7ec85SAndroid Build Coastguard Worker };
145*70a7ec85SAndroid Build Coastguard Worker 
146*70a7ec85SAndroid Build Coastguard Worker struct StaticRuntimeInfoFactory : public ObjectFactory<RuntimeInfo> {
147*70a7ec85SAndroid Build Coastguard Worker     std::shared_ptr<RuntimeInfo> info;
StaticRuntimeInfoFactoryandroid::vintf::details::StaticRuntimeInfoFactory148*70a7ec85SAndroid Build Coastguard Worker     StaticRuntimeInfoFactory(std::shared_ptr<RuntimeInfo> i) : info(i) {}
make_sharedandroid::vintf::details::StaticRuntimeInfoFactory149*70a7ec85SAndroid Build Coastguard Worker     std::shared_ptr<RuntimeInfo> make_shared() const override {
150*70a7ec85SAndroid Build Coastguard Worker         if (info) return info;
151*70a7ec85SAndroid Build Coastguard Worker         return std::make_shared<StubRuntimeInfo>();
152*70a7ec85SAndroid Build Coastguard Worker     }
153*70a7ec85SAndroid Build Coastguard Worker };
154*70a7ec85SAndroid Build Coastguard Worker 
155*70a7ec85SAndroid Build Coastguard Worker // helper functions
156*70a7ec85SAndroid Build Coastguard Worker template <typename T>
readObject(FileSystem * fileSystem,const std::string & path)157*70a7ec85SAndroid Build Coastguard Worker std::unique_ptr<T> readObject(FileSystem* fileSystem, const std::string& path) {
158*70a7ec85SAndroid Build Coastguard Worker     std::string xml;
159*70a7ec85SAndroid Build Coastguard Worker     std::string error;
160*70a7ec85SAndroid Build Coastguard Worker     status_t err = fileSystem->fetch(path, &xml, &error);
161*70a7ec85SAndroid Build Coastguard Worker     if (err != OK) {
162*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: Cannot read '" << path << "' (" << strerror(-err) << "): " << error;
163*70a7ec85SAndroid Build Coastguard Worker         return nullptr;
164*70a7ec85SAndroid Build Coastguard Worker     }
165*70a7ec85SAndroid Build Coastguard Worker     auto ret = std::make_unique<T>();
166*70a7ec85SAndroid Build Coastguard Worker     ret->setFileName(path);
167*70a7ec85SAndroid Build Coastguard Worker     if (!fromXml(ret.get(), xml, &error)) {
168*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: Cannot parse '" << path << "': " << error;
169*70a7ec85SAndroid Build Coastguard Worker         return nullptr;
170*70a7ec85SAndroid Build Coastguard Worker     }
171*70a7ec85SAndroid Build Coastguard Worker     return ret;
172*70a7ec85SAndroid Build Coastguard Worker }
173*70a7ec85SAndroid Build Coastguard Worker 
checkCompatibilityForFiles(const std::string & manifestPath,const std::string & matrixPath)174*70a7ec85SAndroid Build Coastguard Worker int checkCompatibilityForFiles(const std::string& manifestPath, const std::string& matrixPath) {
175*70a7ec85SAndroid Build Coastguard Worker     auto fileSystem = std::make_unique<FileSystemImpl>();
176*70a7ec85SAndroid Build Coastguard Worker     auto manifest = readObject<HalManifest>(fileSystem.get(), manifestPath);
177*70a7ec85SAndroid Build Coastguard Worker     auto matrix = readObject<CompatibilityMatrix>(fileSystem.get(), matrixPath);
178*70a7ec85SAndroid Build Coastguard Worker     if (manifest == nullptr || matrix == nullptr) {
179*70a7ec85SAndroid Build Coastguard Worker         return -1;
180*70a7ec85SAndroid Build Coastguard Worker     }
181*70a7ec85SAndroid Build Coastguard Worker 
182*70a7ec85SAndroid Build Coastguard Worker     std::string error;
183*70a7ec85SAndroid Build Coastguard Worker     if (!manifest->checkCompatibility(*matrix, &error)) {
184*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: Incompatible: " << error;
185*70a7ec85SAndroid Build Coastguard Worker         std::cout << "false" << std::endl;
186*70a7ec85SAndroid Build Coastguard Worker         return 1;
187*70a7ec85SAndroid Build Coastguard Worker     }
188*70a7ec85SAndroid Build Coastguard Worker 
189*70a7ec85SAndroid Build Coastguard Worker     std::cout << "true" << std::endl;
190*70a7ec85SAndroid Build Coastguard Worker     return 0;
191*70a7ec85SAndroid Build Coastguard Worker }
192*70a7ec85SAndroid Build Coastguard Worker 
parseArgs(int argc,char ** argv)193*70a7ec85SAndroid Build Coastguard Worker Args parseArgs(int argc, char** argv) {
194*70a7ec85SAndroid Build Coastguard Worker     int longOptFlag;
195*70a7ec85SAndroid Build Coastguard Worker     int optionIndex;
196*70a7ec85SAndroid Build Coastguard Worker     Args ret;
197*70a7ec85SAndroid Build Coastguard Worker     std::vector<struct option> longopts{
198*70a7ec85SAndroid Build Coastguard Worker         // Modes
199*70a7ec85SAndroid Build Coastguard Worker         {"help", no_argument, &longOptFlag, HELP},
200*70a7ec85SAndroid Build Coastguard Worker         {"dump-file-list", no_argument, &longOptFlag, DUMP_FILE_LIST},
201*70a7ec85SAndroid Build Coastguard Worker         {"check-compat", no_argument, &longOptFlag, CHECK_COMPAT},
202*70a7ec85SAndroid Build Coastguard Worker         {"check-one", no_argument, &longOptFlag, CHECK_ONE},
203*70a7ec85SAndroid Build Coastguard Worker         // Options
204*70a7ec85SAndroid Build Coastguard Worker         {"rootdir", required_argument, &longOptFlag, ROOTDIR},
205*70a7ec85SAndroid Build Coastguard Worker         {"property", required_argument, &longOptFlag, PROPERTY},
206*70a7ec85SAndroid Build Coastguard Worker         {"dirmap", required_argument, &longOptFlag, DIR_MAP},
207*70a7ec85SAndroid Build Coastguard Worker         {"kernel", required_argument, &longOptFlag, KERNEL},
208*70a7ec85SAndroid Build Coastguard Worker         {0, 0, 0, 0}};
209*70a7ec85SAndroid Build Coastguard Worker     std::map<int, Option> shortopts{
210*70a7ec85SAndroid Build Coastguard Worker         {'h', HELP}, {'D', PROPERTY}, {'c', CHECK_COMPAT},
211*70a7ec85SAndroid Build Coastguard Worker     };
212*70a7ec85SAndroid Build Coastguard Worker     for (;;) {
213*70a7ec85SAndroid Build Coastguard Worker         int c = getopt_long(argc, argv, "hcD:", longopts.data(), &optionIndex);
214*70a7ec85SAndroid Build Coastguard Worker         if (c == -1) {
215*70a7ec85SAndroid Build Coastguard Worker             break;
216*70a7ec85SAndroid Build Coastguard Worker         }
217*70a7ec85SAndroid Build Coastguard Worker         std::string argValue = optarg ? optarg : std::string{};
218*70a7ec85SAndroid Build Coastguard Worker         if (c == 0) {
219*70a7ec85SAndroid Build Coastguard Worker             ret.emplace(static_cast<Option>(longOptFlag), std::move(argValue));
220*70a7ec85SAndroid Build Coastguard Worker         } else {
221*70a7ec85SAndroid Build Coastguard Worker             ret.emplace(shortopts[c], std::move(argValue));
222*70a7ec85SAndroid Build Coastguard Worker         }
223*70a7ec85SAndroid Build Coastguard Worker     }
224*70a7ec85SAndroid Build Coastguard Worker     if (optind < argc) {
225*70a7ec85SAndroid Build Coastguard Worker         // see non option
226*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: unrecognized option `" << argv[optind] << "'";
227*70a7ec85SAndroid Build Coastguard Worker         return {{HELP, ""}};
228*70a7ec85SAndroid Build Coastguard Worker     }
229*70a7ec85SAndroid Build Coastguard Worker     return ret;
230*70a7ec85SAndroid Build Coastguard Worker }
231*70a7ec85SAndroid Build Coastguard Worker 
232*70a7ec85SAndroid Build Coastguard Worker template <typename T>
getProperties(const T & args)233*70a7ec85SAndroid Build Coastguard Worker Properties getProperties(const T& args) {
234*70a7ec85SAndroid Build Coastguard Worker     return splitArgs(args, '=');
235*70a7ec85SAndroid Build Coastguard Worker }
236*70a7ec85SAndroid Build Coastguard Worker 
237*70a7ec85SAndroid Build Coastguard Worker // Parse a kernel version or a GKI kernel release.
parseKernelVersionOrRelease(const std::string & s,StaticRuntimeInfo * ret)238*70a7ec85SAndroid Build Coastguard Worker bool parseKernelVersionOrRelease(const std::string& s, StaticRuntimeInfo* ret) {
239*70a7ec85SAndroid Build Coastguard Worker     // 5.4.42
240*70a7ec85SAndroid Build Coastguard Worker     if (parse(s, &ret->kernelVersion)) {
241*70a7ec85SAndroid Build Coastguard Worker         ret->kernelLevel = Level::UNSPECIFIED;
242*70a7ec85SAndroid Build Coastguard Worker         ret->setIsMainline(false);
243*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "\"" << s << "\" is not a mainline kernel.";
244*70a7ec85SAndroid Build Coastguard Worker         return true;
245*70a7ec85SAndroid Build Coastguard Worker     }
246*70a7ec85SAndroid Build Coastguard Worker     LOG(INFO) << "Cannot parse \"" << s << "\" as kernel version, parsing as GKI kernel release.";
247*70a7ec85SAndroid Build Coastguard Worker 
248*70a7ec85SAndroid Build Coastguard Worker     // 5.4.42-android12-0-something
249*70a7ec85SAndroid Build Coastguard Worker     auto kernelRelease = KernelRelease::Parse(s, true /* allow suffix */);
250*70a7ec85SAndroid Build Coastguard Worker     if (kernelRelease.has_value()) {
251*70a7ec85SAndroid Build Coastguard Worker         ret->kernelVersion = KernelVersion{kernelRelease->version(), kernelRelease->patch_level(),
252*70a7ec85SAndroid Build Coastguard Worker                                            kernelRelease->sub_level()};
253*70a7ec85SAndroid Build Coastguard Worker         ret->kernelLevel = RuntimeInfo::gkiAndroidReleaseToLevel(kernelRelease->android_release());
254*70a7ec85SAndroid Build Coastguard Worker         ret->setIsMainline(false);
255*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "\"" << s << "\" is not a mainline kernel.";
256*70a7ec85SAndroid Build Coastguard Worker         return true;
257*70a7ec85SAndroid Build Coastguard Worker     }
258*70a7ec85SAndroid Build Coastguard Worker     LOG(INFO) << "Cannot parse \"" << s << "\" as GKI kernel release, parsing as kernel release";
259*70a7ec85SAndroid Build Coastguard Worker 
260*70a7ec85SAndroid Build Coastguard Worker     // 5.4.42-something
261*70a7ec85SAndroid Build Coastguard Worker     auto pos = s.find_first_not_of("0123456789.");
262*70a7ec85SAndroid Build Coastguard Worker     // substr handles pos == npos case
263*70a7ec85SAndroid Build Coastguard Worker     if (parse(s.substr(0, pos), &ret->kernelVersion)) {
264*70a7ec85SAndroid Build Coastguard Worker         ret->kernelLevel = Level::UNSPECIFIED;
265*70a7ec85SAndroid Build Coastguard Worker 
266*70a7ec85SAndroid Build Coastguard Worker         bool isMainline = RuntimeInfo::kernelReleaseIsMainline(s);
267*70a7ec85SAndroid Build Coastguard Worker         ret->setIsMainline(isMainline);
268*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "\"" << s << "\" is" << (isMainline ? "" : " not") << " a mainline kernel.";
269*70a7ec85SAndroid Build Coastguard Worker 
270*70a7ec85SAndroid Build Coastguard Worker         return true;
271*70a7ec85SAndroid Build Coastguard Worker     }
272*70a7ec85SAndroid Build Coastguard Worker 
273*70a7ec85SAndroid Build Coastguard Worker     LOG(INFO) << "Cannot parse \"" << s << "\" as kernel release";
274*70a7ec85SAndroid Build Coastguard Worker     return false;
275*70a7ec85SAndroid Build Coastguard Worker }
276*70a7ec85SAndroid Build Coastguard Worker 
277*70a7ec85SAndroid Build Coastguard Worker // Parse the first half of --kernel. |s| can either be a kernel version, a GKI kernel release,
278*70a7ec85SAndroid Build Coastguard Worker // or a file that contains either of them.
parseKernelArgFirstHalf(const std::string & s,StaticRuntimeInfo * ret)279*70a7ec85SAndroid Build Coastguard Worker bool parseKernelArgFirstHalf(const std::string& s, StaticRuntimeInfo* ret) {
280*70a7ec85SAndroid Build Coastguard Worker     if (parseKernelVersionOrRelease(s, ret)) {
281*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "Successfully parsed \"" << s << "\"";
282*70a7ec85SAndroid Build Coastguard Worker         return true;
283*70a7ec85SAndroid Build Coastguard Worker     }
284*70a7ec85SAndroid Build Coastguard Worker     std::string content;
285*70a7ec85SAndroid Build Coastguard Worker     if (!android::base::ReadFileToString(s, &content)) {
286*70a7ec85SAndroid Build Coastguard Worker         PLOG(INFO) << "Cannot read file " << s;
287*70a7ec85SAndroid Build Coastguard Worker         return false;
288*70a7ec85SAndroid Build Coastguard Worker     }
289*70a7ec85SAndroid Build Coastguard Worker     if (parseKernelVersionOrRelease(content, ret)) {
290*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "Successfully parsed content of " << s << ": " << content;
291*70a7ec85SAndroid Build Coastguard Worker         return true;
292*70a7ec85SAndroid Build Coastguard Worker     }
293*70a7ec85SAndroid Build Coastguard Worker     LOG(ERROR) << "ERROR: Cannot parse content of " << s << ": " << content;
294*70a7ec85SAndroid Build Coastguard Worker     return false;
295*70a7ec85SAndroid Build Coastguard Worker }
296*70a7ec85SAndroid Build Coastguard Worker 
297*70a7ec85SAndroid Build Coastguard Worker template <typename T>
getRuntimeInfo(const T & args)298*70a7ec85SAndroid Build Coastguard Worker std::shared_ptr<StaticRuntimeInfo> getRuntimeInfo(const T& args) {
299*70a7ec85SAndroid Build Coastguard Worker     auto ret = std::make_shared<StaticRuntimeInfo>();
300*70a7ec85SAndroid Build Coastguard Worker     if (std::distance(args.begin(), args.end()) > 1) {
301*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: Can't have multiple --kernel options";
302*70a7ec85SAndroid Build Coastguard Worker         return nullptr;
303*70a7ec85SAndroid Build Coastguard Worker     }
304*70a7ec85SAndroid Build Coastguard Worker     const auto& arg = *args.begin();
305*70a7ec85SAndroid Build Coastguard Worker     auto colonPos = arg.rfind(":");
306*70a7ec85SAndroid Build Coastguard Worker     if (colonPos == std::string::npos) {
307*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: Invalid --kernel";
308*70a7ec85SAndroid Build Coastguard Worker         return nullptr;
309*70a7ec85SAndroid Build Coastguard Worker     }
310*70a7ec85SAndroid Build Coastguard Worker 
311*70a7ec85SAndroid Build Coastguard Worker     if (!parseKernelArgFirstHalf(arg.substr(0, colonPos), ret.get())) {
312*70a7ec85SAndroid Build Coastguard Worker         return nullptr;
313*70a7ec85SAndroid Build Coastguard Worker     }
314*70a7ec85SAndroid Build Coastguard Worker 
315*70a7ec85SAndroid Build Coastguard Worker     ret->kernelConfigFile = arg.substr(colonPos + 1);
316*70a7ec85SAndroid Build Coastguard Worker     return ret;
317*70a7ec85SAndroid Build Coastguard Worker }
318*70a7ec85SAndroid Build Coastguard Worker 
usage(const char * me)319*70a7ec85SAndroid Build Coastguard Worker int usage(const char* me) {
320*70a7ec85SAndroid Build Coastguard Worker     LOG(ERROR)
321*70a7ec85SAndroid Build Coastguard Worker         << me << ": check VINTF metadata." << std::endl
322*70a7ec85SAndroid Build Coastguard Worker         << "    Modes:" << std::endl
323*70a7ec85SAndroid Build Coastguard Worker         << "        --dump-file-list: Dump a list of directories / files on device" << std::endl
324*70a7ec85SAndroid Build Coastguard Worker         << "                that is required to be used by --check-compat." << std::endl
325*70a7ec85SAndroid Build Coastguard Worker         << "        -c, --check-compat: check compatibility for files under the root" << std::endl
326*70a7ec85SAndroid Build Coastguard Worker         << "                directory specified by --root-dir." << std::endl
327*70a7ec85SAndroid Build Coastguard Worker         << "        --check-one: check consistency of VINTF metadata for a single partition."
328*70a7ec85SAndroid Build Coastguard Worker         << std::endl
329*70a7ec85SAndroid Build Coastguard Worker         << std::endl
330*70a7ec85SAndroid Build Coastguard Worker         << "    Options:" << std::endl
331*70a7ec85SAndroid Build Coastguard Worker         << "        --rootdir=<dir>: specify root directory for all metadata. Same as " << std::endl
332*70a7ec85SAndroid Build Coastguard Worker         << "                --dirmap /:<dir>" << std::endl
333*70a7ec85SAndroid Build Coastguard Worker         << "        -D, --property <key>=<value>: specify sysprops." << std::endl
334*70a7ec85SAndroid Build Coastguard Worker         << "        --dirmap </system:/dir/to/system> [--dirmap </vendor:/dir/to/vendor>[...]]"
335*70a7ec85SAndroid Build Coastguard Worker         << std::endl
336*70a7ec85SAndroid Build Coastguard Worker         << "                Map partitions to directories. Cannot be specified with --rootdir."
337*70a7ec85SAndroid Build Coastguard Worker         << "        --kernel <version:path/to/config>" << std::endl
338*70a7ec85SAndroid Build Coastguard Worker         << "                Use the given kernel version and config to check. If" << std::endl
339*70a7ec85SAndroid Build Coastguard Worker         << "                unspecified, kernel requirements are skipped." << std::endl
340*70a7ec85SAndroid Build Coastguard Worker         << "                The first half, version, can be just x.y.z, or a file " << std::endl
341*70a7ec85SAndroid Build Coastguard Worker         << "                containing the full kernel release string x.y.z-something." << std::endl
342*70a7ec85SAndroid Build Coastguard Worker         << "        --help: show this message." << std::endl
343*70a7ec85SAndroid Build Coastguard Worker         << std::endl
344*70a7ec85SAndroid Build Coastguard Worker         << "    Example:" << std::endl
345*70a7ec85SAndroid Build Coastguard Worker         << "        # Get the list of required files." << std::endl
346*70a7ec85SAndroid Build Coastguard Worker         << "        " << me << " --dump-file-list > /tmp/files.txt" << std::endl
347*70a7ec85SAndroid Build Coastguard Worker         << "        # Pull from ADB, or use your own command to extract files from images"
348*70a7ec85SAndroid Build Coastguard Worker         << std::endl
349*70a7ec85SAndroid Build Coastguard Worker         << "        ROOTDIR=/tmp/device/" << std::endl
350*70a7ec85SAndroid Build Coastguard Worker         << "        cat /tmp/files.txt | xargs -I{} bash -c \"mkdir -p $ROOTDIR`dirname {}` && adb "
351*70a7ec85SAndroid Build Coastguard Worker            "pull {} $ROOTDIR{}\""
352*70a7ec85SAndroid Build Coastguard Worker         << std::endl
353*70a7ec85SAndroid Build Coastguard Worker         << "        # Check compatibility." << std::endl
354*70a7ec85SAndroid Build Coastguard Worker         << "        " << me << " --check-compat --rootdir=$ROOTDIR \\" << std::endl
355*70a7ec85SAndroid Build Coastguard Worker         << "            --property ro.product.first_api_level=`adb shell getprop "
356*70a7ec85SAndroid Build Coastguard Worker            "ro.product.first_api_level` \\"
357*70a7ec85SAndroid Build Coastguard Worker         << std::endl
358*70a7ec85SAndroid Build Coastguard Worker         << "            --property ro.boot.product.hardware.sku=`adb shell getprop "
359*70a7ec85SAndroid Build Coastguard Worker            "ro.boot.product.hardware.sku`";
360*70a7ec85SAndroid Build Coastguard Worker     return EX_USAGE;
361*70a7ec85SAndroid Build Coastguard Worker }
362*70a7ec85SAndroid Build Coastguard Worker 
363*70a7ec85SAndroid Build Coastguard Worker class CheckVintfUtils {
364*70a7ec85SAndroid Build Coastguard Worker    public:
365*70a7ec85SAndroid Build Coastguard Worker     // Print HALs in the device manifest that are not declared in FCMs <= target FCM version.
logHalsFromNewFcms(VintfObject * vintfObject,const std::vector<HidlInterfaceMetadata> & hidlMetadata)366*70a7ec85SAndroid Build Coastguard Worker     static void logHalsFromNewFcms(VintfObject* vintfObject,
367*70a7ec85SAndroid Build Coastguard Worker                                    const std::vector<HidlInterfaceMetadata>& hidlMetadata) {
368*70a7ec85SAndroid Build Coastguard Worker         auto deviceManifest = vintfObject->getDeviceHalManifest();
369*70a7ec85SAndroid Build Coastguard Worker         if (deviceManifest == nullptr) {
370*70a7ec85SAndroid Build Coastguard Worker             LOG(WARNING) << "Unable to print HALs from new FCMs: no device HAL manifest.";
371*70a7ec85SAndroid Build Coastguard Worker             return;
372*70a7ec85SAndroid Build Coastguard Worker         }
373*70a7ec85SAndroid Build Coastguard Worker         std::string kernelLevelError;
374*70a7ec85SAndroid Build Coastguard Worker         auto kernelLevel = vintfObject->getKernelLevel(&kernelLevelError);
375*70a7ec85SAndroid Build Coastguard Worker         if (kernelLevel == Level::UNSPECIFIED) {
376*70a7ec85SAndroid Build Coastguard Worker             LOG(WARNING) << "getKernelLevel: " << kernelLevel;
377*70a7ec85SAndroid Build Coastguard Worker         }
378*70a7ec85SAndroid Build Coastguard Worker         std::vector<CompatibilityMatrix> matrixFragments;
379*70a7ec85SAndroid Build Coastguard Worker         std::string error;
380*70a7ec85SAndroid Build Coastguard Worker         auto status = vintfObject->getAllFrameworkMatrixLevels(&matrixFragments, &error);
381*70a7ec85SAndroid Build Coastguard Worker         if (status != OK || matrixFragments.empty()) {
382*70a7ec85SAndroid Build Coastguard Worker             LOG(WARNING) << "Unable to print HALs from new FCMs: " << statusToString(status) << ": "
383*70a7ec85SAndroid Build Coastguard Worker                          << error;
384*70a7ec85SAndroid Build Coastguard Worker             return;
385*70a7ec85SAndroid Build Coastguard Worker         }
386*70a7ec85SAndroid Build Coastguard Worker         auto it = std::remove_if(matrixFragments.begin(), matrixFragments.end(),
387*70a7ec85SAndroid Build Coastguard Worker                                  [&](const CompatibilityMatrix& matrix) {
388*70a7ec85SAndroid Build Coastguard Worker                                      return matrix.level() != Level::UNSPECIFIED &&
389*70a7ec85SAndroid Build Coastguard Worker                                             matrix.level() > deviceManifest->level();
390*70a7ec85SAndroid Build Coastguard Worker                                  });
391*70a7ec85SAndroid Build Coastguard Worker         matrixFragments.erase(it, matrixFragments.end());
392*70a7ec85SAndroid Build Coastguard Worker         auto combined = CompatibilityMatrix::combine(deviceManifest->level(), kernelLevel,
393*70a7ec85SAndroid Build Coastguard Worker                                                      &matrixFragments, &error);
394*70a7ec85SAndroid Build Coastguard Worker         if (combined == nullptr) {
395*70a7ec85SAndroid Build Coastguard Worker             LOG(WARNING) << "Unable to print HALs from new FCMs: unable to combine matrix "
396*70a7ec85SAndroid Build Coastguard Worker                             "fragments <= level "
397*70a7ec85SAndroid Build Coastguard Worker                          << deviceManifest->level() << ": " << error;
398*70a7ec85SAndroid Build Coastguard Worker         }
399*70a7ec85SAndroid Build Coastguard Worker         auto unused = deviceManifest->checkUnusedHals(*combined, hidlMetadata);
400*70a7ec85SAndroid Build Coastguard Worker         if (unused.empty()) {
401*70a7ec85SAndroid Build Coastguard Worker             LOG(INFO) << "All HALs in device manifest are declared in FCM <= level "
402*70a7ec85SAndroid Build Coastguard Worker                       << deviceManifest->level();
403*70a7ec85SAndroid Build Coastguard Worker             return;
404*70a7ec85SAndroid Build Coastguard Worker         }
405*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "The following HALs in device manifest are not declared in FCM <= level "
406*70a7ec85SAndroid Build Coastguard Worker                   << deviceManifest->level() << ": ";
407*70a7ec85SAndroid Build Coastguard Worker         for (const auto& hal : unused) {
408*70a7ec85SAndroid Build Coastguard Worker             LOG(INFO) << "  " << hal;
409*70a7ec85SAndroid Build Coastguard Worker         }
410*70a7ec85SAndroid Build Coastguard Worker     }
411*70a7ec85SAndroid Build Coastguard Worker };
412*70a7ec85SAndroid Build Coastguard Worker 
413*70a7ec85SAndroid Build Coastguard Worker // If |result| is already an error, don't do anything. Otherwise, set it to
414*70a7ec85SAndroid Build Coastguard Worker // an error with |errorCode|. Return reference to Error object for appending
415*70a7ec85SAndroid Build Coastguard Worker // additional error messages.
SetErrorCode(std::optional<android::base::Error<>> * retError,int errorCode=0)416*70a7ec85SAndroid Build Coastguard Worker android::base::Error<>& SetErrorCode(std::optional<android::base::Error<>>* retError,
417*70a7ec85SAndroid Build Coastguard Worker                                      int errorCode = 0) {
418*70a7ec85SAndroid Build Coastguard Worker     if (!retError->has_value()) {
419*70a7ec85SAndroid Build Coastguard Worker         retError->emplace(errorCode);
420*70a7ec85SAndroid Build Coastguard Worker     } else {
421*70a7ec85SAndroid Build Coastguard Worker         // Use existing error code.
422*70a7ec85SAndroid Build Coastguard Worker         // There should already been an error message appended. Add a new line char for
423*70a7ec85SAndroid Build Coastguard Worker         // additional messages.
424*70a7ec85SAndroid Build Coastguard Worker         (**retError) << "\n";
425*70a7ec85SAndroid Build Coastguard Worker     }
426*70a7ec85SAndroid Build Coastguard Worker     return **retError;
427*70a7ec85SAndroid Build Coastguard Worker }
428*70a7ec85SAndroid Build Coastguard Worker 
429*70a7ec85SAndroid Build Coastguard Worker // If |other| is an error, add it to |retError|.
430*70a7ec85SAndroid Build Coastguard Worker template <typename T>
AddResult(std::optional<android::base::Error<>> * retError,const android::base::Result<T> & other,const char * additionalMessage="")431*70a7ec85SAndroid Build Coastguard Worker void AddResult(std::optional<android::base::Error<>>* retError,
432*70a7ec85SAndroid Build Coastguard Worker                const android::base::Result<T>& other, const char* additionalMessage = "") {
433*70a7ec85SAndroid Build Coastguard Worker     if (other.ok()) return;
434*70a7ec85SAndroid Build Coastguard Worker     SetErrorCode(retError, other.error().code()) << other.error() << additionalMessage;
435*70a7ec85SAndroid Build Coastguard Worker }
436*70a7ec85SAndroid Build Coastguard Worker 
437*70a7ec85SAndroid Build Coastguard Worker static constexpr const char* gCheckMissingHalsSuggestion{
438*70a7ec85SAndroid Build Coastguard Worker     "\n- If this is a new package, add it to the latest framework compatibility matrix."
439*70a7ec85SAndroid Build Coastguard Worker     "\n- If no interface should be added to the framework compatibility matrix (e.g. "
440*70a7ec85SAndroid Build Coastguard Worker     "types-only package), add it to the exempt list in libvintf_fcm_exclude."};
441*70a7ec85SAndroid Build Coastguard Worker 
checkAllFiles(const Dirmap & dirmap,const Properties & props,std::shared_ptr<StaticRuntimeInfo> runtimeInfo)442*70a7ec85SAndroid Build Coastguard Worker android::base::Result<void> checkAllFiles(const Dirmap& dirmap, const Properties& props,
443*70a7ec85SAndroid Build Coastguard Worker                                           std::shared_ptr<StaticRuntimeInfo> runtimeInfo) {
444*70a7ec85SAndroid Build Coastguard Worker     auto hostFileSystem = std::make_unique<HostFileSystem>(dirmap, UNKNOWN_ERROR);
445*70a7ec85SAndroid Build Coastguard Worker     auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
446*70a7ec85SAndroid Build Coastguard Worker     hostPropertyFetcher->setProperties(props);
447*70a7ec85SAndroid Build Coastguard Worker 
448*70a7ec85SAndroid Build Coastguard Worker     CheckFlags::Type flags = CheckFlags::DEFAULT;
449*70a7ec85SAndroid Build Coastguard Worker     if (!runtimeInfo) flags = flags.disableRuntimeInfo();
450*70a7ec85SAndroid Build Coastguard Worker 
451*70a7ec85SAndroid Build Coastguard Worker     auto vintfObject =
452*70a7ec85SAndroid Build Coastguard Worker         VintfObject::Builder()
453*70a7ec85SAndroid Build Coastguard Worker             .setFileSystem(std::move(hostFileSystem))
454*70a7ec85SAndroid Build Coastguard Worker             .setPropertyFetcher(std::move(hostPropertyFetcher))
455*70a7ec85SAndroid Build Coastguard Worker             .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(runtimeInfo))
456*70a7ec85SAndroid Build Coastguard Worker             .build();
457*70a7ec85SAndroid Build Coastguard Worker 
458*70a7ec85SAndroid Build Coastguard Worker     std::optional<android::base::Error<>> retError = std::nullopt;
459*70a7ec85SAndroid Build Coastguard Worker 
460*70a7ec85SAndroid Build Coastguard Worker     std::string compatibleError;
461*70a7ec85SAndroid Build Coastguard Worker     int compatibleResult = vintfObject->checkCompatibility(&compatibleError, flags);
462*70a7ec85SAndroid Build Coastguard Worker     if (compatibleResult == INCOMPATIBLE) {
463*70a7ec85SAndroid Build Coastguard Worker         SetErrorCode(&retError) << compatibleError;
464*70a7ec85SAndroid Build Coastguard Worker     } else if (compatibleResult != COMPATIBLE) {
465*70a7ec85SAndroid Build Coastguard Worker         SetErrorCode(&retError, -compatibleResult) << compatibleError;
466*70a7ec85SAndroid Build Coastguard Worker     }
467*70a7ec85SAndroid Build Coastguard Worker 
468*70a7ec85SAndroid Build Coastguard Worker     auto hidlMetadata = HidlInterfaceMetadata::all();
469*70a7ec85SAndroid Build Coastguard Worker 
470*70a7ec85SAndroid Build Coastguard Worker     std::string deprecateError;
471*70a7ec85SAndroid Build Coastguard Worker     int deprecateResult = vintfObject->checkDeprecation(hidlMetadata, &deprecateError);
472*70a7ec85SAndroid Build Coastguard Worker     if (deprecateResult == DEPRECATED) {
473*70a7ec85SAndroid Build Coastguard Worker         SetErrorCode(&retError) << deprecateError;
474*70a7ec85SAndroid Build Coastguard Worker     } else if (deprecateResult != NO_DEPRECATED_HALS) {
475*70a7ec85SAndroid Build Coastguard Worker         SetErrorCode(&retError, -deprecateResult) << deprecateError;
476*70a7ec85SAndroid Build Coastguard Worker     }
477*70a7ec85SAndroid Build Coastguard Worker 
478*70a7ec85SAndroid Build Coastguard Worker     auto hasFcmExt = vintfObject->hasFrameworkCompatibilityMatrixExtensions();
479*70a7ec85SAndroid Build Coastguard Worker     AddResult(&retError, hasFcmExt);
480*70a7ec85SAndroid Build Coastguard Worker 
481*70a7ec85SAndroid Build Coastguard Worker     auto deviceManifest = vintfObject->getDeviceHalManifest();
482*70a7ec85SAndroid Build Coastguard Worker     Level targetFcm = Level::UNSPECIFIED;
483*70a7ec85SAndroid Build Coastguard Worker     if (deviceManifest == nullptr) {
484*70a7ec85SAndroid Build Coastguard Worker         SetErrorCode(&retError, -NAME_NOT_FOUND) << "No device HAL manifest";
485*70a7ec85SAndroid Build Coastguard Worker     } else {
486*70a7ec85SAndroid Build Coastguard Worker         targetFcm = deviceManifest->level();
487*70a7ec85SAndroid Build Coastguard Worker     }
488*70a7ec85SAndroid Build Coastguard Worker 
489*70a7ec85SAndroid Build Coastguard Worker     if (hasFcmExt.value_or(false) || (targetFcm != Level::UNSPECIFIED && targetFcm >= Level::R)) {
490*70a7ec85SAndroid Build Coastguard Worker         AddResult(&retError, vintfObject->checkUnusedHals(hidlMetadata));
491*70a7ec85SAndroid Build Coastguard Worker     } else {
492*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "Skip checking unused HALs.";
493*70a7ec85SAndroid Build Coastguard Worker     }
494*70a7ec85SAndroid Build Coastguard Worker 
495*70a7ec85SAndroid Build Coastguard Worker     CheckVintfUtils::logHalsFromNewFcms(vintfObject.get(), hidlMetadata);
496*70a7ec85SAndroid Build Coastguard Worker 
497*70a7ec85SAndroid Build Coastguard Worker     if (retError.has_value()) {
498*70a7ec85SAndroid Build Coastguard Worker         return *retError;
499*70a7ec85SAndroid Build Coastguard Worker     } else {
500*70a7ec85SAndroid Build Coastguard Worker         return {};
501*70a7ec85SAndroid Build Coastguard Worker     }
502*70a7ec85SAndroid Build Coastguard Worker }
503*70a7ec85SAndroid Build Coastguard Worker 
504*70a7ec85SAndroid Build Coastguard Worker // Checks consistency of VINTF metadata for a single partition.
505*70a7ec85SAndroid Build Coastguard Worker // For now it supports either /system or /vendor.
checkOne(const Dirmap & dirmap,const Properties & props)506*70a7ec85SAndroid Build Coastguard Worker int checkOne(const Dirmap& dirmap, const Properties& props) {
507*70a7ec85SAndroid Build Coastguard Worker     if (dirmap.count("/system") + dirmap.count("/vendor") != 1) {
508*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: --check-one requires either --dirmap /system or --dirmap /vendor";
509*70a7ec85SAndroid Build Coastguard Worker         return EX_SOFTWARE;
510*70a7ec85SAndroid Build Coastguard Worker     }
511*70a7ec85SAndroid Build Coastguard Worker 
512*70a7ec85SAndroid Build Coastguard Worker     auto hostFileSystem = std::make_unique<HostFileSystem>(dirmap, NAME_NOT_FOUND);
513*70a7ec85SAndroid Build Coastguard Worker     auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
514*70a7ec85SAndroid Build Coastguard Worker     hostPropertyFetcher->setProperties(props);
515*70a7ec85SAndroid Build Coastguard Worker 
516*70a7ec85SAndroid Build Coastguard Worker     auto vintfObject =
517*70a7ec85SAndroid Build Coastguard Worker         VintfObject::Builder()
518*70a7ec85SAndroid Build Coastguard Worker             .setFileSystem(std::move(hostFileSystem))
519*70a7ec85SAndroid Build Coastguard Worker             .setPropertyFetcher(std::move(hostPropertyFetcher))
520*70a7ec85SAndroid Build Coastguard Worker             .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(nullptr))
521*70a7ec85SAndroid Build Coastguard Worker             .build();
522*70a7ec85SAndroid Build Coastguard Worker 
523*70a7ec85SAndroid Build Coastguard Worker     if (dirmap.count("/system")) {
524*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "Checking system manifest.";
525*70a7ec85SAndroid Build Coastguard Worker         auto manifest = vintfObject->getFrameworkHalManifest();
526*70a7ec85SAndroid Build Coastguard Worker         if (!manifest) {
527*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "ERROR: Cannot fetch system manifest.";
528*70a7ec85SAndroid Build Coastguard Worker             return EX_SOFTWARE;
529*70a7ec85SAndroid Build Coastguard Worker         }
530*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "Checking system matrix.";
531*70a7ec85SAndroid Build Coastguard Worker         auto matrix = vintfObject->getFrameworkCompatibilityMatrix();
532*70a7ec85SAndroid Build Coastguard Worker         if (!matrix) {
533*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "ERROR: Cannot fetch system matrix.";
534*70a7ec85SAndroid Build Coastguard Worker             return EX_SOFTWARE;
535*70a7ec85SAndroid Build Coastguard Worker         }
536*70a7ec85SAndroid Build Coastguard Worker         auto res = vintfObject->checkMissingHalsInMatrices(
537*70a7ec85SAndroid Build Coastguard Worker             HidlInterfaceMetadata::all(), AidlInterfaceMetadata::all(),
538*70a7ec85SAndroid Build Coastguard Worker             ShouldCheckMissingHidlHalsInFcm, ShouldCheckMissingAidlHalsInFcm);
539*70a7ec85SAndroid Build Coastguard Worker         if (!res.ok()) {
540*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "ERROR: " << res.error() << gCheckMissingHalsSuggestion;
541*70a7ec85SAndroid Build Coastguard Worker             return EX_SOFTWARE;
542*70a7ec85SAndroid Build Coastguard Worker         }
543*70a7ec85SAndroid Build Coastguard Worker 
544*70a7ec85SAndroid Build Coastguard Worker         res = vintfObject->checkMatrixHalsHasDefinition(HidlInterfaceMetadata::all(),
545*70a7ec85SAndroid Build Coastguard Worker                                                         AidlInterfaceMetadata::all());
546*70a7ec85SAndroid Build Coastguard Worker         if (!res.ok()) {
547*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "ERROR: " << res.error();
548*70a7ec85SAndroid Build Coastguard Worker             return EX_SOFTWARE;
549*70a7ec85SAndroid Build Coastguard Worker         }
550*70a7ec85SAndroid Build Coastguard Worker         return EX_OK;
551*70a7ec85SAndroid Build Coastguard Worker     }
552*70a7ec85SAndroid Build Coastguard Worker 
553*70a7ec85SAndroid Build Coastguard Worker     if (dirmap.count("/vendor")) {
554*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "Checking vendor manifest.";
555*70a7ec85SAndroid Build Coastguard Worker         auto manifest = vintfObject->getDeviceHalManifest();
556*70a7ec85SAndroid Build Coastguard Worker         if (!manifest) {
557*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "ERROR: Cannot fetch vendor manifest.";
558*70a7ec85SAndroid Build Coastguard Worker             return EX_SOFTWARE;
559*70a7ec85SAndroid Build Coastguard Worker         }
560*70a7ec85SAndroid Build Coastguard Worker         LOG(INFO) << "Checking vendor matrix.";
561*70a7ec85SAndroid Build Coastguard Worker         auto matrix = vintfObject->getDeviceCompatibilityMatrix();
562*70a7ec85SAndroid Build Coastguard Worker         if (!matrix) {
563*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "ERROR: Cannot fetch vendor matrix.";
564*70a7ec85SAndroid Build Coastguard Worker             return EX_SOFTWARE;
565*70a7ec85SAndroid Build Coastguard Worker         }
566*70a7ec85SAndroid Build Coastguard Worker         return EX_OK;
567*70a7ec85SAndroid Build Coastguard Worker     }
568*70a7ec85SAndroid Build Coastguard Worker 
569*70a7ec85SAndroid Build Coastguard Worker     __builtin_unreachable();
570*70a7ec85SAndroid Build Coastguard Worker }
571*70a7ec85SAndroid Build Coastguard Worker 
Logger(android::base::LogId,android::base::LogSeverity severity,const char *,const char *,unsigned int,const char * message)572*70a7ec85SAndroid Build Coastguard Worker void Logger(android::base::LogId, android::base::LogSeverity severity, const char* /*tag*/,
573*70a7ec85SAndroid Build Coastguard Worker             const char* /*file*/, unsigned int /*line*/, const char* message) {
574*70a7ec85SAndroid Build Coastguard Worker     if (severity >= android::base::WARNING) {
575*70a7ec85SAndroid Build Coastguard Worker         fflush(stdout);
576*70a7ec85SAndroid Build Coastguard Worker         fprintf(stderr, "%s\n", message);
577*70a7ec85SAndroid Build Coastguard Worker     } else {
578*70a7ec85SAndroid Build Coastguard Worker         fprintf(stdout, "%s\n", message);
579*70a7ec85SAndroid Build Coastguard Worker     }
580*70a7ec85SAndroid Build Coastguard Worker }
581*70a7ec85SAndroid Build Coastguard Worker 
582*70a7ec85SAndroid Build Coastguard Worker }  // namespace details
583*70a7ec85SAndroid Build Coastguard Worker }  // namespace vintf
584*70a7ec85SAndroid Build Coastguard Worker }  // namespace android
585*70a7ec85SAndroid Build Coastguard Worker 
main(int argc,char ** argv)586*70a7ec85SAndroid Build Coastguard Worker int main(int argc, char** argv) {
587*70a7ec85SAndroid Build Coastguard Worker     android::base::SetLogger(android::vintf::details::Logger);
588*70a7ec85SAndroid Build Coastguard Worker 
589*70a7ec85SAndroid Build Coastguard Worker     using namespace android::vintf;
590*70a7ec85SAndroid Build Coastguard Worker     using namespace android::vintf::details;
591*70a7ec85SAndroid Build Coastguard Worker     // legacy usage: check_vintf <manifest.xml> <matrix.xml>
592*70a7ec85SAndroid Build Coastguard Worker     if (argc == 3 && *argv[1] != '-' && *argv[2] != '-') {
593*70a7ec85SAndroid Build Coastguard Worker         int ret = checkCompatibilityForFiles(argv[1], argv[2]);
594*70a7ec85SAndroid Build Coastguard Worker         if (ret >= 0) return ret;
595*70a7ec85SAndroid Build Coastguard Worker     }
596*70a7ec85SAndroid Build Coastguard Worker 
597*70a7ec85SAndroid Build Coastguard Worker     Args args = parseArgs(argc, argv);
598*70a7ec85SAndroid Build Coastguard Worker 
599*70a7ec85SAndroid Build Coastguard Worker     if (!iterateValues(args, HELP).empty()) {
600*70a7ec85SAndroid Build Coastguard Worker         return usage(argv[0]);
601*70a7ec85SAndroid Build Coastguard Worker     }
602*70a7ec85SAndroid Build Coastguard Worker 
603*70a7ec85SAndroid Build Coastguard Worker     auto dirmap = getDirmap(iterateValues(args, DIR_MAP));
604*70a7ec85SAndroid Build Coastguard Worker     auto properties = getProperties(iterateValues(args, PROPERTY));
605*70a7ec85SAndroid Build Coastguard Worker     if (!iterateValues(args, DUMP_FILE_LIST).empty()) {
606*70a7ec85SAndroid Build Coastguard Worker         auto it = properties.find("ro.boot.product.hardware.sku");
607*70a7ec85SAndroid Build Coastguard Worker         const std::string sku = it == properties.end() ? "" : it->second;
608*70a7ec85SAndroid Build Coastguard Worker         for (const auto& file : dumpFileList(sku)) {
609*70a7ec85SAndroid Build Coastguard Worker             std::cout << file << std::endl;
610*70a7ec85SAndroid Build Coastguard Worker         }
611*70a7ec85SAndroid Build Coastguard Worker         return 0;
612*70a7ec85SAndroid Build Coastguard Worker     }
613*70a7ec85SAndroid Build Coastguard Worker 
614*70a7ec85SAndroid Build Coastguard Worker     if (!iterateValues(args, CHECK_ONE).empty()) {
615*70a7ec85SAndroid Build Coastguard Worker         return checkOne(dirmap, properties);
616*70a7ec85SAndroid Build Coastguard Worker     }
617*70a7ec85SAndroid Build Coastguard Worker 
618*70a7ec85SAndroid Build Coastguard Worker     auto checkCompat = iterateValues(args, CHECK_COMPAT);
619*70a7ec85SAndroid Build Coastguard Worker     if (checkCompat.empty()) {
620*70a7ec85SAndroid Build Coastguard Worker         return usage(argv[0]);
621*70a7ec85SAndroid Build Coastguard Worker     }
622*70a7ec85SAndroid Build Coastguard Worker 
623*70a7ec85SAndroid Build Coastguard Worker     auto rootdirs = iterateValues(args, ROOTDIR);
624*70a7ec85SAndroid Build Coastguard Worker     if (!rootdirs.empty()) {
625*70a7ec85SAndroid Build Coastguard Worker         if (std::distance(rootdirs.begin(), rootdirs.end()) > 1) {
626*70a7ec85SAndroid Build Coastguard Worker             LOG(ERROR) << "ERROR: Can't have multiple --rootdir options";
627*70a7ec85SAndroid Build Coastguard Worker             return usage(argv[0]);
628*70a7ec85SAndroid Build Coastguard Worker         }
629*70a7ec85SAndroid Build Coastguard Worker         args.emplace(DIR_MAP, "/:" + *rootdirs.begin());
630*70a7ec85SAndroid Build Coastguard Worker     }
631*70a7ec85SAndroid Build Coastguard Worker 
632*70a7ec85SAndroid Build Coastguard Worker     std::shared_ptr<StaticRuntimeInfo> runtimeInfo;
633*70a7ec85SAndroid Build Coastguard Worker     auto kernelArgs = iterateValues(args, KERNEL);
634*70a7ec85SAndroid Build Coastguard Worker     if (!kernelArgs.empty()) {
635*70a7ec85SAndroid Build Coastguard Worker         runtimeInfo = getRuntimeInfo(kernelArgs);
636*70a7ec85SAndroid Build Coastguard Worker         if (runtimeInfo == nullptr) {
637*70a7ec85SAndroid Build Coastguard Worker             return usage(argv[0]);
638*70a7ec85SAndroid Build Coastguard Worker         }
639*70a7ec85SAndroid Build Coastguard Worker     }
640*70a7ec85SAndroid Build Coastguard Worker 
641*70a7ec85SAndroid Build Coastguard Worker     if (dirmap.empty()) {
642*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: Missing --rootdir or --dirmap option.";
643*70a7ec85SAndroid Build Coastguard Worker         return usage(argv[0]);
644*70a7ec85SAndroid Build Coastguard Worker     }
645*70a7ec85SAndroid Build Coastguard Worker 
646*70a7ec85SAndroid Build Coastguard Worker     auto compat = checkAllFiles(dirmap, properties, runtimeInfo);
647*70a7ec85SAndroid Build Coastguard Worker 
648*70a7ec85SAndroid Build Coastguard Worker     if (compat.ok()) {
649*70a7ec85SAndroid Build Coastguard Worker         std::cout << "COMPATIBLE" << std::endl;
650*70a7ec85SAndroid Build Coastguard Worker         return EX_OK;
651*70a7ec85SAndroid Build Coastguard Worker     }
652*70a7ec85SAndroid Build Coastguard Worker     if (compat.error().code() == 0) {
653*70a7ec85SAndroid Build Coastguard Worker         LOG(ERROR) << "ERROR: files are incompatible: " << compat.error();
654*70a7ec85SAndroid Build Coastguard Worker         std::cout << "INCOMPATIBLE" << std::endl;
655*70a7ec85SAndroid Build Coastguard Worker         return EX_DATAERR;
656*70a7ec85SAndroid Build Coastguard Worker     }
657*70a7ec85SAndroid Build Coastguard Worker     LOG(ERROR) << "ERROR: " << strerror(compat.error().code()) << ": " << compat.error();
658*70a7ec85SAndroid Build Coastguard Worker     return EX_SOFTWARE;
659*70a7ec85SAndroid Build Coastguard Worker }
660