blob: 9c7c13f83f3475fa2b5d85437a7c4f382ed9006d [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
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
Andreas Huber5345ec22016-07-29 13:33:27 -070017#include "Coordinator.h"
18
Iliyan Malcheva72e0d22016-09-09 11:03:08 -070019#include <dirent.h>
Andreas Huberd2943e12016-08-05 11:59:31 -070020#include <sys/stat.h>
Andreas Huber5345ec22016-07-29 13:33:27 -070021
Yifan Hong78b38d12017-02-13 18:14:46 +000022#include <algorithm>
23#include <iterator>
24
25#include <android-base/logging.h>
Steven Moreland5bdfa702017-04-18 23:20:39 -070026#include <hidl-hash/Hash.h>
Neel Mehta80a8b3c2019-05-23 16:42:30 -070027#include <hidl-util/Formatter.h>
Yifan Hong78b38d12017-02-13 18:14:46 +000028#include <hidl-util/StringHelper.h>
Steven Morelandcbff5612017-10-11 17:01:54 -070029#include <iostream>
Yifan Hong78b38d12017-02-13 18:14:46 +000030
31#include "AST.h"
32#include "Interface.h"
Steven Moreland06a088b2018-02-20 12:34:47 -080033#include "hidl-gen_l.h"
Andreas Huber5345ec22016-07-29 13:33:27 -070034
Yifan Hong78b38d12017-02-13 18:14:46 +000035static bool existdir(const char *name) {
36 DIR *dir = opendir(name);
Yi Kong56758da2018-07-24 16:21:37 -070037 if (dir == nullptr) {
Yifan Hong78b38d12017-02-13 18:14:46 +000038 return false;
39 }
40 closedir(dir);
41 return true;
42}
43
Andreas Huber5345ec22016-07-29 13:33:27 -070044namespace android {
45
Steven Moreland47792c42017-09-20 10:03:20 -070046const std::string &Coordinator::getRootPath() const {
47 return mRootPath;
Andreas Huberdc981332016-07-29 15:46:54 -070048}
49
Steven Moreland47792c42017-09-20 10:03:20 -070050void Coordinator::setRootPath(const std::string &rootPath) {
51 mRootPath = rootPath;
Andreas Huber5345ec22016-07-29 13:33:27 -070052
Steven Moreland47792c42017-09-20 10:03:20 -070053 if (!mRootPath.empty() && !StringHelper::EndsWith(mRootPath, "/")) {
54 mRootPath += "/";
Steven Moreland25c81662017-05-12 14:57:36 -070055 }
56}
57
Steven Moreland6d3d3c82018-02-08 11:49:34 -080058void Coordinator::setOutputPath(const std::string& outputPath) {
59 mOutputPath = outputPath;
60}
61
Steven Moreland37c57ee2017-09-25 19:08:56 -070062void Coordinator::setVerbose(bool verbose) {
63 mVerbose = verbose;
64}
65
Steven Morelanda492aae2020-05-12 17:14:48 -070066void Coordinator::setRequireFrozen(bool requireFrozen) {
67 mRequireFrozen = requireFrozen;
68}
69
Andreas Huber308d8a22017-11-06 14:46:52 -080070bool Coordinator::isVerbose() const {
71 return mVerbose;
72}
73
Steven Moreland394af5c2018-02-09 14:41:46 -080074void Coordinator::setDepFile(const std::string& depFile) {
75 mDepFile = depFile;
76}
77
Steven Moreland89a9ebb2017-12-04 10:18:00 -080078const std::string& Coordinator::getOwner() const {
79 return mOwner;
80}
81void Coordinator::setOwner(const std::string& owner) {
82 mOwner = owner;
83}
84
Steven Moreland47792c42017-09-20 10:03:20 -070085status_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
Steven Moreland1a85fd92017-09-28 16:31:24 -0700100 mPackageRoots.push_back({path, package});
Steven Moreland47792c42017-09-20 10:03:20 -0700101 return OK;
102}
103void Coordinator::addDefaultPackagePath(const std::string& root, const std::string& path) {
104 addPackagePath(root, path, nullptr /* error */);
105}
106
Steven Moreland6d3d3c82018-02-08 11:49:34 -0800107Formatter Coordinator::getFormatter(const FQName& fqName, Location location,
108 const std::string& fileName) const {
Steven Moreland5abcf012018-02-08 18:50:18 -0800109 if (location == Location::STANDARD_OUT) {
110 return Formatter(stdout);
111 }
112
Steven Moreland255c9a12018-02-26 13:10:27 -0800113 std::string filepath;
114 status_t err = getFilepath(fqName, location, fileName, &filepath);
115 if (err != OK) {
116 return Formatter::invalid();
117 }
Steven Morelandf78c44d2017-09-25 18:41:45 -0700118
Steven Moreland37c57ee2017-09-25 19:08:56 -0700119 onFileAccess(filepath, "w");
120
Steven Morelandf78c44d2017-09-25 18:41:45 -0700121 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
Steven Moreland255c9a12018-02-26 13:10:27 -0800136status_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;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700141
142 switch (location) {
143 case Location::DIRECT: { /* nothing */
Steven Moreland255c9a12018-02-26 13:10:27 -0800144 *path = mOutputPath + fileName;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700145 } break;
146 case Location::PACKAGE_ROOT: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800147 err = getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath);
148 if (err != OK) return err;
149
150 *path = mOutputPath + packagePath + fileName;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700151 } break;
152 case Location::GEN_OUTPUT: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800153 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;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700159 } break;
160 case Location::GEN_SANITIZED: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800161 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;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700167 } break;
168 default: { CHECK(false) << "Invalid location: " << static_cast<size_t>(location); }
169 }
170
Steven Moreland255c9a12018-02-26 13:10:27 -0800171 return OK;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700172}
173
Steven Moreland37c57ee2017-09-25 19:08:56 -0700174void Coordinator::onFileAccess(const std::string& path, const std::string& mode) const {
Steven Moreland394af5c2018-02-09 14:41:46 -0800175 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.
Neel Mehtaf6293d32019-06-12 17:16:38 -0700181 mReadFiles.insert(makeRelative(path));
Steven Moreland394af5c2018-02-09 14:41:46 -0800182 }
183
Steven Moreland37c57ee2017-09-25 19:08:56 -0700184 if (!mVerbose) {
185 return;
186 }
187
188 fprintf(stderr,
189 "VERBOSE: file access %s %s\n", path.c_str(), mode.c_str());
190}
191
Steven Moreland394af5c2018-02-09 14:41:46 -0800192status_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) {
Neel Mehtaf6293d32019-06-12 17:16:38 -0700208 out << makeRelative(file) << " \\\n";
Steven Moreland394af5c2018-02-09 14:41:46 -0800209 }
210 });
211 return OK;
212}
Steven Moreland37c57ee2017-09-25 19:08:56 -0700213
Steven Morelandc59326e2017-06-20 15:19:30 -0700214AST* Coordinator::parse(const FQName& fqName, std::set<AST*>* parsedASTs,
215 Enforce enforcement) const {
Steven Moreland71f09132018-02-20 12:24:30 -0800216 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
226status_t Coordinator::parseOptional(const FQName& fqName, AST** ast, std::set<AST*>* parsedASTs,
227 Enforce enforcement) const {
Andreas Huber68f24592016-07-29 14:53:48 -0700228 CHECK(fqName.isFullyQualified());
229
Steven Morelandd537ab02016-09-12 10:32:01 -0700230 auto it = mCache.find(fqName);
231 if (it != mCache.end()) {
Steven Moreland71f09132018-02-20 12:24:30 -0800232 *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -0700233
Steven Moreland71f09132018-02-20 12:24:30 -0800234 if (*ast != nullptr && parsedASTs != nullptr) {
235 parsedASTs->insert(*ast);
Andreas Huber39fa7182016-08-19 14:27:33 -0700236 }
237
Steven Moreland71f09132018-02-20 12:24:30 -0800238 if (*ast == nullptr) {
239 // circular import OR that AST has errors in it
240 return UNKNOWN_ERROR;
241 }
242
243 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700244 }
245
Andreas Huber68f24592016-07-29 14:53:48 -0700246 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -0700247 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -0700248
Steven Moreland255c9a12018-02-26 13:10:27 -0800249 std::string packagePath;
250 status_t err =
251 getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath);
252 if (err != OK) return err;
Andreas Huberdca261f2016-08-04 13:47:51 -0700253
Steven Moreland255c9a12018-02-26 13:10:27 -0800254 const std::string path = makeAbsolute(packagePath + fqName.name() + ".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -0700255
Steven Moreland71f09132018-02-20 12:24:30 -0800256 *ast = new AST(this, &Hash::getHash(path));
Andreas Huber39fa7182016-08-19 14:27:33 -0700257
Neel Mehta8b0f06a2019-07-11 18:13:21 -0700258 if (fqName.name() != "types") {
Andreas Huber39fa7182016-08-19 14:27:33 -0700259 // 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.
Neel Mehta8b0f06a2019-07-11 18:13:21 -0700261 (*ast)->addImplicitImport(fqName.getTypesForPackage());
Andreas Huber39fa7182016-08-19 14:27:33 -0700262 }
263
Steven Moreland161afb22018-02-20 14:22:44 -0800264 std::unique_ptr<FILE, std::function<void(FILE*)>> file(fopen(path.c_str(), "rb"), fclose);
Andreas Huber68f24592016-07-29 14:53:48 -0700265
Steven Moreland71f09132018-02-20 12:24:30 -0800266 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.
Andreas Huber68f24592016-07-29 14:53:48 -0700271 }
272
Steven Moreland3d846992018-02-14 17:24:57 -0800273 onFileAccess(path, "r");
274
Steven Moreland71f09132018-02-20 12:24:30 -0800275 // parse file takes ownership of file
Steven Moreland161afb22018-02-20 14:22:44 -0800276 if (parseFile(*ast, std::move(file)) != OK || (*ast)->postParse() != OK) {
Steven Moreland71f09132018-02-20 12:24:30 -0800277 delete *ast;
278 *ast = nullptr;
279 return UNKNOWN_ERROR;
280 }
281
Steven Moreland71f09132018-02-20 12:24:30 -0800282 if ((*ast)->package().package() != fqName.package() ||
283 (*ast)->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700284 fprintf(stderr,
285 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700286 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700287 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700288
289 err = UNKNOWN_ERROR;
290 } else {
Steven Moreland71f09132018-02-20 12:24:30 -0800291 if ((*ast)->isInterface()) {
Andreas Hubera2723d22016-07-29 15:36:07 -0700292 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700293 fprintf(stderr,
294 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700295 "instead of the expected types common to the package.\n",
Neel Mehta9200af02019-07-19 13:24:57 -0700296 path.c_str(), (*ast)->getInterface()->definedName().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700297
298 err = UNKNOWN_ERROR;
Neel Mehta9200af02019-07-19 13:24:57 -0700299 } else if ((*ast)->getInterface()->definedName() != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700300 fprintf(stderr,
301 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700302 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700303 path.c_str(),
304 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700305
306 err = UNKNOWN_ERROR;
307 }
308 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700309 fprintf(stderr,
310 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700311 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700312 path.c_str(),
313 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700314
315 err = UNKNOWN_ERROR;
Steven Morelandb47a2622018-07-11 09:04:25 -0700316 } else if ((*ast)->definesInterfaces()) {
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700317 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;
Andreas Hubera2723d22016-07-29 15:36:07 -0700323 }
324 }
325
326 if (err != OK) {
Steven Moreland71f09132018-02-20 12:24:30 -0800327 delete *ast;
328 *ast = nullptr;
329 return err;
Andreas Hubera2723d22016-07-29 15:36:07 -0700330 }
331
Steven Moreland71f09132018-02-20 12:24:30 -0800332 if (parsedASTs != nullptr) {
333 parsedASTs->insert(*ast);
334 }
Andreas Huber39fa7182016-08-19 14:27:33 -0700335
Yifan Hongfe07bff2017-02-15 14:55:48 -0800336 // put it into the cache now, so that enforceRestrictionsOnPackage can
337 // parse fqName.
Steven Moreland71f09132018-02-20 12:24:30 -0800338 mCache[fqName] = *ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700339
Steven Morelandc59326e2017-06-20 15:19:30 -0700340 // 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;
Steven Moreland71f09132018-02-20 12:24:30 -0800344 delete *ast;
345 *ast = nullptr;
346 return err;
Yifan Hong78b38d12017-02-13 18:14:46 +0000347 }
348
Steven Moreland71f09132018-02-20 12:24:30 -0800349 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700350}
351
Steven Moreland255c9a12018-02-26 13:10:27 -0800352const Coordinator::PackageRoot* Coordinator::findPackageRoot(const FQName& fqName) const {
Steven Morelandacb19862020-03-19 11:59:24 -0700353 CHECK(!fqName.package().empty()) << fqName.string();
Andreas Huber5345ec22016-07-29 13:33:27 -0700354
Andreas Huberdca261f2016-08-04 13:47:51 -0700355 // 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
Steven Moreland62709d72017-01-18 10:14:51 -0800362 auto ret = mPackageRoots.end();
Steven Moreland47792c42017-09-20 10:03:20 -0700363 for (auto it = mPackageRoots.begin(); it != mPackageRoots.end(); it++) {
364 if (!fqName.inPackage(it->root.package())) {
Steven Moreland62709d72017-01-18 10:14:51 -0800365 continue;
Andreas Huberdca261f2016-08-04 13:47:51 -0700366 }
Steven Moreland62709d72017-01-18 10:14:51 -0800367
Steven Moreland255c9a12018-02-26 13:10:27 -0800368 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 }
Steven Moreland62709d72017-01-18 10:14:51 -0800373
374 ret = it;
Andreas Huberdca261f2016-08-04 13:47:51 -0700375 }
Andreas Huberdca261f2016-08-04 13:47:51 -0700376
Steven Moreland255c9a12018-02-26 13:10:27 -0800377 if (ret == mPackageRoots.end()) {
378 std::cerr << "ERROR: Package root not specified for " << fqName.string() << "\n";
379 return nullptr;
380 }
381
382 return &(*ret);
Andreas Huberdca261f2016-08-04 13:47:51 -0700383}
384
Steven Moreland7a368042017-08-28 12:47:24 -0700385std::string Coordinator::makeAbsolute(const std::string& path) const {
386 if (StringHelper::StartsWith(path, "/") || mRootPath.empty()) {
387 return path;
Steven Morelandb90d3272017-05-26 10:02:39 -0700388 }
389
Steven Moreland47792c42017-09-20 10:03:20 -0700390 return mRootPath + path;
Steven Morelandb90d3272017-05-26 10:02:39 -0700391}
392
Neel Mehtaf6293d32019-06-12 17:16:38 -0700393std::string Coordinator::makeRelative(const std::string& filename) const {
394 return StringHelper::LTrim(filename, mRootPath);
395}
396
Steven Moreland255c9a12018-02-26 13:10:27 -0800397status_t Coordinator::getPackageRoot(const FQName& fqName, std::string* root) const {
398 const PackageRoot* packageRoot = findPackageRoot(fqName);
Neel Mehta698840c2019-05-17 11:43:41 -0700399 if (packageRoot == nullptr) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800400 return UNKNOWN_ERROR;
401 }
402 *root = packageRoot->root.package();
403 return OK;
Andreas Huberdca261f2016-08-04 13:47:51 -0700404}
405
Steven Moreland255c9a12018-02-26 13:10:27 -0800406status_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;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700413}
414
Steven Moreland255c9a12018-02-26 13:10:27 -0800415status_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;
Andreas Huberdca261f2016-08-04 13:47:51 -0700419
Steven Morelanda9387382017-09-18 15:09:36 -0700420 // Given FQName of "android.hardware.nfc.test@1.0::IFoo" and a prefix
Steven Moreland8f52c8a2017-09-19 08:45:53 -0700421 // "android.hardware", the suffix is "nfc.test".
Steven Moreland255c9a12018-02-26 13:10:27 -0800422 std::string suffix = StringHelper::LTrim(fqName.package(), packageRoot->root.package());
Steven Moreland80ba1742017-09-26 09:49:18 -0700423 suffix = StringHelper::LTrim(suffix, ".");
424
Steven Morelanda9387382017-09-18 15:09:36 -0700425 std::vector<std::string> suffixComponents;
426 StringHelper::SplitString(suffix, '.', &suffixComponents);
Andreas Huberdca261f2016-08-04 13:47:51 -0700427
Steven Morelanda9387382017-09-18 15:09:36 -0700428 std::vector<std::string> components;
Andreas Huber881227d2016-08-02 14:20:21 -0700429 if (!relative) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800430 components.push_back(StringHelper::RTrimAll(packageRoot->path, "/"));
Andreas Huber881227d2016-08-02 14:20:21 -0700431 }
Steven Morelanda9387382017-09-18 15:09:36 -0700432 components.insert(components.end(), suffixComponents.begin(), suffixComponents.end());
433 components.push_back(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700434
Steven Moreland255c9a12018-02-26 13:10:27 -0800435 *path = StringHelper::JoinStrings(components, "/") + "/";
436 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700437}
438
Andreas Huberd2943e12016-08-05 11:59:31 -0700439status_t Coordinator::getPackageInterfaceFiles(
440 const FQName &package,
441 std::vector<std::string> *fileNames) const {
Steven Morelande7d32102018-12-03 17:03:36 -0800442 if (fileNames) fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700443
Steven Moreland255c9a12018-02-26 13:10:27 -0800444 std::string packagePath;
445 status_t err =
446 getPackagePath(package, false /* relative */, false /* sanitized */, &packagePath);
447 if (err != OK) return err;
Andreas Huberd2943e12016-08-05 11:59:31 -0700448
Steven Moreland255c9a12018-02-26 13:10:27 -0800449 const std::string path = makeAbsolute(packagePath);
Steven Morelande7d32102018-12-03 17:03:36 -0800450 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700451
Yi Kong56758da2018-07-24 16:21:37 -0700452 if (dir == nullptr) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800453 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());
Andreas Huberd2943e12016-08-05 11:59:31 -0700455 return -errno;
456 }
457
Steven Morelande7d32102018-12-03 17:03:36 -0800458 if (fileNames == nullptr) {
459 return OK;
460 }
461
Andreas Huberd2943e12016-08-05 11:59:31 -0700462 struct dirent *ent;
Steven Morelande7d32102018-12-03 17:03:36 -0800463 while ((ent = readdir(dir.get())) != nullptr) {
Iris Chang1a92c582018-03-27 18:40:24 +0800464 // 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;
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700477 }
478
Andreas Huberd2943e12016-08-05 11:59:31 -0700479 const auto suffix = ".hal";
480 const auto suffix_len = std::strlen(suffix);
481 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700482
Andreas Huberd2943e12016-08-05 11:59:31 -0700483 if (d_namelen < suffix_len
484 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
485 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700486 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700487
488 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
489 }
490
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700491 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
Andreas Huberd2943e12016-08-05 11:59:31 -0700502 return OK;
503}
504
Steven Morelandaa186832016-09-26 13:51:43 -0700505status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700506 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) {
Steven Morelande1b157e2018-03-06 14:18:32 -0800518 FQName subFQName(package.package(), package.version(), fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700519 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700520 }
521
522 return OK;
523}
524
Steven Moreland255c9a12018-02-26 13:10:27 -0800525status_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;
Andreas Huberd2943e12016-08-05 11:59:31 -0700529
530 if (*(packageRoot.end()--) != '.') {
531 packageRoot += '.';
532 }
533
534 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
535
Steven Moreland255c9a12018-02-26 13:10:27 -0800536 *path = packageRoot; // now converted to a path
537 return OK;
Andreas Huberd2943e12016-08-05 11:59:31 -0700538}
539
Steven Moreland87b26d72017-10-11 09:35:42 -0700540status_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
Steven Moreland40b86352018-02-01 16:03:30 -0800554status_t Coordinator::addUnreferencedTypes(const std::vector<FQName>& packageInterfaces,
555 std::set<FQName>* unreferencedDefinitions,
Steven Morelandb65e5d92018-02-08 12:44:51 -0800556 std::set<FQName>* unreferencedImports) const {
Steven Moreland40b86352018-02-01 16:03:30 -0800557 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) {
Steven Moreland156f7aa2019-11-22 17:30:49 -0800566 AST* ast = parse(fqName, nullptr /*imported*/, Coordinator::Enforce::NONE);
Steven Moreland40b86352018-02-01 16:03:30 -0800567 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
Steven Morelandc59326e2017-06-20 15:19:30 -0700617status_t Coordinator::enforceRestrictionsOnPackage(const FQName& fqName,
618 Enforce enforcement) const {
619 CHECK(enforcement == Enforce::FULL || enforcement == Enforce::NO_HASH ||
620 enforcement == Enforce::NONE);
Yifan Hong78b38d12017-02-13 18:14:46 +0000621
Yifan Hong78b38d12017-02-13 18:14:46 +0000622 // 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()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700625 std::cerr << "ERROR: Cannot enforce restrictions on package " << fqName.string()
626 << ": package or version is missing." << std::endl;
Yifan Hong78b38d12017-02-13 18:14:46 +0000627 return BAD_VALUE;
628 }
Steven Morelandc59326e2017-06-20 15:19:30 -0700629
630 if (enforcement == Enforce::NONE) {
631 return OK;
632 }
633
Yifan Hong78b38d12017-02-13 18:14:46 +0000634 FQName package = fqName.getPackageAndVersion();
635 // look up cache.
636 if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) {
637 return OK;
638 }
639
640 // enforce all rules.
Steven Moreland218625a2017-04-18 22:31:50 -0700641 status_t err;
642
Steven Moreland51b02f42018-03-14 15:43:29 -0700643 err = enforceMinorVersionUprevs(package, enforcement);
Steven Moreland218625a2017-04-18 22:31:50 -0700644 if (err != OK) {
645 return err;
646 }
647
Steven Morelandc59326e2017-06-20 15:19:30 -0700648 if (enforcement != Enforce::NO_HASH) {
649 err = enforceHashes(package);
650 if (err != OK) {
651 return err;
652 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000653 }
654
655 // cache it so that it won't need to be enforced again.
656 mPackagesEnforced.insert(package);
657 return OK;
658}
659
Neel Mehta23bdeaf2019-08-01 18:32:56 -0700660status_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
Steven Moreland51b02f42018-03-14 15:43:29 -0700675status_t Coordinator::enforceMinorVersionUprevs(const FQName& currentPackage,
676 Enforce enforcement) const {
Yifan Hong78b38d12017-02-13 18:14:46 +0000677 if(!currentPackage.hasVersion()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700678 std::cerr << "ERROR: Cannot enforce minor version uprevs for " << currentPackage.string()
679 << ": missing version." << std::endl;
Yifan Hong78b38d12017-02-13 18:14:46 +0000680 return UNKNOWN_ERROR;
681 }
682
683 if (currentPackage.getPackageMinorVersion() == 0) {
684 return OK; // ignore for @x.0
685 }
686
687 bool hasPrevPackage = false;
Steven Morelandad79f562017-05-11 14:36:54 -0700688 FQName prevPackage = currentPackage;
689 while (prevPackage.getPackageMinorVersion() > 0) {
690 prevPackage = prevPackage.downRev();
Steven Moreland255c9a12018-02-26 13:10:27 -0800691
Neel Mehta23bdeaf2019-08-01 18:32:56 -0700692 bool result;
693 status_t err = packageExists(prevPackage, &result);
Steven Moreland255c9a12018-02-26 13:10:27 -0800694 if (err != OK) return err;
695
Neel Mehta23bdeaf2019-08-01 18:32:56 -0700696 if (result) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000697 hasPrevPackage = true;
698 break;
699 }
700 }
701 if (!hasPrevPackage) {
702 // no @x.z, where z < y, exist.
703 return OK;
704 }
705
Steven Morelandad79f562017-05-11 14:36:54 -0700706 if (prevPackage != currentPackage.downRev()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700707 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;
Yifan Hong78b38d12017-02-13 18:14:46 +0000711 return UNKNOWN_ERROR;
712 }
713
Steven Moreland87b26d72017-10-11 09:35:42 -0700714 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
Yifan Hong78b38d12017-02-13 18:14:46 +0000723 std::vector<FQName> packageInterfaces;
724 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
725 if (err != OK) {
726 return err;
727 }
728
Yifan Hongfe07bff2017-02-15 14:55:48 -0800729 bool extendedInterface = false;
Yifan Hong78b38d12017-02-13 18:14:46 +0000730 for (const FQName &currentFQName : packageInterfaces) {
731 if (currentFQName.name() == "types") {
732 continue; // ignore types.hal
733 }
Steven Morelandad79f562017-05-11 14:36:54 -0700734
Yifan Hong78b38d12017-02-13 18:14:46 +0000735 const Interface *iface = nullptr;
Steven Moreland51b02f42018-03-14 15:43:29 -0700736 AST* currentAST = parse(currentFQName, nullptr /* parsedASTs */, enforcement);
Yifan Hong78b38d12017-02-13 18:14:46 +0000737 if (currentAST != nullptr) {
738 iface = currentAST->getInterface();
739 }
740 if (iface == nullptr) {
Yifan Hongfe07bff2017-02-15 14:55:48 -0800741 if (currentAST == nullptr) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700742 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;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800746 } else {
Steven Morelandcbff5612017-10-11 17:01:54 -0700747 std::cerr << "WARNING: Skipping " << currentFQName.string()
748 << " because the file might contain more than one interface."
749 << std::endl;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800750 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000751 continue;
752 }
753
Yifan Hong78b38d12017-02-13 18:14:46 +0000754 if (iface->superType() == nullptr) {
Steven Morelandad79f562017-05-11 14:36:54 -0700755 CHECK(iface->isIBase());
Yifan Hong78b38d12017-02-13 18:14:46 +0000756 continue;
757 }
758
Steven Morelandad79f562017-05-11 14:36:54 -0700759 // 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
Steven Moreland87757152017-11-09 08:57:59 -0800775 if (!lastFQNameExists) {
776 continue;
777 }
778
779 if (iface->superType()->fqName() != lastFQName) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700780 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;
Steven Morelandad79f562017-05-11 14:36:54 -0700785 return UNKNOWN_ERROR;
786 }
787
788 // at least one interface must extend the previous version
Steven Moreland87757152017-11-09 08:57:59 -0800789 // @2.0::IFoo does not work. It must be @2.1::IFoo for at least one interface.
Steven Morelandad79f562017-05-11 14:36:54 -0700790 if (lastFQName.getPackageAndVersion() == prevPackage.getPackageAndVersion()) {
791 extendedInterface = true;
792 }
793
Steven Morelandcbff5612017-10-11 17:01:54 -0700794 if (mVerbose) {
795 std::cout << "VERBOSE: EnforceMinorVersionUprevs: " << currentFQName.string()
796 << " passes." << std::endl;
797 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000798 }
799
Yifan Hongfe07bff2017-02-15 14:55:48 -0800800 if (!extendedInterface) {
801 // No interface extends the interface with the same name in @x.(y-1).
Steven Morelandcbff5612017-10-11 17:01:54 -0700802 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;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800806 return UNKNOWN_ERROR;
807 }
808
809 return OK;
Yifan Hong78b38d12017-02-13 18:14:46 +0000810}
811
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800812Coordinator::HashStatus Coordinator::checkHash(const FQName& fqName) const {
813 AST* ast = parse(fqName);
814 if (ast == nullptr) return HashStatus::ERROR;
815
Steven Moreland255c9a12018-02-26 13:10:27 -0800816 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";
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800821 std::string error;
Steven Moreland566b0e92018-02-16 13:51:33 -0800822 bool fileExists;
823 std::vector<std::string> frozen =
824 Hash::lookupHash(hashPath, fqName.string(), &error, &fileExists);
825 if (fileExists) onFileAccess(hashPath, "r");
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800826
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) {
Steven Moreland156f7aa2019-11-22 17:30:49 -0800834 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 }
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800840 // This ensures that it can be detected.
841 Hash::clearHash(ast->getFilename());
842
Steven Morelanda492aae2020-05-12 17:14:48 -0700843 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
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800850 return HashStatus::UNFROZEN;
851 }
852
Steven Moreland04dea8d2018-02-06 13:11:24 -0800853 std::string currentHash = ast->getFileHash()->hexString();
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800854
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
865status_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
Steven Moreland598c8232020-05-18 16:56:02 +0000875 // 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
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800879 // 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);
Steven Morelandfc32bf22019-02-11 21:02:10 -0800890 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);
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800901 }
902 }
903 }
904
905 return OK;
906}
907
908status_t Coordinator::enforceHashes(const FQName& currentPackage) const {
Steven Moreland218625a2017-04-18 22:31:50 -0700909 std::vector<FQName> packageInterfaces;
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800910 status_t err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
Steven Moreland218625a2017-04-18 22:31:50 -0700911 if (err != OK) {
912 return err;
913 }
914
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800915 for (const FQName& currentFQName : packageInterfaces) {
916 HashStatus status = checkHash(currentFQName);
Steven Morelandfc32bf22019-02-11 21:02:10 -0800917 switch (status) {
918 case HashStatus::CHANGED:
919 case HashStatus::ERROR:
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800920 return UNKNOWN_ERROR;
Steven Morelandfc32bf22019-02-11 21:02:10 -0800921 case HashStatus::FROZEN: {
922 std::set<FQName> unfrozenDependencies;
923 err = getUnfrozenDependencies(currentFQName, &unfrozenDependencies);
924 if (err != OK) return err;
Steven Moreland218625a2017-04-18 22:31:50 -0700925
Steven Morelandfc32bf22019-02-11 21:02:10 -0800926 if (!unfrozenDependencies.empty()) {
927 std::cerr << "ERROR: Frozen interface " << currentFQName.string()
Steven Moreland598c8232020-05-18 16:56:02 +0000928 << " cannot depend or be adjacent to unfrozen thing(s):" << std::endl;
Steven Morelandfc32bf22019-02-11 21:02:10 -0800929 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 }
Steven Moreland218625a2017-04-18 22:31:50 -0700941 }
942
943 return err;
944}
945
Andreas Huberd2943e12016-08-05 11:59:31 -0700946bool 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;
Chih-Hung Hsieh8c90cc52017-08-03 14:51:13 -0700951 while ((slashPos = path.find('/', start)) != std::string::npos) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700952 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
Neel Mehta80a8b3c2019-05-23 16:42:30 -0700974void Coordinator::emitOptionsUsageString(Formatter& out) {
Steven Morelanda492aae2020-05-12 17:14:48 -0700975 out << "[-p <root path>] (-r <interface root>)+ [-R] [-F] [-v] [-d <depfile>]";
Neel Mehta80a8b3c2019-05-23 16:42:30 -0700976}
977
978void 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"
Steven Morelanda492aae2020-05-12 17:14:48 -0700981 << "-F: Require all referenced ASTs to be frozen.\n"
Neel Mehta80a8b3c2019-05-23 16:42:30 -0700982 << "-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
Neel Mehta698840c2019-05-17 11:43:41 -0700987void Coordinator::parseOptions(int argc, char** argv, const std::string& options,
988 const HandleArg& handleArg) {
989 // reset global state for getopt
Steven Morelandee4524f2019-05-22 13:40:03 -0700990 optind = 1;
Neel Mehta698840c2019-05-17 11:43:41 -0700991
992 bool suppressDefaultPackagePaths = false;
993
994 int res;
Steven Morelanda492aae2020-05-12 17:14:48 -0700995 std::string optstr = options + "p:r:RFvd:";
Neel Mehta698840c2019-05-17 11:43:41 -0700996 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 }
Steven Morelanda492aae2020-05-12 17:14:48 -07001038 case 'F': {
1039 setRequireFrozen(true);
1040 break;
1041 }
Neel Mehta698840c2019-05-17 11:43:41 -07001042 // 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
Andreas Huber5345ec22016-07-29 13:33:27 -07001062} // namespace android
1063