blob: 2e16cf1f80b3a79c45e54ea59ea2175e6750af8a [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
Andreas Huber308d8a22017-11-06 14:46:52 -080066bool Coordinator::isVerbose() const {
67 return mVerbose;
68}
69
Steven Moreland394af5c2018-02-09 14:41:46 -080070void Coordinator::setDepFile(const std::string& depFile) {
71 mDepFile = depFile;
72}
73
Steven Moreland89a9ebb2017-12-04 10:18:00 -080074const std::string& Coordinator::getOwner() const {
75 return mOwner;
76}
77void Coordinator::setOwner(const std::string& owner) {
78 mOwner = owner;
79}
80
Steven Moreland47792c42017-09-20 10:03:20 -070081status_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
Steven Moreland1a85fd92017-09-28 16:31:24 -070096 mPackageRoots.push_back({path, package});
Steven Moreland47792c42017-09-20 10:03:20 -070097 return OK;
98}
99void Coordinator::addDefaultPackagePath(const std::string& root, const std::string& path) {
100 addPackagePath(root, path, nullptr /* error */);
101}
102
Steven Moreland6d3d3c82018-02-08 11:49:34 -0800103Formatter Coordinator::getFormatter(const FQName& fqName, Location location,
104 const std::string& fileName) const {
Steven Moreland5abcf012018-02-08 18:50:18 -0800105 if (location == Location::STANDARD_OUT) {
106 return Formatter(stdout);
107 }
108
Steven Moreland255c9a12018-02-26 13:10:27 -0800109 std::string filepath;
110 status_t err = getFilepath(fqName, location, fileName, &filepath);
111 if (err != OK) {
112 return Formatter::invalid();
113 }
Steven Morelandf78c44d2017-09-25 18:41:45 -0700114
Steven Moreland37c57ee2017-09-25 19:08:56 -0700115 onFileAccess(filepath, "w");
116
Steven Morelandf78c44d2017-09-25 18:41:45 -0700117 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
Steven Moreland255c9a12018-02-26 13:10:27 -0800132status_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;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700137
138 switch (location) {
139 case Location::DIRECT: { /* nothing */
Steven Moreland255c9a12018-02-26 13:10:27 -0800140 *path = mOutputPath + fileName;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700141 } break;
142 case Location::PACKAGE_ROOT: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800143 err = getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath);
144 if (err != OK) return err;
145
146 *path = mOutputPath + packagePath + fileName;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700147 } break;
148 case Location::GEN_OUTPUT: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800149 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;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700155 } break;
156 case Location::GEN_SANITIZED: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800157 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;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700163 } break;
164 default: { CHECK(false) << "Invalid location: " << static_cast<size_t>(location); }
165 }
166
Steven Moreland255c9a12018-02-26 13:10:27 -0800167 return OK;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700168}
169
Steven Moreland37c57ee2017-09-25 19:08:56 -0700170void Coordinator::onFileAccess(const std::string& path, const std::string& mode) const {
Steven Moreland394af5c2018-02-09 14:41:46 -0800171 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.
Neel Mehtaf6293d32019-06-12 17:16:38 -0700177 mReadFiles.insert(makeRelative(path));
Steven Moreland394af5c2018-02-09 14:41:46 -0800178 }
179
Steven Moreland37c57ee2017-09-25 19:08:56 -0700180 if (!mVerbose) {
181 return;
182 }
183
184 fprintf(stderr,
185 "VERBOSE: file access %s %s\n", path.c_str(), mode.c_str());
186}
187
Steven Moreland394af5c2018-02-09 14:41:46 -0800188status_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) {
Neel Mehtaf6293d32019-06-12 17:16:38 -0700204 out << makeRelative(file) << " \\\n";
Steven Moreland394af5c2018-02-09 14:41:46 -0800205 }
206 });
207 return OK;
208}
Steven Moreland37c57ee2017-09-25 19:08:56 -0700209
Steven Morelandc59326e2017-06-20 15:19:30 -0700210AST* Coordinator::parse(const FQName& fqName, std::set<AST*>* parsedASTs,
211 Enforce enforcement) const {
Steven Moreland71f09132018-02-20 12:24:30 -0800212 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
222status_t Coordinator::parseOptional(const FQName& fqName, AST** ast, std::set<AST*>* parsedASTs,
223 Enforce enforcement) const {
Andreas Huber68f24592016-07-29 14:53:48 -0700224 CHECK(fqName.isFullyQualified());
225
Steven Morelandd537ab02016-09-12 10:32:01 -0700226 auto it = mCache.find(fqName);
227 if (it != mCache.end()) {
Steven Moreland71f09132018-02-20 12:24:30 -0800228 *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -0700229
Steven Moreland71f09132018-02-20 12:24:30 -0800230 if (*ast != nullptr && parsedASTs != nullptr) {
231 parsedASTs->insert(*ast);
Andreas Huber39fa7182016-08-19 14:27:33 -0700232 }
233
Steven Moreland71f09132018-02-20 12:24:30 -0800234 if (*ast == nullptr) {
235 // circular import OR that AST has errors in it
236 return UNKNOWN_ERROR;
237 }
238
239 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700240 }
241
Andreas Huber68f24592016-07-29 14:53:48 -0700242 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -0700243 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -0700244
Steven Moreland255c9a12018-02-26 13:10:27 -0800245 std::string packagePath;
246 status_t err =
247 getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath);
248 if (err != OK) return err;
Andreas Huberdca261f2016-08-04 13:47:51 -0700249
Steven Moreland255c9a12018-02-26 13:10:27 -0800250 const std::string path = makeAbsolute(packagePath + fqName.name() + ".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -0700251
Steven Moreland71f09132018-02-20 12:24:30 -0800252 *ast = new AST(this, &Hash::getHash(path));
Andreas Huber39fa7182016-08-19 14:27:33 -0700253
Neel Mehta8b0f06a2019-07-11 18:13:21 -0700254 if (fqName.name() != "types") {
Andreas Huber39fa7182016-08-19 14:27:33 -0700255 // 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.
Neel Mehta8b0f06a2019-07-11 18:13:21 -0700257 (*ast)->addImplicitImport(fqName.getTypesForPackage());
Andreas Huber39fa7182016-08-19 14:27:33 -0700258 }
259
Steven Moreland161afb22018-02-20 14:22:44 -0800260 std::unique_ptr<FILE, std::function<void(FILE*)>> file(fopen(path.c_str(), "rb"), fclose);
Andreas Huber68f24592016-07-29 14:53:48 -0700261
Steven Moreland71f09132018-02-20 12:24:30 -0800262 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.
Andreas Huber68f24592016-07-29 14:53:48 -0700267 }
268
Steven Moreland3d846992018-02-14 17:24:57 -0800269 onFileAccess(path, "r");
270
Steven Moreland71f09132018-02-20 12:24:30 -0800271 // parse file takes ownership of file
Steven Moreland161afb22018-02-20 14:22:44 -0800272 if (parseFile(*ast, std::move(file)) != OK || (*ast)->postParse() != OK) {
Steven Moreland71f09132018-02-20 12:24:30 -0800273 delete *ast;
274 *ast = nullptr;
275 return UNKNOWN_ERROR;
276 }
277
Steven Moreland71f09132018-02-20 12:24:30 -0800278 if ((*ast)->package().package() != fqName.package() ||
279 (*ast)->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700280 fprintf(stderr,
281 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700282 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700283 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700284
285 err = UNKNOWN_ERROR;
286 } else {
Steven Moreland71f09132018-02-20 12:24:30 -0800287 if ((*ast)->isInterface()) {
Andreas Hubera2723d22016-07-29 15:36:07 -0700288 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700289 fprintf(stderr,
290 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700291 "instead of the expected types common to the package.\n",
Neel Mehta9200af02019-07-19 13:24:57 -0700292 path.c_str(), (*ast)->getInterface()->definedName().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700293
294 err = UNKNOWN_ERROR;
Neel Mehta9200af02019-07-19 13:24:57 -0700295 } else if ((*ast)->getInterface()->definedName() != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700296 fprintf(stderr,
297 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700298 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700299 path.c_str(),
300 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700301
302 err = UNKNOWN_ERROR;
303 }
304 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700305 fprintf(stderr,
306 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700307 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700308 path.c_str(),
309 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700310
311 err = UNKNOWN_ERROR;
Steven Morelandb47a2622018-07-11 09:04:25 -0700312 } else if ((*ast)->definesInterfaces()) {
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700313 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;
Andreas Hubera2723d22016-07-29 15:36:07 -0700319 }
320 }
321
322 if (err != OK) {
Steven Moreland71f09132018-02-20 12:24:30 -0800323 delete *ast;
324 *ast = nullptr;
325 return err;
Andreas Hubera2723d22016-07-29 15:36:07 -0700326 }
327
Steven Moreland71f09132018-02-20 12:24:30 -0800328 if (parsedASTs != nullptr) {
329 parsedASTs->insert(*ast);
330 }
Andreas Huber39fa7182016-08-19 14:27:33 -0700331
Yifan Hongfe07bff2017-02-15 14:55:48 -0800332 // put it into the cache now, so that enforceRestrictionsOnPackage can
333 // parse fqName.
Steven Moreland71f09132018-02-20 12:24:30 -0800334 mCache[fqName] = *ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700335
Steven Morelandc59326e2017-06-20 15:19:30 -0700336 // 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;
Steven Moreland71f09132018-02-20 12:24:30 -0800340 delete *ast;
341 *ast = nullptr;
342 return err;
Yifan Hong78b38d12017-02-13 18:14:46 +0000343 }
344
Steven Moreland71f09132018-02-20 12:24:30 -0800345 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700346}
347
Steven Moreland255c9a12018-02-26 13:10:27 -0800348const Coordinator::PackageRoot* Coordinator::findPackageRoot(const FQName& fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700349 CHECK(!fqName.package().empty());
Andreas Huber5345ec22016-07-29 13:33:27 -0700350
Andreas Huberdca261f2016-08-04 13:47:51 -0700351 // 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
Steven Moreland62709d72017-01-18 10:14:51 -0800358 auto ret = mPackageRoots.end();
Steven Moreland47792c42017-09-20 10:03:20 -0700359 for (auto it = mPackageRoots.begin(); it != mPackageRoots.end(); it++) {
360 if (!fqName.inPackage(it->root.package())) {
Steven Moreland62709d72017-01-18 10:14:51 -0800361 continue;
Andreas Huberdca261f2016-08-04 13:47:51 -0700362 }
Steven Moreland62709d72017-01-18 10:14:51 -0800363
Steven Moreland255c9a12018-02-26 13:10:27 -0800364 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 }
Steven Moreland62709d72017-01-18 10:14:51 -0800369
370 ret = it;
Andreas Huberdca261f2016-08-04 13:47:51 -0700371 }
Andreas Huberdca261f2016-08-04 13:47:51 -0700372
Steven Moreland255c9a12018-02-26 13:10:27 -0800373 if (ret == mPackageRoots.end()) {
374 std::cerr << "ERROR: Package root not specified for " << fqName.string() << "\n";
375 return nullptr;
376 }
377
378 return &(*ret);
Andreas Huberdca261f2016-08-04 13:47:51 -0700379}
380
Steven Moreland7a368042017-08-28 12:47:24 -0700381std::string Coordinator::makeAbsolute(const std::string& path) const {
382 if (StringHelper::StartsWith(path, "/") || mRootPath.empty()) {
383 return path;
Steven Morelandb90d3272017-05-26 10:02:39 -0700384 }
385
Steven Moreland47792c42017-09-20 10:03:20 -0700386 return mRootPath + path;
Steven Morelandb90d3272017-05-26 10:02:39 -0700387}
388
Neel Mehtaf6293d32019-06-12 17:16:38 -0700389std::string Coordinator::makeRelative(const std::string& filename) const {
390 return StringHelper::LTrim(filename, mRootPath);
391}
392
Steven Moreland255c9a12018-02-26 13:10:27 -0800393status_t Coordinator::getPackageRoot(const FQName& fqName, std::string* root) const {
394 const PackageRoot* packageRoot = findPackageRoot(fqName);
Neel Mehta698840c2019-05-17 11:43:41 -0700395 if (packageRoot == nullptr) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800396 return UNKNOWN_ERROR;
397 }
398 *root = packageRoot->root.package();
399 return OK;
Andreas Huberdca261f2016-08-04 13:47:51 -0700400}
401
Steven Moreland255c9a12018-02-26 13:10:27 -0800402status_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;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700409}
410
Steven Moreland255c9a12018-02-26 13:10:27 -0800411status_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;
Andreas Huberdca261f2016-08-04 13:47:51 -0700415
Steven Morelanda9387382017-09-18 15:09:36 -0700416 // Given FQName of "android.hardware.nfc.test@1.0::IFoo" and a prefix
Steven Moreland8f52c8a2017-09-19 08:45:53 -0700417 // "android.hardware", the suffix is "nfc.test".
Steven Moreland255c9a12018-02-26 13:10:27 -0800418 std::string suffix = StringHelper::LTrim(fqName.package(), packageRoot->root.package());
Steven Moreland80ba1742017-09-26 09:49:18 -0700419 suffix = StringHelper::LTrim(suffix, ".");
420
Steven Morelanda9387382017-09-18 15:09:36 -0700421 std::vector<std::string> suffixComponents;
422 StringHelper::SplitString(suffix, '.', &suffixComponents);
Andreas Huberdca261f2016-08-04 13:47:51 -0700423
Steven Morelanda9387382017-09-18 15:09:36 -0700424 std::vector<std::string> components;
Andreas Huber881227d2016-08-02 14:20:21 -0700425 if (!relative) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800426 components.push_back(StringHelper::RTrimAll(packageRoot->path, "/"));
Andreas Huber881227d2016-08-02 14:20:21 -0700427 }
Steven Morelanda9387382017-09-18 15:09:36 -0700428 components.insert(components.end(), suffixComponents.begin(), suffixComponents.end());
429 components.push_back(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700430
Steven Moreland255c9a12018-02-26 13:10:27 -0800431 *path = StringHelper::JoinStrings(components, "/") + "/";
432 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700433}
434
Andreas Huberd2943e12016-08-05 11:59:31 -0700435status_t Coordinator::getPackageInterfaceFiles(
436 const FQName &package,
437 std::vector<std::string> *fileNames) const {
Steven Morelande7d32102018-12-03 17:03:36 -0800438 if (fileNames) fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700439
Steven Moreland255c9a12018-02-26 13:10:27 -0800440 std::string packagePath;
441 status_t err =
442 getPackagePath(package, false /* relative */, false /* sanitized */, &packagePath);
443 if (err != OK) return err;
Andreas Huberd2943e12016-08-05 11:59:31 -0700444
Steven Moreland255c9a12018-02-26 13:10:27 -0800445 const std::string path = makeAbsolute(packagePath);
Steven Morelande7d32102018-12-03 17:03:36 -0800446 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700447
Yi Kong56758da2018-07-24 16:21:37 -0700448 if (dir == nullptr) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800449 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());
Andreas Huberd2943e12016-08-05 11:59:31 -0700451 return -errno;
452 }
453
Steven Morelande7d32102018-12-03 17:03:36 -0800454 if (fileNames == nullptr) {
455 return OK;
456 }
457
Andreas Huberd2943e12016-08-05 11:59:31 -0700458 struct dirent *ent;
Steven Morelande7d32102018-12-03 17:03:36 -0800459 while ((ent = readdir(dir.get())) != nullptr) {
Iris Chang1a92c582018-03-27 18:40:24 +0800460 // 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;
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700473 }
474
Andreas Huberd2943e12016-08-05 11:59:31 -0700475 const auto suffix = ".hal";
476 const auto suffix_len = std::strlen(suffix);
477 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700478
Andreas Huberd2943e12016-08-05 11:59:31 -0700479 if (d_namelen < suffix_len
480 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
481 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700482 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700483
484 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
485 }
486
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700487 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
Andreas Huberd2943e12016-08-05 11:59:31 -0700498 return OK;
499}
500
Steven Morelandaa186832016-09-26 13:51:43 -0700501status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700502 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) {
Steven Morelande1b157e2018-03-06 14:18:32 -0800514 FQName subFQName(package.package(), package.version(), fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700515 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700516 }
517
518 return OK;
519}
520
Steven Moreland255c9a12018-02-26 13:10:27 -0800521status_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;
Andreas Huberd2943e12016-08-05 11:59:31 -0700525
526 if (*(packageRoot.end()--) != '.') {
527 packageRoot += '.';
528 }
529
530 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
531
Steven Moreland255c9a12018-02-26 13:10:27 -0800532 *path = packageRoot; // now converted to a path
533 return OK;
Andreas Huberd2943e12016-08-05 11:59:31 -0700534}
535
Steven Moreland87b26d72017-10-11 09:35:42 -0700536status_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
Steven Moreland40b86352018-02-01 16:03:30 -0800550status_t Coordinator::addUnreferencedTypes(const std::vector<FQName>& packageInterfaces,
551 std::set<FQName>* unreferencedDefinitions,
Steven Morelandb65e5d92018-02-08 12:44:51 -0800552 std::set<FQName>* unreferencedImports) const {
Steven Moreland40b86352018-02-01 16:03:30 -0800553 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) {
Steven Moreland156f7aa2019-11-22 17:30:49 -0800562 AST* ast = parse(fqName, nullptr /*imported*/, Coordinator::Enforce::NONE);
Steven Moreland40b86352018-02-01 16:03:30 -0800563 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
Steven Morelandc59326e2017-06-20 15:19:30 -0700613status_t Coordinator::enforceRestrictionsOnPackage(const FQName& fqName,
614 Enforce enforcement) const {
615 CHECK(enforcement == Enforce::FULL || enforcement == Enforce::NO_HASH ||
616 enforcement == Enforce::NONE);
Yifan Hong78b38d12017-02-13 18:14:46 +0000617
Yifan Hong78b38d12017-02-13 18:14:46 +0000618 // 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()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700621 std::cerr << "ERROR: Cannot enforce restrictions on package " << fqName.string()
622 << ": package or version is missing." << std::endl;
Yifan Hong78b38d12017-02-13 18:14:46 +0000623 return BAD_VALUE;
624 }
Steven Morelandc59326e2017-06-20 15:19:30 -0700625
626 if (enforcement == Enforce::NONE) {
627 return OK;
628 }
629
Yifan Hong78b38d12017-02-13 18:14:46 +0000630 FQName package = fqName.getPackageAndVersion();
631 // look up cache.
632 if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) {
633 return OK;
634 }
635
636 // enforce all rules.
Steven Moreland218625a2017-04-18 22:31:50 -0700637 status_t err;
638
Steven Moreland51b02f42018-03-14 15:43:29 -0700639 err = enforceMinorVersionUprevs(package, enforcement);
Steven Moreland218625a2017-04-18 22:31:50 -0700640 if (err != OK) {
641 return err;
642 }
643
Steven Morelandc59326e2017-06-20 15:19:30 -0700644 if (enforcement != Enforce::NO_HASH) {
645 err = enforceHashes(package);
646 if (err != OK) {
647 return err;
648 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000649 }
650
651 // cache it so that it won't need to be enforced again.
652 mPackagesEnforced.insert(package);
653 return OK;
654}
655
Neel Mehta23bdeaf2019-08-01 18:32:56 -0700656status_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
Steven Moreland51b02f42018-03-14 15:43:29 -0700671status_t Coordinator::enforceMinorVersionUprevs(const FQName& currentPackage,
672 Enforce enforcement) const {
Yifan Hong78b38d12017-02-13 18:14:46 +0000673 if(!currentPackage.hasVersion()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700674 std::cerr << "ERROR: Cannot enforce minor version uprevs for " << currentPackage.string()
675 << ": missing version." << std::endl;
Yifan Hong78b38d12017-02-13 18:14:46 +0000676 return UNKNOWN_ERROR;
677 }
678
679 if (currentPackage.getPackageMinorVersion() == 0) {
680 return OK; // ignore for @x.0
681 }
682
683 bool hasPrevPackage = false;
Steven Morelandad79f562017-05-11 14:36:54 -0700684 FQName prevPackage = currentPackage;
685 while (prevPackage.getPackageMinorVersion() > 0) {
686 prevPackage = prevPackage.downRev();
Steven Moreland255c9a12018-02-26 13:10:27 -0800687
Neel Mehta23bdeaf2019-08-01 18:32:56 -0700688 bool result;
689 status_t err = packageExists(prevPackage, &result);
Steven Moreland255c9a12018-02-26 13:10:27 -0800690 if (err != OK) return err;
691
Neel Mehta23bdeaf2019-08-01 18:32:56 -0700692 if (result) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000693 hasPrevPackage = true;
694 break;
695 }
696 }
697 if (!hasPrevPackage) {
698 // no @x.z, where z < y, exist.
699 return OK;
700 }
701
Steven Morelandad79f562017-05-11 14:36:54 -0700702 if (prevPackage != currentPackage.downRev()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700703 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;
Yifan Hong78b38d12017-02-13 18:14:46 +0000707 return UNKNOWN_ERROR;
708 }
709
Steven Moreland87b26d72017-10-11 09:35:42 -0700710 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
Yifan Hong78b38d12017-02-13 18:14:46 +0000719 std::vector<FQName> packageInterfaces;
720 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
721 if (err != OK) {
722 return err;
723 }
724
Yifan Hongfe07bff2017-02-15 14:55:48 -0800725 bool extendedInterface = false;
Yifan Hong78b38d12017-02-13 18:14:46 +0000726 for (const FQName &currentFQName : packageInterfaces) {
727 if (currentFQName.name() == "types") {
728 continue; // ignore types.hal
729 }
Steven Morelandad79f562017-05-11 14:36:54 -0700730
Yifan Hong78b38d12017-02-13 18:14:46 +0000731 const Interface *iface = nullptr;
Steven Moreland51b02f42018-03-14 15:43:29 -0700732 AST* currentAST = parse(currentFQName, nullptr /* parsedASTs */, enforcement);
Yifan Hong78b38d12017-02-13 18:14:46 +0000733 if (currentAST != nullptr) {
734 iface = currentAST->getInterface();
735 }
736 if (iface == nullptr) {
Yifan Hongfe07bff2017-02-15 14:55:48 -0800737 if (currentAST == nullptr) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700738 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;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800742 } else {
Steven Morelandcbff5612017-10-11 17:01:54 -0700743 std::cerr << "WARNING: Skipping " << currentFQName.string()
744 << " because the file might contain more than one interface."
745 << std::endl;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800746 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000747 continue;
748 }
749
Yifan Hong78b38d12017-02-13 18:14:46 +0000750 if (iface->superType() == nullptr) {
Steven Morelandad79f562017-05-11 14:36:54 -0700751 CHECK(iface->isIBase());
Yifan Hong78b38d12017-02-13 18:14:46 +0000752 continue;
753 }
754
Steven Morelandad79f562017-05-11 14:36:54 -0700755 // 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
Steven Moreland87757152017-11-09 08:57:59 -0800771 if (!lastFQNameExists) {
772 continue;
773 }
774
775 if (iface->superType()->fqName() != lastFQName) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700776 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;
Steven Morelandad79f562017-05-11 14:36:54 -0700781 return UNKNOWN_ERROR;
782 }
783
784 // at least one interface must extend the previous version
Steven Moreland87757152017-11-09 08:57:59 -0800785 // @2.0::IFoo does not work. It must be @2.1::IFoo for at least one interface.
Steven Morelandad79f562017-05-11 14:36:54 -0700786 if (lastFQName.getPackageAndVersion() == prevPackage.getPackageAndVersion()) {
787 extendedInterface = true;
788 }
789
Steven Morelandcbff5612017-10-11 17:01:54 -0700790 if (mVerbose) {
791 std::cout << "VERBOSE: EnforceMinorVersionUprevs: " << currentFQName.string()
792 << " passes." << std::endl;
793 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000794 }
795
Yifan Hongfe07bff2017-02-15 14:55:48 -0800796 if (!extendedInterface) {
797 // No interface extends the interface with the same name in @x.(y-1).
Steven Morelandcbff5612017-10-11 17:01:54 -0700798 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;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800802 return UNKNOWN_ERROR;
803 }
804
805 return OK;
Yifan Hong78b38d12017-02-13 18:14:46 +0000806}
807
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800808Coordinator::HashStatus Coordinator::checkHash(const FQName& fqName) const {
809 AST* ast = parse(fqName);
810 if (ast == nullptr) return HashStatus::ERROR;
811
Steven Moreland255c9a12018-02-26 13:10:27 -0800812 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";
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800817 std::string error;
Steven Moreland566b0e92018-02-16 13:51:33 -0800818 bool fileExists;
819 std::vector<std::string> frozen =
820 Hash::lookupHash(hashPath, fqName.string(), &error, &fileExists);
821 if (fileExists) onFileAccess(hashPath, "r");
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800822
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) {
Steven Moreland156f7aa2019-11-22 17:30:49 -0800830 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 }
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800836 // This ensures that it can be detected.
837 Hash::clearHash(ast->getFilename());
838
839 return HashStatus::UNFROZEN;
840 }
841
Steven Moreland04dea8d2018-02-06 13:11:24 -0800842 std::string currentHash = ast->getFileHash()->hexString();
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800843
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
854status_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);
Steven Morelandfc32bf22019-02-11 21:02:10 -0800875 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);
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800886 }
887 }
888 }
889
890 return OK;
891}
892
893status_t Coordinator::enforceHashes(const FQName& currentPackage) const {
Steven Moreland218625a2017-04-18 22:31:50 -0700894 std::vector<FQName> packageInterfaces;
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800895 status_t err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
Steven Moreland218625a2017-04-18 22:31:50 -0700896 if (err != OK) {
897 return err;
898 }
899
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800900 for (const FQName& currentFQName : packageInterfaces) {
901 HashStatus status = checkHash(currentFQName);
Steven Morelandfc32bf22019-02-11 21:02:10 -0800902 switch (status) {
903 case HashStatus::CHANGED:
904 case HashStatus::ERROR:
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800905 return UNKNOWN_ERROR;
Steven Morelandfc32bf22019-02-11 21:02:10 -0800906 case HashStatus::FROZEN: {
907 std::set<FQName> unfrozenDependencies;
908 err = getUnfrozenDependencies(currentFQName, &unfrozenDependencies);
909 if (err != OK) return err;
Steven Moreland218625a2017-04-18 22:31:50 -0700910
Steven Morelandfc32bf22019-02-11 21:02:10 -0800911 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 }
Steven Moreland218625a2017-04-18 22:31:50 -0700926 }
927
928 return err;
929}
930
Andreas Huberd2943e12016-08-05 11:59:31 -0700931bool 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;
Chih-Hung Hsieh8c90cc52017-08-03 14:51:13 -0700936 while ((slashPos = path.find('/', start)) != std::string::npos) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700937 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
Neel Mehta80a8b3c2019-05-23 16:42:30 -0700959void Coordinator::emitOptionsUsageString(Formatter& out) {
960 out << "[-p <root path>] (-r <interface root>)+ [-R] [-v] [-d <depfile>]";
961}
962
963void 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
Neel Mehta698840c2019-05-17 11:43:41 -0700971void Coordinator::parseOptions(int argc, char** argv, const std::string& options,
972 const HandleArg& handleArg) {
973 // reset global state for getopt
Steven Morelandee4524f2019-05-22 13:40:03 -0700974 optind = 1;
Neel Mehta698840c2019-05-17 11:43:41 -0700975
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
Andreas Huber5345ec22016-07-29 13:33:27 -07001042} // namespace android
1043