• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 
17 #include "Coordinator.h"
18 
19 #include <dirent.h>
20 #include <sys/stat.h>
21 
22 #include <algorithm>
23 #include <iterator>
24 
25 #include <android-base/logging.h>
26 #include <hidl-hash/Hash.h>
27 #include <hidl-util/Formatter.h>
28 #include <hidl-util/StringHelper.h>
29 #include <iostream>
30 
31 #include "AST.h"
32 #include "Interface.h"
33 #include "hidl-gen_l.h"
34 
existdir(const char * name)35 static bool existdir(const char *name) {
36     DIR *dir = opendir(name);
37     if (dir == nullptr) {
38         return false;
39     }
40     closedir(dir);
41     return true;
42 }
43 
44 namespace android {
45 
getRootPath() const46 const std::string &Coordinator::getRootPath() const {
47     return mRootPath;
48 }
49 
setRootPath(const std::string & rootPath)50 void Coordinator::setRootPath(const std::string &rootPath) {
51     mRootPath = rootPath;
52 
53     if (!mRootPath.empty() && !StringHelper::EndsWith(mRootPath, "/")) {
54         mRootPath += "/";
55     }
56 }
57 
setOutputPath(const std::string & outputPath)58 void Coordinator::setOutputPath(const std::string& outputPath) {
59     mOutputPath = outputPath;
60 }
61 
setVerbose(bool verbose)62 void Coordinator::setVerbose(bool verbose) {
63     mVerbose = verbose;
64 }
65 
setRequireFrozen(bool requireFrozen)66 void Coordinator::setRequireFrozen(bool requireFrozen) {
67     mRequireFrozen = requireFrozen;
68 }
69 
isVerbose() const70 bool Coordinator::isVerbose() const {
71     return mVerbose;
72 }
73 
setDepFile(const std::string & depFile)74 void Coordinator::setDepFile(const std::string& depFile) {
75     mDepFile = depFile;
76 }
77 
getOwner() const78 const std::string& Coordinator::getOwner() const {
79     return mOwner;
80 }
setOwner(const std::string & owner)81 void Coordinator::setOwner(const std::string& owner) {
82     mOwner = owner;
83 }
84 
addPackagePath(const std::string & root,const std::string & path,std::string * error)85 status_t Coordinator::addPackagePath(const std::string& root, const std::string& path, std::string* error) {
86     FQName package = FQName(root, "0.0", "");
87     for (const PackageRoot &packageRoot : mPackageRoots) {
88         if (packageRoot.root.inPackage(root) || package.inPackage(packageRoot.root.package())) {
89             if (error != nullptr) {
90                 *error = "ERROR: conflicting package roots " +
91                          packageRoot.root.package() +
92                          " and " +
93                          root;
94             }
95 
96             return UNKNOWN_ERROR;
97         }
98     }
99 
100     mPackageRoots.push_back({path, package});
101     return OK;
102 }
addDefaultPackagePath(const std::string & root,const std::string & path)103 void Coordinator::addDefaultPackagePath(const std::string& root, const std::string& path) {
104     addPackagePath(root, path, nullptr /* error */);
105 }
106 
getFormatter(const FQName & fqName,Location location,const std::string & fileName) const107 Formatter Coordinator::getFormatter(const FQName& fqName, Location location,
108                                     const std::string& fileName) const {
109     if (location == Location::STANDARD_OUT) {
110         return Formatter(stdout);
111     }
112 
113     std::string filepath;
114     status_t err = getFilepath(fqName, location, fileName, &filepath);
115     if (err != OK) {
116         return Formatter::invalid();
117     }
118 
119     onFileAccess(filepath, "w");
120 
121     if (!Coordinator::MakeParentHierarchy(filepath)) {
122         fprintf(stderr, "ERROR: could not make directories for %s.\n", filepath.c_str());
123         return Formatter::invalid();
124     }
125 
126     FILE* file = fopen(filepath.c_str(), "w");
127 
128     if (file == nullptr) {
129         fprintf(stderr, "ERROR: could not open file %s: %d\n", filepath.c_str(), errno);
130         return Formatter::invalid();
131     }
132 
133     return Formatter(file);
134 }
135 
getFilepath(const FQName & fqName,Location location,const std::string & fileName,std::string * path) const136 status_t Coordinator::getFilepath(const FQName& fqName, Location location,
137                                   const std::string& fileName, std::string* path) const {
138     status_t err;
139     std::string packagePath;
140     std::string packageRootPath;
141 
142     switch (location) {
143         case Location::DIRECT: { /* nothing */
144             *path = mOutputPath + fileName;
145         } break;
146         case Location::PACKAGE_ROOT: {
147             err = getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath);
148             if (err != OK) return err;
149 
150             *path = mOutputPath + packagePath + fileName;
151         } break;
152         case Location::GEN_OUTPUT: {
153             err = convertPackageRootToPath(fqName, &packageRootPath);
154             if (err != OK) return err;
155             err = getPackagePath(fqName, true /* relative */, false /* sanitized */, &packagePath);
156             if (err != OK) return err;
157 
158             *path = mOutputPath + packageRootPath + packagePath + fileName;
159         } break;
160         case Location::GEN_SANITIZED: {
161             err = convertPackageRootToPath(fqName, &packageRootPath);
162             if (err != OK) return err;
163             err = getPackagePath(fqName, true /* relative */, true /* sanitized */, &packagePath);
164             if (err != OK) return err;
165 
166             *path = mOutputPath + packageRootPath + packagePath + fileName;
167         } break;
168         default: { CHECK(false) << "Invalid location: " << static_cast<size_t>(location); }
169     }
170 
171     return OK;
172 }
173 
onFileAccess(const std::string & path,const std::string & mode) const174 void Coordinator::onFileAccess(const std::string& path, const std::string& mode) const {
175     if (mode == "r") {
176         // This is a global list. It's not cleared when a second fqname is processed for
177         // two reasons:
178         // 1). If there is a bug in hidl-gen, the dependencies on the first project from
179         //     the second would be required to recover correctly when the bug is fixed.
180         // 2). This option is never used in Android builds.
181         mReadFiles.insert(makeRelative(path));
182     }
183 
184     if (!mVerbose) {
185         return;
186     }
187 
188     fprintf(stderr,
189             "VERBOSE: file access %s %s\n", path.c_str(), mode.c_str());
190 }
191 
writeDepFile(const std::string & forFile) const192 status_t Coordinator::writeDepFile(const std::string& forFile) const {
193     // No dep file requested
194     if (mDepFile.empty()) return OK;
195 
196     onFileAccess(mDepFile, "w");
197 
198     FILE* file = fopen(mDepFile.c_str(), "w");
199     if (file == nullptr) {
200         fprintf(stderr, "ERROR: could not open dep file at %s.\n", mDepFile.c_str());
201         return UNKNOWN_ERROR;
202     }
203 
204     Formatter out(file, 2 /* spacesPerIndent */);
205     out << StringHelper::LTrim(forFile, mOutputPath) << ": \\\n";
206     out.indent([&] {
207         for (const std::string& file : mReadFiles) {
208             out << makeRelative(file) << " \\\n";
209         }
210     });
211     return OK;
212 }
213 
parse(const FQName & fqName,std::set<AST * > * parsedASTs,Enforce enforcement) const214 AST* Coordinator::parse(const FQName& fqName, std::set<AST*>* parsedASTs,
215                         Enforce enforcement) const {
216     AST* ret;
217     status_t err = parseOptional(fqName, &ret, parsedASTs, enforcement);
218     if (err != OK) CHECK(ret == nullptr);  // internal consistency
219 
220     // only in a handful of places do we want to distinguish between
221     // a missing file and a bad AST. Everywhere else, we just want to
222     // throw an error if we expect an AST to be present but it is not.
223     return ret;
224 }
225 
parseOptional(const FQName & fqName,AST ** ast,std::set<AST * > * parsedASTs,Enforce enforcement) const226 status_t Coordinator::parseOptional(const FQName& fqName, AST** ast, std::set<AST*>* parsedASTs,
227                                     Enforce enforcement) const {
228     CHECK(fqName.isFullyQualified());
229 
230     auto it = mCache.find(fqName);
231     if (it != mCache.end()) {
232         *ast = (*it).second;
233 
234         if (*ast != nullptr && parsedASTs != nullptr) {
235             parsedASTs->insert(*ast);
236         }
237 
238         if (*ast == nullptr) {
239             // circular import OR that AST has errors in it
240             return UNKNOWN_ERROR;
241         }
242 
243         return OK;
244     }
245 
246     // Add this to the cache immediately, so we can discover circular imports.
247     mCache[fqName] = nullptr;
248 
249     std::string packagePath;
250     status_t err =
251         getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath);
252     if (err != OK) return err;
253 
254     const std::string path = makeAbsolute(packagePath + fqName.name() + ".hal");
255 
256     *ast = new AST(this, &Hash::getHash(path));
257 
258     if (fqName.name() != "types") {
259         // If types.hal for this AST's package existed, make it's defined
260         // types available to the (about to be parsed) AST right away.
261         (*ast)->addImplicitImport(fqName.getTypesForPackage());
262     }
263 
264     std::unique_ptr<FILE, std::function<void(FILE*)>> file(fopen(path.c_str(), "rb"), fclose);
265 
266     if (file == nullptr) {
267         mCache.erase(fqName);  // nullptr in cache is used to find circular imports
268         delete *ast;
269         *ast = nullptr;
270         return OK;  // File does not exist, nullptr AST* == file doesn't exist.
271     }
272 
273     onFileAccess(path, "r");
274 
275     // parse file takes ownership of file
276     if (parseFile(*ast, std::move(file)) != OK || (*ast)->postParse() != OK) {
277         delete *ast;
278         *ast = nullptr;
279         return UNKNOWN_ERROR;
280     }
281 
282     if ((*ast)->package().package() != fqName.package() ||
283         (*ast)->package().version() != fqName.version()) {
284         fprintf(stderr,
285                 "ERROR: File at '%s' does not match expected package and/or "
286                 "version.\n",
287                 path.c_str());
288 
289         err = UNKNOWN_ERROR;
290     } else {
291         if ((*ast)->isInterface()) {
292             if (fqName.name() == "types") {
293                 fprintf(stderr,
294                         "ERROR: File at '%s' declares an interface '%s' "
295                         "instead of the expected types common to the package.\n",
296                         path.c_str(), (*ast)->getInterface()->definedName().c_str());
297 
298                 err = UNKNOWN_ERROR;
299             } else if ((*ast)->getInterface()->definedName() != fqName.name()) {
300                 fprintf(stderr,
301                         "ERROR: File at '%s' does not declare interface type "
302                         "'%s'.\n",
303                         path.c_str(),
304                         fqName.name().c_str());
305 
306                 err = UNKNOWN_ERROR;
307             }
308         } else if (fqName.name() != "types") {
309             fprintf(stderr,
310                     "ERROR: File at '%s' declares types rather than the "
311                     "expected interface type '%s'.\n",
312                     path.c_str(),
313                     fqName.name().c_str());
314 
315             err = UNKNOWN_ERROR;
316         } else if ((*ast)->definesInterfaces()) {
317             fprintf(stderr,
318                     "ERROR: types.hal file at '%s' declares at least one "
319                     "interface type.\n",
320                     path.c_str());
321 
322             err = UNKNOWN_ERROR;
323         }
324     }
325 
326     if (err != OK) {
327         delete *ast;
328         *ast = nullptr;
329         return err;
330     }
331 
332     if (parsedASTs != nullptr) {
333         parsedASTs->insert(*ast);
334     }
335 
336     // put it into the cache now, so that enforceRestrictionsOnPackage can
337     // parse fqName.
338     mCache[fqName] = *ast;
339 
340     // For each .hal file that hidl-gen parses, the whole package will be checked.
341     err = enforceRestrictionsOnPackage(fqName, enforcement);
342     if (err != OK) {
343         mCache[fqName] = nullptr;
344         delete *ast;
345         *ast = nullptr;
346         return err;
347     }
348 
349     return OK;
350 }
351 
findPackageRoot(const FQName & fqName) const352 const Coordinator::PackageRoot* Coordinator::findPackageRoot(const FQName& fqName) const {
353     CHECK(!fqName.package().empty()) << fqName.string();
354 
355     // Find the right package prefix and path for this FQName.  For
356     // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
357     // prefix:root is set to [ "android.hardware:hardware/interfaces",
358     // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
359     // prefix "android.hardware" and the package root
360     // "hardware/interfaces".
361 
362     auto ret = mPackageRoots.end();
363     for (auto it = mPackageRoots.begin(); it != mPackageRoots.end(); it++) {
364         if (!fqName.inPackage(it->root.package())) {
365             continue;
366         }
367 
368         if (ret != mPackageRoots.end()) {
369             std::cerr << "ERROR: Multiple package roots found for " << fqName.string() << " ("
370                       << it->root.package() << " and " << ret->root.package() << ")\n";
371             return nullptr;
372         }
373 
374         ret = it;
375     }
376 
377     if (ret == mPackageRoots.end()) {
378         std::cerr << "ERROR: Package root not specified for " << fqName.string() << "\n";
379         return nullptr;
380     }
381 
382     return &(*ret);
383 }
384 
makeAbsolute(const std::string & path) const385 std::string Coordinator::makeAbsolute(const std::string& path) const {
386     if (StringHelper::StartsWith(path, "/") || mRootPath.empty()) {
387         return path;
388     }
389 
390     return mRootPath + path;
391 }
392 
makeRelative(const std::string & filename) const393 std::string Coordinator::makeRelative(const std::string& filename) const {
394     return StringHelper::LTrim(filename, mRootPath);
395 }
396 
getPackageRoot(const FQName & fqName,std::string * root) const397 status_t Coordinator::getPackageRoot(const FQName& fqName, std::string* root) const {
398     const PackageRoot* packageRoot = findPackageRoot(fqName);
399     if (packageRoot == nullptr) {
400         return UNKNOWN_ERROR;
401     }
402     *root = packageRoot->root.package();
403     return OK;
404 }
405 
getPackageRootPath(const FQName & fqName,std::string * path) const406 status_t Coordinator::getPackageRootPath(const FQName& fqName, std::string* path) const {
407     const PackageRoot* packageRoot = findPackageRoot(fqName);
408     if (packageRoot == nullptr) {
409         return UNKNOWN_ERROR;
410     }
411     *path = packageRoot->path;
412     return OK;
413 }
414 
getPackagePath(const FQName & fqName,bool relative,bool sanitized,std::string * path) const415 status_t Coordinator::getPackagePath(const FQName& fqName, bool relative, bool sanitized,
416                                      std::string* path) const {
417     const PackageRoot* packageRoot = findPackageRoot(fqName);
418     if (packageRoot == nullptr) return UNKNOWN_ERROR;
419 
420     // Given FQName of "android.hardware.nfc.test@1.0::IFoo" and a prefix
421     // "android.hardware", the suffix is "nfc.test".
422     std::string suffix = StringHelper::LTrim(fqName.package(), packageRoot->root.package());
423     suffix = StringHelper::LTrim(suffix, ".");
424 
425     std::vector<std::string> suffixComponents;
426     StringHelper::SplitString(suffix, '.', &suffixComponents);
427 
428     std::vector<std::string> components;
429     if (!relative) {
430         components.push_back(StringHelper::RTrimAll(packageRoot->path, "/"));
431     }
432     components.insert(components.end(), suffixComponents.begin(), suffixComponents.end());
433     components.push_back(sanitized ? fqName.sanitizedVersion() : fqName.version());
434 
435     *path = StringHelper::JoinStrings(components, "/") + "/";
436     return OK;
437 }
438 
getPackageInterfaceFiles(const FQName & package,std::vector<std::string> * fileNames) const439 status_t Coordinator::getPackageInterfaceFiles(
440         const FQName &package,
441         std::vector<std::string> *fileNames) const {
442     if (fileNames) fileNames->clear();
443 
444     std::string packagePath;
445     status_t err =
446         getPackagePath(package, false /* relative */, false /* sanitized */, &packagePath);
447     if (err != OK) return err;
448 
449     const std::string path = makeAbsolute(packagePath);
450     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
451 
452     if (dir == nullptr) {
453         fprintf(stderr, "ERROR: Could not open package path %s for package %s:\n%s\n",
454                 packagePath.c_str(), package.string().c_str(), path.c_str());
455         return -errno;
456     }
457 
458     if (fileNames == nullptr) {
459         return OK;
460     }
461 
462     struct dirent *ent;
463     while ((ent = readdir(dir.get())) != nullptr) {
464         // filesystems may not support d_type and return DT_UNKNOWN
465         if (ent->d_type == DT_UNKNOWN) {
466             struct stat sb;
467             const auto filename = packagePath + std::string(ent->d_name);
468             if (stat(filename.c_str(), &sb) == -1) {
469                 fprintf(stderr, "ERROR: Could not stat %s\n", filename.c_str());
470                 return -errno;
471             }
472             if ((sb.st_mode & S_IFMT) != S_IFREG) {
473                 continue;
474             }
475         } else if (ent->d_type != DT_REG) {
476              continue;
477         }
478 
479         const auto suffix = ".hal";
480         const auto suffix_len = std::strlen(suffix);
481         const auto d_namelen = strlen(ent->d_name);
482 
483         if (d_namelen < suffix_len
484                 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
485             continue;
486         }
487 
488         fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
489     }
490 
491     std::sort(fileNames->begin(), fileNames->end(),
492               [](const std::string& lhs, const std::string& rhs) -> bool {
493                   if (lhs == "types") {
494                       return true;
495                   }
496                   if (rhs == "types") {
497                       return false;
498                   }
499                   return lhs < rhs;
500               });
501 
502     return OK;
503 }
504 
appendPackageInterfacesToVector(const FQName & package,std::vector<FQName> * packageInterfaces) const505 status_t Coordinator::appendPackageInterfacesToVector(
506         const FQName &package,
507         std::vector<FQName> *packageInterfaces) const {
508     packageInterfaces->clear();
509 
510     std::vector<std::string> fileNames;
511     status_t err = getPackageInterfaceFiles(package, &fileNames);
512 
513     if (err != OK) {
514         return err;
515     }
516 
517     for (const auto &fileName : fileNames) {
518         FQName subFQName(package.package(), package.version(), fileName);
519         packageInterfaces->push_back(subFQName);
520     }
521 
522     return OK;
523 }
524 
convertPackageRootToPath(const FQName & fqName,std::string * path) const525 status_t Coordinator::convertPackageRootToPath(const FQName& fqName, std::string* path) const {
526     std::string packageRoot;
527     status_t err = getPackageRoot(fqName, &packageRoot);
528     if (err != OK) return err;
529 
530     if (*(packageRoot.end()--) != '.') {
531         packageRoot += '.';
532     }
533 
534     std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
535 
536     *path = packageRoot;  // now converted to a path
537     return OK;
538 }
539 
isTypesOnlyPackage(const FQName & package,bool * result) const540 status_t Coordinator::isTypesOnlyPackage(const FQName& package, bool* result) const {
541     std::vector<FQName> packageInterfaces;
542 
543     status_t err = appendPackageInterfacesToVector(package, &packageInterfaces);
544 
545     if (err != OK) {
546         *result = false;
547         return err;
548     }
549 
550     *result = packageInterfaces.size() == 1 && packageInterfaces[0].name() == "types";
551     return OK;
552 }
553 
addUnreferencedTypes(const std::vector<FQName> & packageInterfaces,std::set<FQName> * unreferencedDefinitions,std::set<FQName> * unreferencedImports) const554 status_t Coordinator::addUnreferencedTypes(const std::vector<FQName>& packageInterfaces,
555                                            std::set<FQName>* unreferencedDefinitions,
556                                            std::set<FQName>* unreferencedImports) const {
557     CHECK(unreferencedDefinitions != nullptr);
558     CHECK(unreferencedImports != nullptr);
559 
560     std::set<FQName> packageDefinedTypes;
561     std::set<FQName> packageReferencedTypes;
562     std::set<FQName> packageImportedTypes;
563     std::set<FQName> typesDefinedTypes;  // only types.hal types
564 
565     for (const auto& fqName : packageInterfaces) {
566         AST* ast = parse(fqName, nullptr /*imported*/, Coordinator::Enforce::NONE);
567         if (!ast) {
568             std::cerr << "ERROR: Could not parse " << fqName.string() << ". Aborting." << std::endl;
569 
570             return UNKNOWN_ERROR;
571         }
572 
573         ast->addDefinedTypes(&packageDefinedTypes);
574         ast->addReferencedTypes(&packageReferencedTypes);
575         ast->getAllImportedNamesGranular(&packageImportedTypes);
576 
577         if (fqName.name() == "types") {
578             ast->addDefinedTypes(&typesDefinedTypes);
579         }
580     }
581 
582 #if 0
583     for (const auto &fqName : packageDefinedTypes) {
584         std::cout << "VERBOSE: DEFINED " << fqName.string() << std::endl;
585     }
586 
587     for (const auto &fqName : packageImportedTypes) {
588         std::cout << "VERBOSE: IMPORTED " << fqName.string() << std::endl;
589     }
590 
591     for (const auto &fqName : packageReferencedTypes) {
592         std::cout << "VERBOSE: REFERENCED " << fqName.string() << std::endl;
593     }
594 
595     for (const auto &fqName : typesDefinedTypes) {
596         std::cout << "VERBOSE: DEFINED in types.hal " << fqName.string() << std::endl;
597     }
598 #endif
599 
600     for (const auto& fqName : packageReferencedTypes) {
601         packageDefinedTypes.erase(fqName);
602         packageImportedTypes.erase(fqName);
603     }
604 
605     // A package implicitly imports its own types.hal, only track them in one set.
606     for (const auto& fqName : typesDefinedTypes) {
607         packageImportedTypes.erase(fqName);
608     }
609 
610     // defined but not referenced
611     unreferencedDefinitions->insert(packageDefinedTypes.begin(), packageDefinedTypes.end());
612     // imported but not referenced
613     unreferencedImports->insert(packageImportedTypes.begin(), packageImportedTypes.end());
614     return OK;
615 }
616 
enforceRestrictionsOnPackage(const FQName & fqName,Enforce enforcement) const617 status_t Coordinator::enforceRestrictionsOnPackage(const FQName& fqName,
618                                                    Enforce enforcement) const {
619     CHECK(enforcement == Enforce::FULL || enforcement == Enforce::NO_HASH ||
620           enforcement == Enforce::NONE);
621 
622     // need fqName to be something like android.hardware.foo@1.0.
623     // name and valueName is ignored.
624     if (fqName.package().empty() || fqName.version().empty()) {
625         std::cerr << "ERROR: Cannot enforce restrictions on package " << fqName.string()
626                   << ": package or version is missing." << std::endl;
627         return BAD_VALUE;
628     }
629 
630     if (enforcement == Enforce::NONE) {
631         return OK;
632     }
633 
634     FQName package = fqName.getPackageAndVersion();
635     // look up cache.
636     if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) {
637         return OK;
638     }
639 
640     // enforce all rules.
641     status_t err;
642 
643     err = enforceMinorVersionUprevs(package, enforcement);
644     if (err != OK) {
645         return err;
646     }
647 
648     if (enforcement != Enforce::NO_HASH) {
649         err = enforceHashes(package);
650         if (err != OK) {
651             return err;
652         }
653     }
654 
655     // cache it so that it won't need to be enforced again.
656     mPackagesEnforced.insert(package);
657     return OK;
658 }
659 
packageExists(const FQName & package,bool * result) const660 status_t Coordinator::packageExists(const FQName& package, bool* result) const {
661     std::string packagePath;
662     status_t err =
663             getPackagePath(package, false /* relative */, false /* sanitized */, &packagePath);
664     if (err != OK) return err;
665 
666     if (existdir(makeAbsolute(packagePath).c_str())) {
667         *result = true;
668         return OK;
669     }
670 
671     *result = false;
672     return OK;
673 }
674 
enforceMinorVersionUprevs(const FQName & currentPackage,Enforce enforcement) const675 status_t Coordinator::enforceMinorVersionUprevs(const FQName& currentPackage,
676                                                 Enforce enforcement) const {
677     if(!currentPackage.hasVersion()) {
678         std::cerr << "ERROR: Cannot enforce minor version uprevs for " << currentPackage.string()
679                   << ": missing version." << std::endl;
680         return UNKNOWN_ERROR;
681     }
682 
683     if (currentPackage.getPackageMinorVersion() == 0) {
684         return OK; // ignore for @x.0
685     }
686 
687     bool hasPrevPackage = false;
688     FQName prevPackage = currentPackage;
689     while (prevPackage.getPackageMinorVersion() > 0) {
690         prevPackage = prevPackage.downRev();
691 
692         bool result;
693         status_t err = packageExists(prevPackage, &result);
694         if (err != OK) return err;
695 
696         if (result) {
697             hasPrevPackage = true;
698             break;
699         }
700     }
701     if (!hasPrevPackage) {
702         // no @x.z, where z < y, exist.
703         return OK;
704     }
705 
706     if (prevPackage != currentPackage.downRev()) {
707         std::cerr << "ERROR: Cannot enforce minor version uprevs for " << currentPackage.string()
708                   << ": Found package " << prevPackage.string() << " but missing "
709                   << currentPackage.downRev().string() << "; you cannot skip a minor version."
710                   << std::endl;
711         return UNKNOWN_ERROR;
712     }
713 
714     bool prevIsTypesOnly;
715     status_t err = isTypesOnlyPackage(prevPackage, &prevIsTypesOnly);
716     if (err != OK) return err;
717 
718     if (prevIsTypesOnly) {
719         // A types only package can be extended in any way.
720         return OK;
721     }
722 
723     std::vector<FQName> packageInterfaces;
724     err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
725     if (err != OK) {
726         return err;
727     }
728 
729     bool extendedInterface = false;
730     for (const FQName &currentFQName : packageInterfaces) {
731         if (currentFQName.name() == "types") {
732             continue; // ignore types.hal
733         }
734 
735         const Interface *iface = nullptr;
736         AST* currentAST = parse(currentFQName, nullptr /* parsedASTs */, enforcement);
737         if (currentAST != nullptr) {
738             iface = currentAST->getInterface();
739         }
740         if (iface == nullptr) {
741             if (currentAST == nullptr) {
742                 std::cerr << "WARNING: Skipping " << currentFQName.string()
743                           << " because it could not be found or parsed"
744                           << " or " << currentPackage.string() << " doesn't pass all requirements."
745                           << std::endl;
746             } else {
747                 std::cerr << "WARNING: Skipping " << currentFQName.string()
748                           << " because the file might contain more than one interface."
749                           << std::endl;
750             }
751             continue;
752         }
753 
754         if (iface->superType() == nullptr) {
755             CHECK(iface->isIBase());
756             continue;
757         }
758 
759         // Assume that currentFQName == android.hardware.foo@2.2::IFoo.
760         FQName lastFQName(prevPackage.package(), prevPackage.version(),
761                 currentFQName.name());
762         AST *lastAST = parse(lastFQName);
763 
764         for (; lastFQName.getPackageMinorVersion() > 0 &&
765                (lastAST == nullptr || lastAST->getInterface() == nullptr)
766              ; lastFQName = lastFQName.downRev(), lastAST = parse(lastFQName)) {
767             // nothing
768         }
769 
770         // Then lastFQName == android.hardware.foo@2.1::IFoo or
771         //      lastFQName == android.hardware.foo@2.0::IFoo if 2.1 doesn't exist.
772 
773         bool lastFQNameExists = lastAST != nullptr && lastAST->getInterface() != nullptr;
774 
775         if (!lastFQNameExists) {
776             continue;
777         }
778 
779         if (iface->superType()->fqName() != lastFQName) {
780             std::cerr << "ERROR: Cannot enforce minor version uprevs for "
781                       << currentPackage.string() << ": " << iface->fqName().string() << " extends "
782                       << iface->superType()->fqName().string()
783                       << ", which is not allowed. It must extend " << lastFQName.string()
784                       << std::endl;
785             return UNKNOWN_ERROR;
786         }
787 
788         // at least one interface must extend the previous version
789         // @2.0::IFoo does not work. It must be @2.1::IFoo for at least one interface.
790         if (lastFQName.getPackageAndVersion() == prevPackage.getPackageAndVersion()) {
791             extendedInterface = true;
792         }
793 
794         if (mVerbose) {
795             std::cout << "VERBOSE: EnforceMinorVersionUprevs: " << currentFQName.string()
796                       << " passes." << std::endl;
797         }
798     }
799 
800     if (!extendedInterface) {
801         // No interface extends the interface with the same name in @x.(y-1).
802         std::cerr << "ERROR: " << currentPackage.string()
803                   << " doesn't pass minor version uprev requirement. "
804                   << "Requires at least one interface to extend an interface with the same name "
805                   << "from " << prevPackage.string() << "." << std::endl;
806         return UNKNOWN_ERROR;
807     }
808 
809     return OK;
810 }
811 
checkHash(const FQName & fqName) const812 Coordinator::HashStatus Coordinator::checkHash(const FQName& fqName) const {
813     AST* ast = parse(fqName);
814     if (ast == nullptr) return HashStatus::ERROR;
815 
816     std::string rootPath;
817     status_t err = getPackageRootPath(fqName, &rootPath);
818     if (err != OK) return HashStatus::ERROR;
819 
820     std::string hashPath = makeAbsolute(rootPath) + "/current.txt";
821     std::string error;
822     bool fileExists;
823     std::vector<std::string> frozen =
824         Hash::lookupHash(hashPath, fqName.string(), &error, &fileExists);
825     if (fileExists) onFileAccess(hashPath, "r");
826 
827     if (error.size() > 0) {
828         std::cerr << "ERROR: " << error << std::endl;
829         return HashStatus::ERROR;
830     }
831 
832     // hash not defined, interface not frozen
833     if (frozen.size() == 0) {
834         if (isVerbose()) {
835             std::cerr << "VERBOSE: clearing runtime hash for " << fqName.string()
836                       << " because it is not frozen and so its hash cannot be depended upon as an "
837                          "indication of stability."
838                       << std::endl;
839         }
840         // This ensures that it can be detected.
841         Hash::clearHash(ast->getFilename());
842 
843         if (mRequireFrozen) {
844             std::cerr << "ERROR: Unfrozen " << fqName.string()
845                       << " cannot be referenced from context specifying -F (require_frozen)."
846                       << std::endl;
847             return HashStatus::ERROR;
848         }
849 
850         return HashStatus::UNFROZEN;
851     }
852 
853     std::string currentHash = ast->getFileHash()->hexString();
854 
855     if (std::find(frozen.begin(), frozen.end(), currentHash) == frozen.end()) {
856         std::cerr << "ERROR: " << fqName.string() << " has hash " << currentHash
857                   << " which does not match hash on record. This interface has "
858                   << "been frozen. Do not change it!" << std::endl;
859         return HashStatus::CHANGED;
860     }
861 
862     return HashStatus::FROZEN;
863 }
864 
getUnfrozenDependencies(const FQName & fqName,std::set<FQName> * result) const865 status_t Coordinator::getUnfrozenDependencies(const FQName& fqName,
866                                               std::set<FQName>* result) const {
867     CHECK(result != nullptr);
868 
869     AST* ast = parse(fqName);
870     if (ast == nullptr) return UNKNOWN_ERROR;
871 
872     std::set<FQName> imported;
873     ast->getImportedPackages(&imported);
874 
875     // consider current package as dependency for types.hal and also to make
876     // sure that if anything is frozen in a package, everything is.
877     imported.insert(fqName.getPackageAndVersion());
878 
879     // no circular dependency is already guaranteed by parsing
880     // indirect dependencies will be checked when the imported interface frozen checks are done
881     for (const FQName& importedPackage : imported) {
882         std::vector<FQName> packageInterfaces;
883         status_t err = appendPackageInterfacesToVector(importedPackage, &packageInterfaces);
884         if (err != OK) {
885             return err;
886         }
887 
888         for (const FQName& importedName : packageInterfaces) {
889             HashStatus status = checkHash(importedName);
890             switch (status) {
891                 case HashStatus::CHANGED:
892                 case HashStatus::ERROR:
893                     return UNKNOWN_ERROR;
894                 case HashStatus::FROZEN:
895                     continue;
896                 case HashStatus::UNFROZEN:
897                     result->insert(importedName);
898                     continue;
899                 default:
900                     LOG(FATAL) << static_cast<uint64_t>(status);
901             }
902         }
903     }
904 
905     return OK;
906 }
907 
enforceHashes(const FQName & currentPackage) const908 status_t Coordinator::enforceHashes(const FQName& currentPackage) const {
909     std::vector<FQName> packageInterfaces;
910     status_t err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
911     if (err != OK) {
912         return err;
913     }
914 
915     for (const FQName& currentFQName : packageInterfaces) {
916         HashStatus status = checkHash(currentFQName);
917         switch (status) {
918             case HashStatus::CHANGED:
919             case HashStatus::ERROR:
920                 return UNKNOWN_ERROR;
921             case HashStatus::FROZEN: {
922                 std::set<FQName> unfrozenDependencies;
923                 err = getUnfrozenDependencies(currentFQName, &unfrozenDependencies);
924                 if (err != OK) return err;
925 
926                 if (!unfrozenDependencies.empty()) {
927                     std::cerr << "ERROR: Frozen interface " << currentFQName.string()
928                               << " cannot depend or be adjacent to unfrozen thing(s):" << std::endl;
929                     for (const FQName& name : unfrozenDependencies) {
930                         std::cerr << " (unfrozen) " << name.string() << std::endl;
931                     }
932                     return UNKNOWN_ERROR;
933                 }
934             }
935                 continue;
936             case HashStatus::UNFROZEN:
937                 continue;
938             default:
939                 LOG(FATAL) << static_cast<uint64_t>(status);
940         }
941     }
942 
943     return err;
944 }
945 
MakeParentHierarchy(const std::string & path)946 bool Coordinator::MakeParentHierarchy(const std::string &path) {
947     static const mode_t kMode = 0755;
948 
949     size_t start = 1;  // Ignore leading '/'
950     size_t slashPos;
951     while ((slashPos = path.find('/', start)) != std::string::npos) {
952         std::string partial = path.substr(0, slashPos);
953 
954         struct stat st;
955         if (stat(partial.c_str(), &st) < 0) {
956             if (errno != ENOENT) {
957                 return false;
958             }
959 
960             int res = mkdir(partial.c_str(), kMode);
961             if (res < 0) {
962                 return false;
963             }
964         } else if (!S_ISDIR(st.st_mode)) {
965             return false;
966         }
967 
968         start = slashPos + 1;
969     }
970 
971     return true;
972 }
973 
emitOptionsUsageString(Formatter & out)974 void Coordinator::emitOptionsUsageString(Formatter& out) {
975     out << "[-p <root path>] (-r <interface root>)+ [-R] [-F] [-v] [-d <depfile>]";
976 }
977 
emitOptionsDetailString(Formatter & out)978 void Coordinator::emitOptionsDetailString(Formatter& out) {
979     out << "-p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.\n"
980         << "-R: Do not add default package roots if not specified in -r.\n"
981         << "-F: Require all referenced ASTs to be frozen.\n"
982         << "-r <package:path root>: E.g., android.hardware:hardware/interfaces.\n"
983         << "-v: verbose output.\n"
984         << "-d <depfile>: location of depfile to write to.\n";
985 }
986 
parseOptions(int argc,char ** argv,const std::string & options,const HandleArg & handleArg)987 void Coordinator::parseOptions(int argc, char** argv, const std::string& options,
988                                const HandleArg& handleArg) {
989     // reset global state for getopt
990     optind = 1;
991 
992     bool suppressDefaultPackagePaths = false;
993 
994     int res;
995     std::string optstr = options + "p:r:RFvd:";
996     while ((res = getopt(argc, argv, optstr.c_str())) >= 0) {
997         switch (res) {
998             case 'v': {
999                 setVerbose(true);
1000                 break;
1001             }
1002             case 'd': {
1003                 setDepFile(optarg);
1004                 break;
1005             }
1006             case 'p': {
1007                 if (!getRootPath().empty()) {
1008                     fprintf(stderr, "ERROR: -p <root path> can only be specified once.\n");
1009                     exit(1);
1010                 }
1011                 setRootPath(optarg);
1012                 break;
1013             }
1014             case 'r': {
1015                 std::string val(optarg);
1016                 auto index = val.find_first_of(':');
1017                 if (index == std::string::npos) {
1018                     fprintf(stderr, "ERROR: -r option must contain ':': %s\n", val.c_str());
1019                     exit(1);
1020                 }
1021 
1022                 auto root = val.substr(0, index);
1023                 auto path = val.substr(index + 1);
1024 
1025                 std::string error;
1026                 status_t err = addPackagePath(root, path, &error);
1027                 if (err != OK) {
1028                     fprintf(stderr, "%s\n", error.c_str());
1029                     exit(1);
1030                 }
1031 
1032                 break;
1033             }
1034             case 'R': {
1035                 suppressDefaultPackagePaths = true;
1036                 break;
1037             }
1038             case 'F': {
1039                 setRequireFrozen(true);
1040                 break;
1041             }
1042             // something downstream should handle these cases
1043             default: { handleArg(res, optarg); }
1044         }
1045     }
1046 
1047     if (getRootPath().empty()) {
1048         const char* ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
1049         if (ANDROID_BUILD_TOP != nullptr) {
1050             setRootPath(ANDROID_BUILD_TOP);
1051         }
1052     }
1053 
1054     if (!suppressDefaultPackagePaths) {
1055         addDefaultPackagePath("android.hardware", "hardware/interfaces");
1056         addDefaultPackagePath("android.hidl", "system/libhidl/transport");
1057         addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
1058         addDefaultPackagePath("android.system", "system/hardware/interfaces");
1059     }
1060 }
1061 
1062 }  // namespace android
1063 
1064