blob: 9b31c77dfe5f5f253af8dc3ac0468c5d7969e278 [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>
Yifan Hong78b38d12017-02-13 18:14:46 +000027#include <hidl-util/StringHelper.h>
28
29#include "AST.h"
30#include "Interface.h"
31
Andreas Huber0d0f9a22016-08-17 10:26:11 -070032extern android::status_t parseFile(android::AST *ast);
Andreas Huber5345ec22016-07-29 13:33:27 -070033
Yifan Hong78b38d12017-02-13 18:14:46 +000034static bool existdir(const char *name) {
35 DIR *dir = opendir(name);
36 if (dir == NULL) {
37 return false;
38 }
39 closedir(dir);
40 return true;
41}
42
Andreas Huber5345ec22016-07-29 13:33:27 -070043namespace android {
44
Andreas Huberdca261f2016-08-04 13:47:51 -070045Coordinator::Coordinator(
46 const std::vector<std::string> &packageRootPaths,
Steven Morelandf7fa0682017-05-11 16:14:55 -070047 const std::vector<std::string> &packageRoots,
48 const std::string &rootPath)
Andreas Huberdca261f2016-08-04 13:47:51 -070049 : mPackageRootPaths(packageRootPaths),
Steven Morelandf7fa0682017-05-11 16:14:55 -070050 mPackageRoots(packageRoots),
51 mRootPath(rootPath) {
Andreas Huberdca261f2016-08-04 13:47:51 -070052 // empty
Andreas Huberdc981332016-07-29 15:46:54 -070053}
54
Andreas Huberdca261f2016-08-04 13:47:51 -070055Coordinator::~Coordinator() {
56 // empty
57}
Andreas Huber5345ec22016-07-29 13:33:27 -070058
Steven Moreland25c81662017-05-12 14:57:36 -070059void Coordinator::addDefaultPackagePath(const std::string& root, const std::string& path) {
60 if (std::find(mPackageRoots.begin(), mPackageRoots.end(), root) == mPackageRoots.end()) {
61 mPackageRoots.push_back(root);
62 mPackageRootPaths.push_back(path);
63 }
64}
65
Steven Moreland28b9b532017-05-12 17:02:58 -070066AST *Coordinator::parse(const FQName &fqName, std::set<AST *> *parsedASTs, bool enforce) const {
Andreas Huber68f24592016-07-29 14:53:48 -070067 CHECK(fqName.isFullyQualified());
68
Steven Morelandd537ab02016-09-12 10:32:01 -070069 auto it = mCache.find(fqName);
70 if (it != mCache.end()) {
71 AST *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -070072
Andreas Huber39fa7182016-08-19 14:27:33 -070073 if (ast != nullptr && parsedASTs != nullptr) {
74 parsedASTs->insert(ast);
75 }
76
Andreas Huber5345ec22016-07-29 13:33:27 -070077 return ast;
78 }
79
Andreas Huber68f24592016-07-29 14:53:48 -070080 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -070081 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -070082
83 AST *typesAST = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070084
Andreas Huber68f24592016-07-29 14:53:48 -070085 if (fqName.name() != "types") {
86 // Any interface file implicitly imports its package's types.hal.
Yifan Hongfece6ec2017-01-12 17:04:04 -080087 FQName typesName = fqName.getTypesForPackage();
Yifan Hongf619fc72017-04-07 15:40:06 -070088 // Do not enforce on imports.
89 typesAST = parse(typesName, parsedASTs, false /* enforce */);
Andreas Huber68f24592016-07-29 14:53:48 -070090
91 // fall through.
92 }
93
Steven Morelandf7fa0682017-05-11 16:14:55 -070094 std::string path = mRootPath + getPackagePath(fqName);
Andreas Huberdca261f2016-08-04 13:47:51 -070095
Andreas Huber68f24592016-07-29 14:53:48 -070096 path.append(fqName.name());
97 path.append(".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -070098
Andreas Huber0d0f9a22016-08-17 10:26:11 -070099 AST *ast = new AST(this, path);
Andreas Huber39fa7182016-08-19 14:27:33 -0700100
101 if (typesAST != NULL) {
102 // If types.hal for this AST's package existed, make it's defined
103 // types available to the (about to be parsed) AST right away.
104 ast->addImportedAST(typesAST);
105 }
106
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700107 status_t err = parseFile(ast);
Andreas Huber5345ec22016-07-29 13:33:27 -0700108
Andreas Huber68f24592016-07-29 14:53:48 -0700109 if (err != OK) {
110 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700111 ast = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700112
Andreas Huber39fa7182016-08-19 14:27:33 -0700113 return nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700114 }
115
Andreas Hubera2723d22016-07-29 15:36:07 -0700116 if (ast->package().package() != fqName.package()
117 || ast->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700118 fprintf(stderr,
119 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700120 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700121 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700122
123 err = UNKNOWN_ERROR;
124 } else {
Steven Moreland19f11b52017-05-12 18:22:21 -0700125 if (ast->isInterface()) {
Andreas Hubera2723d22016-07-29 15:36:07 -0700126 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700127 fprintf(stderr,
128 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700129 "instead of the expected types common to the package.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700130 path.c_str(),
Steven Moreland19f11b52017-05-12 18:22:21 -0700131 ast->getInterface()->localName().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700132
133 err = UNKNOWN_ERROR;
Steven Moreland19f11b52017-05-12 18:22:21 -0700134 } else if (ast->getInterface()->localName() != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700135 fprintf(stderr,
136 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700137 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700138 path.c_str(),
139 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700140
141 err = UNKNOWN_ERROR;
142 }
143 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700144 fprintf(stderr,
145 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700146 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700147 path.c_str(),
148 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700149
150 err = UNKNOWN_ERROR;
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700151 } else if (ast->containsInterfaces()) {
152 fprintf(stderr,
153 "ERROR: types.hal file at '%s' declares at least one "
154 "interface type.\n",
155 path.c_str());
156
157 err = UNKNOWN_ERROR;
Andreas Hubera2723d22016-07-29 15:36:07 -0700158 }
159 }
160
161 if (err != OK) {
162 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700163 ast = nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700164
Andreas Huber39fa7182016-08-19 14:27:33 -0700165 return nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700166 }
167
Andreas Huber39fa7182016-08-19 14:27:33 -0700168 if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
169
Yifan Hongfe07bff2017-02-15 14:55:48 -0800170 // put it into the cache now, so that enforceRestrictionsOnPackage can
171 // parse fqName.
Steven Morelandd537ab02016-09-12 10:32:01 -0700172 mCache[fqName] = ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700173
Yifan Hongf619fc72017-04-07 15:40:06 -0700174 if (enforce) {
175 // For each .hal file that hidl-gen parses, the whole package will be checked.
176 err = enforceRestrictionsOnPackage(fqName);
177 if (err != OK) {
178 mCache[fqName] = nullptr;
179 delete ast;
180 ast = nullptr;
181 return nullptr;
182 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000183 }
184
Andreas Huber5345ec22016-07-29 13:33:27 -0700185 return ast;
186}
187
Andreas Huberdca261f2016-08-04 13:47:51 -0700188std::vector<std::string>::const_iterator
189Coordinator::findPackageRoot(const FQName &fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700190 CHECK(!fqName.package().empty());
191 CHECK(!fqName.version().empty());
Andreas Huber5345ec22016-07-29 13:33:27 -0700192
Andreas Huberdca261f2016-08-04 13:47:51 -0700193 // Find the right package prefix and path for this FQName. For
194 // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
195 // prefix:root is set to [ "android.hardware:hardware/interfaces",
196 // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
197 // prefix "android.hardware" and the package root
198 // "hardware/interfaces".
199
Andreas Huberdca261f2016-08-04 13:47:51 -0700200 auto it = mPackageRoots.begin();
Steven Moreland62709d72017-01-18 10:14:51 -0800201 auto ret = mPackageRoots.end();
Andreas Huberdca261f2016-08-04 13:47:51 -0700202 for (; it != mPackageRoots.end(); it++) {
Steven Moreland62709d72017-01-18 10:14:51 -0800203 if (!fqName.inPackage(*it)) {
204 continue;
Andreas Huberdca261f2016-08-04 13:47:51 -0700205 }
Steven Moreland62709d72017-01-18 10:14:51 -0800206
207 CHECK(ret == mPackageRoots.end())
208 << "Multiple package roots found for " << fqName.string()
209 << " (" << *it << " and " << *ret << ")";
210
211 ret = it;
Andreas Huberdca261f2016-08-04 13:47:51 -0700212 }
Steven Moreland62709d72017-01-18 10:14:51 -0800213 CHECK(ret != mPackageRoots.end())
Andreas Huber401cd162016-08-26 10:40:30 -0700214 << "Unable to find package root for " << fqName.string();
Andreas Huberdca261f2016-08-04 13:47:51 -0700215
Steven Moreland62709d72017-01-18 10:14:51 -0800216 return ret;
Andreas Huberdca261f2016-08-04 13:47:51 -0700217}
218
219std::string Coordinator::getPackageRoot(const FQName &fqName) const {
220 auto it = findPackageRoot(fqName);
221 auto prefix = *it;
222 return prefix;
223}
224
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700225std::string Coordinator::getPackageRootPath(const FQName &fqName) const {
226 auto it = findPackageRoot(fqName);
227 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
228 return root;
229}
230
Yifan Hongc8934042016-11-17 17:10:52 -0800231std::string Coordinator::getPackageRootOption(const FQName &fqName) const {
232 return getPackageRoot(fqName) + ":" + getPackageRootPath(fqName);
233}
234
Andreas Huberdca261f2016-08-04 13:47:51 -0700235std::string Coordinator::getPackagePath(
Yifan Hong97288ac2016-12-12 16:03:51 -0800236 const FQName &fqName, bool relative, bool sanitized) const {
Andreas Huberdca261f2016-08-04 13:47:51 -0700237
238 auto it = findPackageRoot(fqName);
239 auto prefix = *it;
240 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
241
242 // Make sure the prefix ends on a '.' and the root path on a '/'
243 if ((*--prefix.end()) != '.') {
244 prefix += '.';
245 }
246
247 if ((*--root.end()) != '/') {
248 root += '/';
249 }
250
251 // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
252 // "android.hardware.", the suffix is "nfc@1.0::IFoo".
253 const std::string packageSuffix = fqName.package().substr(prefix.length());
Andreas Huber5345ec22016-07-29 13:33:27 -0700254
Andreas Huber881227d2016-08-02 14:20:21 -0700255 std::string packagePath;
256 if (!relative) {
Andreas Huberdca261f2016-08-04 13:47:51 -0700257 packagePath = root;
Andreas Huber881227d2016-08-02 14:20:21 -0700258 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700259
260 size_t startPos = 0;
261 size_t dotPos;
262 while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
263 packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
264 packagePath.append("/");
265
266 startPos = dotPos + 1;
267 }
268 CHECK_LT(startPos + 1, packageSuffix.length());
269 packagePath.append(packageSuffix.substr(startPos));
270 packagePath.append("/");
271
Yifan Hong97288ac2016-12-12 16:03:51 -0800272 packagePath.append(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700273 packagePath.append("/");
274
275 return packagePath;
276}
277
Andreas Huberd2943e12016-08-05 11:59:31 -0700278status_t Coordinator::getPackageInterfaceFiles(
279 const FQName &package,
280 std::vector<std::string> *fileNames) const {
281 fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700282
Steven Morelandf7fa0682017-05-11 16:14:55 -0700283 const std::string packagePath = mRootPath + getPackagePath(package);
Andreas Huberd2943e12016-08-05 11:59:31 -0700284
285 DIR *dir = opendir(packagePath.c_str());
286
287 if (dir == NULL) {
Steven Moreland028d5a32017-05-12 15:45:56 -0700288 fprintf(stderr,
289 "ERROR: Could not open package path %s for package %s:\n%s\n",
290 getPackagePath(package).c_str(),
291 package.string().c_str(),
292 packagePath.c_str());
Andreas Huberd2943e12016-08-05 11:59:31 -0700293 return -errno;
294 }
295
296 struct dirent *ent;
297 while ((ent = readdir(dir)) != NULL) {
298 if (ent->d_type != DT_REG) {
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700299 continue;
300 }
301
Andreas Huberd2943e12016-08-05 11:59:31 -0700302 const auto suffix = ".hal";
303 const auto suffix_len = std::strlen(suffix);
304 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700305
Andreas Huberd2943e12016-08-05 11:59:31 -0700306 if (d_namelen < suffix_len
307 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
308 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700309 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700310
311 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
312 }
313
314 closedir(dir);
315 dir = NULL;
316
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700317 std::sort(fileNames->begin(), fileNames->end(),
318 [](const std::string& lhs, const std::string& rhs) -> bool {
319 if (lhs == "types") {
320 return true;
321 }
322 if (rhs == "types") {
323 return false;
324 }
325 return lhs < rhs;
326 });
327
Andreas Huberd2943e12016-08-05 11:59:31 -0700328 return OK;
329}
330
Steven Morelandaa186832016-09-26 13:51:43 -0700331status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700332 const FQName &package,
333 std::vector<FQName> *packageInterfaces) const {
334 packageInterfaces->clear();
335
336 std::vector<std::string> fileNames;
337 status_t err = getPackageInterfaceFiles(package, &fileNames);
338
339 if (err != OK) {
340 return err;
341 }
342
343 for (const auto &fileName : fileNames) {
344 FQName subFQName(
Yifan Hong90ea87f2016-11-01 14:25:47 -0700345 package.package() + package.atVersion() + "::" + fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700346
347 if (!subFQName.isValid()) {
348 LOG(WARNING)
349 << "Whole-package import encountered invalid filename '"
350 << fileName
351 << "' in package "
352 << package.package()
Yifan Hong90ea87f2016-11-01 14:25:47 -0700353 << package.atVersion();
Andreas Huberd2943e12016-08-05 11:59:31 -0700354
355 continue;
356 }
357
358 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700359 }
360
361 return OK;
362}
363
Andreas Huberd2943e12016-08-05 11:59:31 -0700364std::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
365 std::string packageRoot = getPackageRoot(fqName);
366
367 if (*(packageRoot.end()--) != '.') {
368 packageRoot += '.';
369 }
370
371 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
372
373 return packageRoot; // now converted to a path
374}
375
Yifan Hong78b38d12017-02-13 18:14:46 +0000376
Steven Moreland28b9b532017-05-12 17:02:58 -0700377status_t Coordinator::enforceRestrictionsOnPackage(const FQName &fqName) const {
Yifan Hong78b38d12017-02-13 18:14:46 +0000378 // need fqName to be something like android.hardware.foo@1.0.
379 // name and valueName is ignored.
380 if (fqName.package().empty() || fqName.version().empty()) {
381 LOG(ERROR) << "Cannot enforce restrictions on package " << fqName.string()
382 << ": package or version is missing.";
383 return BAD_VALUE;
384 }
385 FQName package = fqName.getPackageAndVersion();
386 // look up cache.
387 if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) {
388 return OK;
389 }
390
391 // enforce all rules.
Steven Moreland218625a2017-04-18 22:31:50 -0700392 status_t err;
393
394 err = enforceMinorVersionUprevs(package);
395 if (err != OK) {
396 return err;
397 }
398
399 err = enforceHashes(package);
Yifan Hong78b38d12017-02-13 18:14:46 +0000400 if (err != OK) {
401 return err;
402 }
403
404 // cache it so that it won't need to be enforced again.
405 mPackagesEnforced.insert(package);
406 return OK;
407}
408
Steven Moreland28b9b532017-05-12 17:02:58 -0700409status_t Coordinator::enforceMinorVersionUprevs(const FQName &currentPackage) const {
Yifan Hong78b38d12017-02-13 18:14:46 +0000410 if(!currentPackage.hasVersion()) {
411 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
412 << ": missing version.";
413 return UNKNOWN_ERROR;
414 }
415
416 if (currentPackage.getPackageMinorVersion() == 0) {
417 return OK; // ignore for @x.0
418 }
419
420 bool hasPrevPackage = false;
421 FQName prevPacakge = currentPackage;
422 while (prevPacakge.getPackageMinorVersion() > 0) {
423 prevPacakge = prevPacakge.downRev();
Steven Morelandf7fa0682017-05-11 16:14:55 -0700424 if (existdir((mRootPath + getPackagePath(prevPacakge)).c_str())) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000425 hasPrevPackage = true;
426 break;
427 }
428 }
429 if (!hasPrevPackage) {
430 // no @x.z, where z < y, exist.
431 return OK;
432 }
433
434 if (prevPacakge != currentPackage.downRev()) {
435 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
436 << ": Found package " << prevPacakge.string() << " but missing "
437 << currentPackage.downRev().string() << "; you cannot skip a minor version.";
438 return UNKNOWN_ERROR;
439 }
440
441 status_t err;
442 std::vector<FQName> packageInterfaces;
443 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
444 if (err != OK) {
445 return err;
446 }
447
Yifan Hongfe07bff2017-02-15 14:55:48 -0800448 bool extendedInterface = false;
Yifan Hong78b38d12017-02-13 18:14:46 +0000449 for (const FQName &currentFQName : packageInterfaces) {
450 if (currentFQName.name() == "types") {
451 continue; // ignore types.hal
452 }
453 // Assume that currentFQName == android.hardware.foo@2.2::IFoo.
454 // Then prevFQName == android.hardware.foo@2.1::IFoo.
455 const Interface *iface = nullptr;
456 AST *currentAST = parse(currentFQName);
457 if (currentAST != nullptr) {
458 iface = currentAST->getInterface();
459 }
460 if (iface == nullptr) {
Yifan Hongfe07bff2017-02-15 14:55:48 -0800461 if (currentAST == nullptr) {
462 LOG(WARNING) << "Warning: Skipping " << currentFQName.string()
463 << " because it could not be found or parsed"
464 << " or " << currentPackage.string()
465 << " doesn't pass all requirements.";
466 } else {
467 LOG(WARNING) << "Warning: Skipping " << currentFQName.string()
468 << " because the file might contain more than one interface.";
469 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000470 continue;
471 }
472
473 // android.hardware.foo@2.2::IFoo exists. Now make sure
474 // @2.2::IFoo extends @2.1::IFoo. If any interface IFoo in @2.2
475 // ensures this, @2.2 passes the enforcement.
476 FQName prevFQName(prevPacakge.package(), prevPacakge.version(),
477 currentFQName.name());
478 if (iface->superType() == nullptr) {
479 // @2.2::IFoo doesn't extend anything. (This is probably IBase.)
480 continue;
481 }
482 if (iface->superType()->fqName() != prevFQName) {
483 // @2.2::IFoo doesn't extend @2.1::IFoo.
Yifan Hongfe07bff2017-02-15 14:55:48 -0800484 if (iface->superType()->fqName().getPackageAndVersion() ==
485 prevPacakge.getPackageAndVersion()) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000486 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
487 << ": " << iface->fqName().string() << " extends "
488 << iface->superType()->fqName().string() << ", which is not allowed.";
489 return UNKNOWN_ERROR;
490 }
491 // @2.2::IFoo extends something from a package with a different package name.
492 // Check the next interface.
493 continue;
494 }
495
Yifan Hongfe07bff2017-02-15 14:55:48 -0800496 // @2.2::IFoo passes. Check next interface.
497 extendedInterface = true;
Yifan Hong78b38d12017-02-13 18:14:46 +0000498 LOG(VERBOSE) << "enforceMinorVersionUprevs: " << currentFQName.string() << " passes.";
Yifan Hong78b38d12017-02-13 18:14:46 +0000499 }
500
Yifan Hongfe07bff2017-02-15 14:55:48 -0800501 if (!extendedInterface) {
502 // No interface extends the interface with the same name in @x.(y-1).
503 LOG(ERROR) << currentPackage.string() << " doesn't pass minor version uprev requirement. "
504 << "Requires at least one interface to extend an interface with the same name "
505 << "from " << prevPacakge.string() << ".";
506 return UNKNOWN_ERROR;
507 }
508
509 return OK;
Yifan Hong78b38d12017-02-13 18:14:46 +0000510}
511
Steven Moreland28b9b532017-05-12 17:02:58 -0700512status_t Coordinator::enforceHashes(const FQName &currentPackage) const {
Steven Moreland218625a2017-04-18 22:31:50 -0700513 status_t err = OK;
514 std::vector<FQName> packageInterfaces;
515 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
516 if (err != OK) {
517 return err;
518 }
519
520 for (const FQName &currentFQName : packageInterfaces) {
521 AST *ast = parse(currentFQName);
522
523 if (ast == nullptr) {
524 err = UNKNOWN_ERROR;
525 continue;
526 }
527
Steven Moreland5bdfa702017-04-18 23:20:39 -0700528 std::string hashPath = getPackageRootPath(currentFQName) + "/current.txt";
Steven Moreland218625a2017-04-18 22:31:50 -0700529 std::string error;
Steven Moreland5bdfa702017-04-18 23:20:39 -0700530 std::vector<std::string> frozen = Hash::lookupHash(hashPath, currentFQName.string(), &error);
Steven Moreland218625a2017-04-18 22:31:50 -0700531
532 if (error.size() > 0) {
533 LOG(ERROR) << error;
534 err = UNKNOWN_ERROR;
535 continue;
536 }
537
538 // hash not define, interface not frozen
539 if (frozen.size() == 0) {
540 continue;
541 }
542
543 std::string currentHash = Hash::getHash(ast->getFilename()).hexString();
544
545 if(std::find(frozen.begin(), frozen.end(), currentHash) == frozen.end()) {
546 LOG(ERROR) << currentFQName.string() << " has hash " << currentHash
547 << " which does not match hash on record. This interface has "
548 << "been frozen. Do not change it!";
549 err = UNKNOWN_ERROR;
550 continue;
551 }
552 }
553
554 return err;
555}
556
Andreas Huberd2943e12016-08-05 11:59:31 -0700557bool Coordinator::MakeParentHierarchy(const std::string &path) {
558 static const mode_t kMode = 0755;
559
560 size_t start = 1; // Ignore leading '/'
561 size_t slashPos;
562 while ((slashPos = path.find("/", start)) != std::string::npos) {
563 std::string partial = path.substr(0, slashPos);
564
565 struct stat st;
566 if (stat(partial.c_str(), &st) < 0) {
567 if (errno != ENOENT) {
568 return false;
569 }
570
571 int res = mkdir(partial.c_str(), kMode);
572 if (res < 0) {
573 return false;
574 }
575 } else if (!S_ISDIR(st.st_mode)) {
576 return false;
577 }
578
579 start = slashPos + 1;
580 }
581
582 return true;
583}
584
Andreas Huber5345ec22016-07-29 13:33:27 -0700585} // namespace android
586