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