blob: d0ef37fd291560458f9fa9db1cb401588b3e97da [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
Yifan Hongf619fc72017-04-07 15:40:06 -070059AST *Coordinator::parse(const FQName &fqName, std::set<AST *> *parsedASTs, bool enforce) {
Andreas Huber68f24592016-07-29 14:53:48 -070060 CHECK(fqName.isFullyQualified());
61
Steven Morelandd537ab02016-09-12 10:32:01 -070062 auto it = mCache.find(fqName);
63 if (it != mCache.end()) {
64 AST *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -070065
Andreas Huber39fa7182016-08-19 14:27:33 -070066 if (ast != nullptr && parsedASTs != nullptr) {
67 parsedASTs->insert(ast);
68 }
69
Andreas Huber5345ec22016-07-29 13:33:27 -070070 return ast;
71 }
72
Andreas Huber68f24592016-07-29 14:53:48 -070073 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -070074 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -070075
76 AST *typesAST = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070077
Andreas Huber68f24592016-07-29 14:53:48 -070078 if (fqName.name() != "types") {
79 // Any interface file implicitly imports its package's types.hal.
Yifan Hongfece6ec2017-01-12 17:04:04 -080080 FQName typesName = fqName.getTypesForPackage();
Yifan Hongf619fc72017-04-07 15:40:06 -070081 // Do not enforce on imports.
82 typesAST = parse(typesName, parsedASTs, false /* enforce */);
Andreas Huber68f24592016-07-29 14:53:48 -070083
84 // fall through.
85 }
86
Steven Morelandf7fa0682017-05-11 16:14:55 -070087 std::string path = mRootPath + getPackagePath(fqName);
Andreas Huberdca261f2016-08-04 13:47:51 -070088
Andreas Huber68f24592016-07-29 14:53:48 -070089 path.append(fqName.name());
90 path.append(".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -070091
Andreas Huber0d0f9a22016-08-17 10:26:11 -070092 AST *ast = new AST(this, path);
Andreas Huber39fa7182016-08-19 14:27:33 -070093
94 if (typesAST != NULL) {
95 // If types.hal for this AST's package existed, make it's defined
96 // types available to the (about to be parsed) AST right away.
97 ast->addImportedAST(typesAST);
98 }
99
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700100 status_t err = parseFile(ast);
Andreas Huber5345ec22016-07-29 13:33:27 -0700101
Andreas Huber68f24592016-07-29 14:53:48 -0700102 if (err != OK) {
Andreas Huber6e584b72016-07-29 16:14:07 -0700103 // LOG(ERROR) << "parsing '" << path << "' FAILED.";
104
Andreas Huber68f24592016-07-29 14:53:48 -0700105 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700106 ast = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700107
Andreas Huber39fa7182016-08-19 14:27:33 -0700108 return nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700109 }
110
Andreas Hubera2723d22016-07-29 15:36:07 -0700111 if (ast->package().package() != fqName.package()
112 || ast->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700113 fprintf(stderr,
114 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700115 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700116 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700117
118 err = UNKNOWN_ERROR;
119 } else {
120 std::string ifaceName;
121 if (ast->isInterface(&ifaceName)) {
122 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700123 fprintf(stderr,
124 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700125 "instead of the expected types common to the package.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700126 path.c_str(),
127 ifaceName.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700128
129 err = UNKNOWN_ERROR;
130 } else if (ifaceName != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700131 fprintf(stderr,
132 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700133 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700134 path.c_str(),
135 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700136
137 err = UNKNOWN_ERROR;
138 }
139 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700140 fprintf(stderr,
141 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700142 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700143 path.c_str(),
144 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700145
146 err = UNKNOWN_ERROR;
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700147 } else if (ast->containsInterfaces()) {
148 fprintf(stderr,
149 "ERROR: types.hal file at '%s' declares at least one "
150 "interface type.\n",
151 path.c_str());
152
153 err = UNKNOWN_ERROR;
Andreas Hubera2723d22016-07-29 15:36:07 -0700154 }
155 }
156
157 if (err != OK) {
158 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700159 ast = nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700160
Andreas Huber39fa7182016-08-19 14:27:33 -0700161 return nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700162 }
163
Andreas Huber39fa7182016-08-19 14:27:33 -0700164 if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
165
Yifan Hongfe07bff2017-02-15 14:55:48 -0800166 // put it into the cache now, so that enforceRestrictionsOnPackage can
167 // parse fqName.
Steven Morelandd537ab02016-09-12 10:32:01 -0700168 mCache[fqName] = ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700169
Yifan Hongf619fc72017-04-07 15:40:06 -0700170 if (enforce) {
171 // For each .hal file that hidl-gen parses, the whole package will be checked.
172 err = enforceRestrictionsOnPackage(fqName);
173 if (err != OK) {
174 mCache[fqName] = nullptr;
175 delete ast;
176 ast = nullptr;
177 return nullptr;
178 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000179 }
180
Andreas Huber5345ec22016-07-29 13:33:27 -0700181 return ast;
182}
183
Andreas Huberdca261f2016-08-04 13:47:51 -0700184std::vector<std::string>::const_iterator
185Coordinator::findPackageRoot(const FQName &fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700186 CHECK(!fqName.package().empty());
187 CHECK(!fqName.version().empty());
Andreas Huber5345ec22016-07-29 13:33:27 -0700188
Andreas Huberdca261f2016-08-04 13:47:51 -0700189 // Find the right package prefix and path for this FQName. For
190 // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
191 // prefix:root is set to [ "android.hardware:hardware/interfaces",
192 // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
193 // prefix "android.hardware" and the package root
194 // "hardware/interfaces".
195
Andreas Huberdca261f2016-08-04 13:47:51 -0700196 auto it = mPackageRoots.begin();
Steven Moreland62709d72017-01-18 10:14:51 -0800197 auto ret = mPackageRoots.end();
Andreas Huberdca261f2016-08-04 13:47:51 -0700198 for (; it != mPackageRoots.end(); it++) {
Steven Moreland62709d72017-01-18 10:14:51 -0800199 if (!fqName.inPackage(*it)) {
200 continue;
Andreas Huberdca261f2016-08-04 13:47:51 -0700201 }
Steven Moreland62709d72017-01-18 10:14:51 -0800202
203 CHECK(ret == mPackageRoots.end())
204 << "Multiple package roots found for " << fqName.string()
205 << " (" << *it << " and " << *ret << ")";
206
207 ret = it;
Andreas Huberdca261f2016-08-04 13:47:51 -0700208 }
Steven Moreland62709d72017-01-18 10:14:51 -0800209 CHECK(ret != mPackageRoots.end())
Andreas Huber401cd162016-08-26 10:40:30 -0700210 << "Unable to find package root for " << fqName.string();
Andreas Huberdca261f2016-08-04 13:47:51 -0700211
Steven Moreland62709d72017-01-18 10:14:51 -0800212 return ret;
Andreas Huberdca261f2016-08-04 13:47:51 -0700213}
214
215std::string Coordinator::getPackageRoot(const FQName &fqName) const {
216 auto it = findPackageRoot(fqName);
217 auto prefix = *it;
218 return prefix;
219}
220
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700221std::string Coordinator::getPackageRootPath(const FQName &fqName) const {
222 auto it = findPackageRoot(fqName);
223 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
224 return root;
225}
226
Yifan Hongc8934042016-11-17 17:10:52 -0800227std::string Coordinator::getPackageRootOption(const FQName &fqName) const {
228 return getPackageRoot(fqName) + ":" + getPackageRootPath(fqName);
229}
230
Andreas Huberdca261f2016-08-04 13:47:51 -0700231std::string Coordinator::getPackagePath(
Yifan Hong97288ac2016-12-12 16:03:51 -0800232 const FQName &fqName, bool relative, bool sanitized) const {
Andreas Huberdca261f2016-08-04 13:47:51 -0700233
234 auto it = findPackageRoot(fqName);
235 auto prefix = *it;
236 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
237
238 // Make sure the prefix ends on a '.' and the root path on a '/'
239 if ((*--prefix.end()) != '.') {
240 prefix += '.';
241 }
242
243 if ((*--root.end()) != '/') {
244 root += '/';
245 }
246
247 // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
248 // "android.hardware.", the suffix is "nfc@1.0::IFoo".
249 const std::string packageSuffix = fqName.package().substr(prefix.length());
Andreas Huber5345ec22016-07-29 13:33:27 -0700250
Andreas Huber881227d2016-08-02 14:20:21 -0700251 std::string packagePath;
252 if (!relative) {
Andreas Huberdca261f2016-08-04 13:47:51 -0700253 packagePath = root;
Andreas Huber881227d2016-08-02 14:20:21 -0700254 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700255
256 size_t startPos = 0;
257 size_t dotPos;
258 while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
259 packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
260 packagePath.append("/");
261
262 startPos = dotPos + 1;
263 }
264 CHECK_LT(startPos + 1, packageSuffix.length());
265 packagePath.append(packageSuffix.substr(startPos));
266 packagePath.append("/");
267
Yifan Hong97288ac2016-12-12 16:03:51 -0800268 packagePath.append(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700269 packagePath.append("/");
270
271 return packagePath;
272}
273
Andreas Huberd2943e12016-08-05 11:59:31 -0700274status_t Coordinator::getPackageInterfaceFiles(
275 const FQName &package,
276 std::vector<std::string> *fileNames) const {
277 fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700278
Steven Morelandf7fa0682017-05-11 16:14:55 -0700279 const std::string packagePath = mRootPath + getPackagePath(package);
Andreas Huberd2943e12016-08-05 11:59:31 -0700280
281 DIR *dir = opendir(packagePath.c_str());
282
283 if (dir == NULL) {
Steven Moreland261370a2016-08-29 15:36:59 -0700284 LOG(ERROR) << "Could not open package path: " << packagePath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700285 return -errno;
286 }
287
288 struct dirent *ent;
289 while ((ent = readdir(dir)) != NULL) {
290 if (ent->d_type != DT_REG) {
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700291 continue;
292 }
293
Andreas Huberd2943e12016-08-05 11:59:31 -0700294 const auto suffix = ".hal";
295 const auto suffix_len = std::strlen(suffix);
296 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700297
Andreas Huberd2943e12016-08-05 11:59:31 -0700298 if (d_namelen < suffix_len
299 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
300 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700301 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700302
303 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
304 }
305
306 closedir(dir);
307 dir = NULL;
308
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700309 std::sort(fileNames->begin(), fileNames->end(),
310 [](const std::string& lhs, const std::string& rhs) -> bool {
311 if (lhs == "types") {
312 return true;
313 }
314 if (rhs == "types") {
315 return false;
316 }
317 return lhs < rhs;
318 });
319
Andreas Huberd2943e12016-08-05 11:59:31 -0700320 return OK;
321}
322
Steven Morelandaa186832016-09-26 13:51:43 -0700323status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700324 const FQName &package,
325 std::vector<FQName> *packageInterfaces) const {
326 packageInterfaces->clear();
327
328 std::vector<std::string> fileNames;
329 status_t err = getPackageInterfaceFiles(package, &fileNames);
330
331 if (err != OK) {
332 return err;
333 }
334
335 for (const auto &fileName : fileNames) {
336 FQName subFQName(
Yifan Hong90ea87f2016-11-01 14:25:47 -0700337 package.package() + package.atVersion() + "::" + fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700338
339 if (!subFQName.isValid()) {
340 LOG(WARNING)
341 << "Whole-package import encountered invalid filename '"
342 << fileName
343 << "' in package "
344 << package.package()
Yifan Hong90ea87f2016-11-01 14:25:47 -0700345 << package.atVersion();
Andreas Huberd2943e12016-08-05 11:59:31 -0700346
347 continue;
348 }
349
350 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700351 }
352
353 return OK;
354}
355
Andreas Huberd2943e12016-08-05 11:59:31 -0700356std::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
357 std::string packageRoot = getPackageRoot(fqName);
358
359 if (*(packageRoot.end()--) != '.') {
360 packageRoot += '.';
361 }
362
363 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
364
365 return packageRoot; // now converted to a path
366}
367
Yifan Hong78b38d12017-02-13 18:14:46 +0000368
369status_t Coordinator::enforceRestrictionsOnPackage(const FQName &fqName) {
370 // need fqName to be something like android.hardware.foo@1.0.
371 // name and valueName is ignored.
372 if (fqName.package().empty() || fqName.version().empty()) {
373 LOG(ERROR) << "Cannot enforce restrictions on package " << fqName.string()
374 << ": package or version is missing.";
375 return BAD_VALUE;
376 }
377 FQName package = fqName.getPackageAndVersion();
378 // look up cache.
379 if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) {
380 return OK;
381 }
382
383 // enforce all rules.
Steven Moreland218625a2017-04-18 22:31:50 -0700384 status_t err;
385
386 err = enforceMinorVersionUprevs(package);
387 if (err != OK) {
388 return err;
389 }
390
391 err = enforceHashes(package);
Yifan Hong78b38d12017-02-13 18:14:46 +0000392 if (err != OK) {
393 return err;
394 }
395
396 // cache it so that it won't need to be enforced again.
397 mPackagesEnforced.insert(package);
398 return OK;
399}
400
401status_t Coordinator::enforceMinorVersionUprevs(const FQName &currentPackage) {
402 if(!currentPackage.hasVersion()) {
403 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
404 << ": missing version.";
405 return UNKNOWN_ERROR;
406 }
407
408 if (currentPackage.getPackageMinorVersion() == 0) {
409 return OK; // ignore for @x.0
410 }
411
412 bool hasPrevPackage = false;
413 FQName prevPacakge = currentPackage;
414 while (prevPacakge.getPackageMinorVersion() > 0) {
415 prevPacakge = prevPacakge.downRev();
Steven Morelandf7fa0682017-05-11 16:14:55 -0700416 if (existdir((mRootPath + getPackagePath(prevPacakge)).c_str())) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000417 hasPrevPackage = true;
418 break;
419 }
420 }
421 if (!hasPrevPackage) {
422 // no @x.z, where z < y, exist.
423 return OK;
424 }
425
426 if (prevPacakge != currentPackage.downRev()) {
427 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
428 << ": Found package " << prevPacakge.string() << " but missing "
429 << currentPackage.downRev().string() << "; you cannot skip a minor version.";
430 return UNKNOWN_ERROR;
431 }
432
433 status_t err;
434 std::vector<FQName> packageInterfaces;
435 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
436 if (err != OK) {
437 return err;
438 }
439
Yifan Hongfe07bff2017-02-15 14:55:48 -0800440 bool extendedInterface = false;
Yifan Hong78b38d12017-02-13 18:14:46 +0000441 for (const FQName &currentFQName : packageInterfaces) {
442 if (currentFQName.name() == "types") {
443 continue; // ignore types.hal
444 }
445 // Assume that currentFQName == android.hardware.foo@2.2::IFoo.
446 // Then prevFQName == android.hardware.foo@2.1::IFoo.
447 const Interface *iface = nullptr;
448 AST *currentAST = parse(currentFQName);
449 if (currentAST != nullptr) {
450 iface = currentAST->getInterface();
451 }
452 if (iface == nullptr) {
Yifan Hongfe07bff2017-02-15 14:55:48 -0800453 if (currentAST == nullptr) {
454 LOG(WARNING) << "Warning: Skipping " << currentFQName.string()
455 << " because it could not be found or parsed"
456 << " or " << currentPackage.string()
457 << " doesn't pass all requirements.";
458 } else {
459 LOG(WARNING) << "Warning: Skipping " << currentFQName.string()
460 << " because the file might contain more than one interface.";
461 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000462 continue;
463 }
464
465 // android.hardware.foo@2.2::IFoo exists. Now make sure
466 // @2.2::IFoo extends @2.1::IFoo. If any interface IFoo in @2.2
467 // ensures this, @2.2 passes the enforcement.
468 FQName prevFQName(prevPacakge.package(), prevPacakge.version(),
469 currentFQName.name());
470 if (iface->superType() == nullptr) {
471 // @2.2::IFoo doesn't extend anything. (This is probably IBase.)
472 continue;
473 }
474 if (iface->superType()->fqName() != prevFQName) {
475 // @2.2::IFoo doesn't extend @2.1::IFoo.
Yifan Hongfe07bff2017-02-15 14:55:48 -0800476 if (iface->superType()->fqName().getPackageAndVersion() ==
477 prevPacakge.getPackageAndVersion()) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000478 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
479 << ": " << iface->fqName().string() << " extends "
480 << iface->superType()->fqName().string() << ", which is not allowed.";
481 return UNKNOWN_ERROR;
482 }
483 // @2.2::IFoo extends something from a package with a different package name.
484 // Check the next interface.
485 continue;
486 }
487
Yifan Hongfe07bff2017-02-15 14:55:48 -0800488 // @2.2::IFoo passes. Check next interface.
489 extendedInterface = true;
Yifan Hong78b38d12017-02-13 18:14:46 +0000490 LOG(VERBOSE) << "enforceMinorVersionUprevs: " << currentFQName.string() << " passes.";
Yifan Hong78b38d12017-02-13 18:14:46 +0000491 }
492
Yifan Hongfe07bff2017-02-15 14:55:48 -0800493 if (!extendedInterface) {
494 // No interface extends the interface with the same name in @x.(y-1).
495 LOG(ERROR) << currentPackage.string() << " doesn't pass minor version uprev requirement. "
496 << "Requires at least one interface to extend an interface with the same name "
497 << "from " << prevPacakge.string() << ".";
498 return UNKNOWN_ERROR;
499 }
500
501 return OK;
Yifan Hong78b38d12017-02-13 18:14:46 +0000502}
503
Steven Moreland218625a2017-04-18 22:31:50 -0700504status_t Coordinator::enforceHashes(const FQName &currentPackage) {
505 status_t err = OK;
506 std::vector<FQName> packageInterfaces;
507 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
508 if (err != OK) {
509 return err;
510 }
511
512 for (const FQName &currentFQName : packageInterfaces) {
513 AST *ast = parse(currentFQName);
514
515 if (ast == nullptr) {
516 err = UNKNOWN_ERROR;
517 continue;
518 }
519
Steven Moreland5bdfa702017-04-18 23:20:39 -0700520 std::string hashPath = getPackageRootPath(currentFQName) + "/current.txt";
Steven Moreland218625a2017-04-18 22:31:50 -0700521 std::string error;
Steven Moreland5bdfa702017-04-18 23:20:39 -0700522 std::vector<std::string> frozen = Hash::lookupHash(hashPath, currentFQName.string(), &error);
Steven Moreland218625a2017-04-18 22:31:50 -0700523
524 if (error.size() > 0) {
525 LOG(ERROR) << error;
526 err = UNKNOWN_ERROR;
527 continue;
528 }
529
530 // hash not define, interface not frozen
531 if (frozen.size() == 0) {
532 continue;
533 }
534
535 std::string currentHash = Hash::getHash(ast->getFilename()).hexString();
536
537 if(std::find(frozen.begin(), frozen.end(), currentHash) == frozen.end()) {
538 LOG(ERROR) << currentFQName.string() << " has hash " << currentHash
539 << " which does not match hash on record. This interface has "
540 << "been frozen. Do not change it!";
541 err = UNKNOWN_ERROR;
542 continue;
543 }
544 }
545
546 return err;
547}
548
Andreas Huberd2943e12016-08-05 11:59:31 -0700549bool Coordinator::MakeParentHierarchy(const std::string &path) {
550 static const mode_t kMode = 0755;
551
552 size_t start = 1; // Ignore leading '/'
553 size_t slashPos;
554 while ((slashPos = path.find("/", start)) != std::string::npos) {
555 std::string partial = path.substr(0, slashPos);
556
557 struct stat st;
558 if (stat(partial.c_str(), &st) < 0) {
559 if (errno != ENOENT) {
560 return false;
561 }
562
563 int res = mkdir(partial.c_str(), kMode);
564 if (res < 0) {
565 return false;
566 }
567 } else if (!S_ISDIR(st.st_mode)) {
568 return false;
569 }
570
571 start = slashPos + 1;
572 }
573
574 return true;
575}
576
Andreas Huber5345ec22016-07-29 13:33:27 -0700577} // namespace android
578