blob: dee56aa25ae84816971cb683404ae28ac926ddb3 [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>
26#include <hidl-util/StringHelper.h>
27
28#include "AST.h"
Steven Morelandae028312017-04-18 22:31:50 -070029#include "Hash.h"
Yifan Hong78b38d12017-02-13 18:14:46 +000030#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,
47 const std::vector<std::string> &packageRoots)
48 : mPackageRootPaths(packageRootPaths),
49 mPackageRoots(packageRoots) {
50 // empty
Andreas Huberdc981332016-07-29 15:46:54 -070051}
52
Andreas Huberdca261f2016-08-04 13:47:51 -070053Coordinator::~Coordinator() {
54 // empty
55}
Andreas Huber5345ec22016-07-29 13:33:27 -070056
Yifan Hongecebc1d2017-04-07 15:40:06 -070057AST *Coordinator::parse(const FQName &fqName, std::set<AST *> *parsedASTs, bool enforce) {
Andreas Huber68f24592016-07-29 14:53:48 -070058 CHECK(fqName.isFullyQualified());
59
Steven Morelandd537ab02016-09-12 10:32:01 -070060 auto it = mCache.find(fqName);
61 if (it != mCache.end()) {
62 AST *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -070063
Andreas Huber39fa7182016-08-19 14:27:33 -070064 if (ast != nullptr && parsedASTs != nullptr) {
65 parsedASTs->insert(ast);
66 }
67
Andreas Huber5345ec22016-07-29 13:33:27 -070068 return ast;
69 }
70
Andreas Huber68f24592016-07-29 14:53:48 -070071 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -070072 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -070073
74 AST *typesAST = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070075
Andreas Huber68f24592016-07-29 14:53:48 -070076 if (fqName.name() != "types") {
77 // Any interface file implicitly imports its package's types.hal.
Yifan Hongfece6ec2017-01-12 17:04:04 -080078 FQName typesName = fqName.getTypesForPackage();
Yifan Hongecebc1d2017-04-07 15:40:06 -070079 // Do not enforce on imports.
80 typesAST = parse(typesName, parsedASTs, false /* enforce */);
Andreas Huber68f24592016-07-29 14:53:48 -070081
82 // fall through.
83 }
84
Andreas Huberdca261f2016-08-04 13:47:51 -070085 std::string path = getPackagePath(fqName);
86
Andreas Huber68f24592016-07-29 14:53:48 -070087 path.append(fqName.name());
88 path.append(".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -070089
Andreas Huber0d0f9a22016-08-17 10:26:11 -070090 AST *ast = new AST(this, path);
Andreas Huber39fa7182016-08-19 14:27:33 -070091
92 if (typesAST != NULL) {
93 // If types.hal for this AST's package existed, make it's defined
94 // types available to the (about to be parsed) AST right away.
95 ast->addImportedAST(typesAST);
96 }
97
Andreas Huber0d0f9a22016-08-17 10:26:11 -070098 status_t err = parseFile(ast);
Andreas Huber5345ec22016-07-29 13:33:27 -070099
Andreas Huber68f24592016-07-29 14:53:48 -0700100 if (err != OK) {
Andreas Huber6e584b72016-07-29 16:14:07 -0700101 // LOG(ERROR) << "parsing '" << path << "' FAILED.";
102
Andreas Huber68f24592016-07-29 14:53:48 -0700103 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700104 ast = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700105
Andreas Huber39fa7182016-08-19 14:27:33 -0700106 return nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700107 }
108
Andreas Hubera2723d22016-07-29 15:36:07 -0700109 if (ast->package().package() != fqName.package()
110 || ast->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700111 fprintf(stderr,
112 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700113 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700114 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700115
116 err = UNKNOWN_ERROR;
117 } else {
118 std::string ifaceName;
119 if (ast->isInterface(&ifaceName)) {
120 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700121 fprintf(stderr,
122 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700123 "instead of the expected types common to the package.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700124 path.c_str(),
125 ifaceName.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700126
127 err = UNKNOWN_ERROR;
128 } else if (ifaceName != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700129 fprintf(stderr,
130 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700131 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700132 path.c_str(),
133 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700134
135 err = UNKNOWN_ERROR;
136 }
137 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700138 fprintf(stderr,
139 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700140 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700141 path.c_str(),
142 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700143
144 err = UNKNOWN_ERROR;
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700145 } else if (ast->containsInterfaces()) {
146 fprintf(stderr,
147 "ERROR: types.hal file at '%s' declares at least one "
148 "interface type.\n",
149 path.c_str());
150
151 err = UNKNOWN_ERROR;
Andreas Hubera2723d22016-07-29 15:36:07 -0700152 }
153 }
154
155 if (err != OK) {
156 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700157 ast = nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700158
Andreas Huber39fa7182016-08-19 14:27:33 -0700159 return nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700160 }
161
Andreas Huber39fa7182016-08-19 14:27:33 -0700162 if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
163
Yifan Hongfe07bff2017-02-15 14:55:48 -0800164 // put it into the cache now, so that enforceRestrictionsOnPackage can
165 // parse fqName.
Steven Morelandd537ab02016-09-12 10:32:01 -0700166 mCache[fqName] = ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700167
Yifan Hongecebc1d2017-04-07 15:40:06 -0700168 if (enforce) {
169 // For each .hal file that hidl-gen parses, the whole package will be checked.
170 err = enforceRestrictionsOnPackage(fqName);
171 if (err != OK) {
172 mCache[fqName] = nullptr;
173 delete ast;
174 ast = nullptr;
175 return nullptr;
176 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000177 }
178
Andreas Huber5345ec22016-07-29 13:33:27 -0700179 return ast;
180}
181
Andreas Huberdca261f2016-08-04 13:47:51 -0700182std::vector<std::string>::const_iterator
183Coordinator::findPackageRoot(const FQName &fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700184 CHECK(!fqName.package().empty());
185 CHECK(!fqName.version().empty());
Andreas Huber5345ec22016-07-29 13:33:27 -0700186
Andreas Huberdca261f2016-08-04 13:47:51 -0700187 // Find the right package prefix and path for this FQName. For
188 // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
189 // prefix:root is set to [ "android.hardware:hardware/interfaces",
190 // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
191 // prefix "android.hardware" and the package root
192 // "hardware/interfaces".
193
Andreas Huberdca261f2016-08-04 13:47:51 -0700194 auto it = mPackageRoots.begin();
Steven Moreland62709d72017-01-18 10:14:51 -0800195 auto ret = mPackageRoots.end();
Andreas Huberdca261f2016-08-04 13:47:51 -0700196 for (; it != mPackageRoots.end(); it++) {
Steven Moreland62709d72017-01-18 10:14:51 -0800197 if (!fqName.inPackage(*it)) {
198 continue;
Andreas Huberdca261f2016-08-04 13:47:51 -0700199 }
Steven Moreland62709d72017-01-18 10:14:51 -0800200
201 CHECK(ret == mPackageRoots.end())
202 << "Multiple package roots found for " << fqName.string()
203 << " (" << *it << " and " << *ret << ")";
204
205 ret = it;
Andreas Huberdca261f2016-08-04 13:47:51 -0700206 }
Steven Moreland62709d72017-01-18 10:14:51 -0800207 CHECK(ret != mPackageRoots.end())
Andreas Huber401cd162016-08-26 10:40:30 -0700208 << "Unable to find package root for " << fqName.string();
Andreas Huberdca261f2016-08-04 13:47:51 -0700209
Steven Moreland62709d72017-01-18 10:14:51 -0800210 return ret;
Andreas Huberdca261f2016-08-04 13:47:51 -0700211}
212
213std::string Coordinator::getPackageRoot(const FQName &fqName) const {
214 auto it = findPackageRoot(fqName);
215 auto prefix = *it;
216 return prefix;
217}
218
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700219std::string Coordinator::getPackageRootPath(const FQName &fqName) const {
220 auto it = findPackageRoot(fqName);
221 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
222 return root;
223}
224
Yifan Hongc8934042016-11-17 17:10:52 -0800225std::string Coordinator::getPackageRootOption(const FQName &fqName) const {
226 return getPackageRoot(fqName) + ":" + getPackageRootPath(fqName);
227}
228
Andreas Huberdca261f2016-08-04 13:47:51 -0700229std::string Coordinator::getPackagePath(
Yifan Hong97288ac2016-12-12 16:03:51 -0800230 const FQName &fqName, bool relative, bool sanitized) const {
Andreas Huberdca261f2016-08-04 13:47:51 -0700231
232 auto it = findPackageRoot(fqName);
233 auto prefix = *it;
234 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
235
236 // Make sure the prefix ends on a '.' and the root path on a '/'
237 if ((*--prefix.end()) != '.') {
238 prefix += '.';
239 }
240
241 if ((*--root.end()) != '/') {
242 root += '/';
243 }
244
245 // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
246 // "android.hardware.", the suffix is "nfc@1.0::IFoo".
247 const std::string packageSuffix = fqName.package().substr(prefix.length());
Andreas Huber5345ec22016-07-29 13:33:27 -0700248
Andreas Huber881227d2016-08-02 14:20:21 -0700249 std::string packagePath;
250 if (!relative) {
Andreas Huberdca261f2016-08-04 13:47:51 -0700251 packagePath = root;
Andreas Huber881227d2016-08-02 14:20:21 -0700252 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700253
254 size_t startPos = 0;
255 size_t dotPos;
256 while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
257 packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
258 packagePath.append("/");
259
260 startPos = dotPos + 1;
261 }
262 CHECK_LT(startPos + 1, packageSuffix.length());
263 packagePath.append(packageSuffix.substr(startPos));
264 packagePath.append("/");
265
Yifan Hong97288ac2016-12-12 16:03:51 -0800266 packagePath.append(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700267 packagePath.append("/");
268
269 return packagePath;
270}
271
Andreas Huberd2943e12016-08-05 11:59:31 -0700272status_t Coordinator::getPackageInterfaceFiles(
273 const FQName &package,
274 std::vector<std::string> *fileNames) const {
275 fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700276
Andreas Huberd2943e12016-08-05 11:59:31 -0700277 const std::string packagePath = getPackagePath(package);
278
279 DIR *dir = opendir(packagePath.c_str());
280
281 if (dir == NULL) {
Steven Moreland261370a2016-08-29 15:36:59 -0700282 LOG(ERROR) << "Could not open package path: " << packagePath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700283 return -errno;
284 }
285
286 struct dirent *ent;
287 while ((ent = readdir(dir)) != NULL) {
288 if (ent->d_type != DT_REG) {
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700289 continue;
290 }
291
Andreas Huberd2943e12016-08-05 11:59:31 -0700292 const auto suffix = ".hal";
293 const auto suffix_len = std::strlen(suffix);
294 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700295
Andreas Huberd2943e12016-08-05 11:59:31 -0700296 if (d_namelen < suffix_len
297 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
298 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700299 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700300
301 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
302 }
303
304 closedir(dir);
305 dir = NULL;
306
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700307 std::sort(fileNames->begin(), fileNames->end(),
308 [](const std::string& lhs, const std::string& rhs) -> bool {
309 if (lhs == "types") {
310 return true;
311 }
312 if (rhs == "types") {
313 return false;
314 }
315 return lhs < rhs;
316 });
317
Andreas Huberd2943e12016-08-05 11:59:31 -0700318 return OK;
319}
320
Steven Morelandaa186832016-09-26 13:51:43 -0700321status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700322 const FQName &package,
323 std::vector<FQName> *packageInterfaces) const {
324 packageInterfaces->clear();
325
326 std::vector<std::string> fileNames;
327 status_t err = getPackageInterfaceFiles(package, &fileNames);
328
329 if (err != OK) {
330 return err;
331 }
332
333 for (const auto &fileName : fileNames) {
334 FQName subFQName(
Yifan Hong90ea87f2016-11-01 14:25:47 -0700335 package.package() + package.atVersion() + "::" + fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700336
337 if (!subFQName.isValid()) {
338 LOG(WARNING)
339 << "Whole-package import encountered invalid filename '"
340 << fileName
341 << "' in package "
342 << package.package()
Yifan Hong90ea87f2016-11-01 14:25:47 -0700343 << package.atVersion();
Andreas Huberd2943e12016-08-05 11:59:31 -0700344
345 continue;
346 }
347
348 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700349 }
350
351 return OK;
352}
353
Andreas Huberd2943e12016-08-05 11:59:31 -0700354std::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
355 std::string packageRoot = getPackageRoot(fqName);
356
357 if (*(packageRoot.end()--) != '.') {
358 packageRoot += '.';
359 }
360
361 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
362
363 return packageRoot; // now converted to a path
364}
365
Yifan Hong78b38d12017-02-13 18:14:46 +0000366
367status_t Coordinator::enforceRestrictionsOnPackage(const FQName &fqName) {
368 // need fqName to be something like android.hardware.foo@1.0.
369 // name and valueName is ignored.
370 if (fqName.package().empty() || fqName.version().empty()) {
371 LOG(ERROR) << "Cannot enforce restrictions on package " << fqName.string()
372 << ": package or version is missing.";
373 return BAD_VALUE;
374 }
375 FQName package = fqName.getPackageAndVersion();
376 // look up cache.
377 if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) {
378 return OK;
379 }
380
381 // enforce all rules.
Steven Morelandae028312017-04-18 22:31:50 -0700382 status_t err;
383
384 err = enforceMinorVersionUprevs(package);
385 if (err != OK) {
386 return err;
387 }
388
389 err = enforceHashes(package);
Yifan Hong78b38d12017-02-13 18:14:46 +0000390 if (err != OK) {
391 return err;
392 }
393
394 // cache it so that it won't need to be enforced again.
395 mPackagesEnforced.insert(package);
396 return OK;
397}
398
399status_t Coordinator::enforceMinorVersionUprevs(const FQName &currentPackage) {
400 if(!currentPackage.hasVersion()) {
401 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
402 << ": missing version.";
403 return UNKNOWN_ERROR;
404 }
405
406 if (currentPackage.getPackageMinorVersion() == 0) {
407 return OK; // ignore for @x.0
408 }
409
410 bool hasPrevPackage = false;
411 FQName prevPacakge = currentPackage;
412 while (prevPacakge.getPackageMinorVersion() > 0) {
413 prevPacakge = prevPacakge.downRev();
414 if (existdir(getPackagePath(prevPacakge).c_str())) {
415 hasPrevPackage = true;
416 break;
417 }
418 }
419 if (!hasPrevPackage) {
420 // no @x.z, where z < y, exist.
421 return OK;
422 }
423
424 if (prevPacakge != currentPackage.downRev()) {
425 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
426 << ": Found package " << prevPacakge.string() << " but missing "
427 << currentPackage.downRev().string() << "; you cannot skip a minor version.";
428 return UNKNOWN_ERROR;
429 }
430
431 status_t err;
432 std::vector<FQName> packageInterfaces;
433 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
434 if (err != OK) {
435 return err;
436 }
437
Yifan Hongfe07bff2017-02-15 14:55:48 -0800438 bool extendedInterface = false;
Yifan Hong78b38d12017-02-13 18:14:46 +0000439 for (const FQName &currentFQName : packageInterfaces) {
440 if (currentFQName.name() == "types") {
441 continue; // ignore types.hal
442 }
443 // Assume that currentFQName == android.hardware.foo@2.2::IFoo.
444 // Then prevFQName == android.hardware.foo@2.1::IFoo.
445 const Interface *iface = nullptr;
446 AST *currentAST = parse(currentFQName);
447 if (currentAST != nullptr) {
448 iface = currentAST->getInterface();
449 }
450 if (iface == nullptr) {
Yifan Hongfe07bff2017-02-15 14:55:48 -0800451 if (currentAST == nullptr) {
452 LOG(WARNING) << "Warning: Skipping " << currentFQName.string()
453 << " because it could not be found or parsed"
454 << " or " << currentPackage.string()
455 << " doesn't pass all requirements.";
456 } else {
457 LOG(WARNING) << "Warning: Skipping " << currentFQName.string()
458 << " because the file might contain more than one interface.";
459 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000460 continue;
461 }
462
463 // android.hardware.foo@2.2::IFoo exists. Now make sure
464 // @2.2::IFoo extends @2.1::IFoo. If any interface IFoo in @2.2
465 // ensures this, @2.2 passes the enforcement.
466 FQName prevFQName(prevPacakge.package(), prevPacakge.version(),
467 currentFQName.name());
468 if (iface->superType() == nullptr) {
469 // @2.2::IFoo doesn't extend anything. (This is probably IBase.)
470 continue;
471 }
472 if (iface->superType()->fqName() != prevFQName) {
473 // @2.2::IFoo doesn't extend @2.1::IFoo.
Yifan Hongfe07bff2017-02-15 14:55:48 -0800474 if (iface->superType()->fqName().getPackageAndVersion() ==
475 prevPacakge.getPackageAndVersion()) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000476 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
477 << ": " << iface->fqName().string() << " extends "
478 << iface->superType()->fqName().string() << ", which is not allowed.";
479 return UNKNOWN_ERROR;
480 }
481 // @2.2::IFoo extends something from a package with a different package name.
482 // Check the next interface.
483 continue;
484 }
485
Yifan Hongfe07bff2017-02-15 14:55:48 -0800486 // @2.2::IFoo passes. Check next interface.
487 extendedInterface = true;
Yifan Hong78b38d12017-02-13 18:14:46 +0000488 LOG(VERBOSE) << "enforceMinorVersionUprevs: " << currentFQName.string() << " passes.";
Yifan Hong78b38d12017-02-13 18:14:46 +0000489 }
490
Yifan Hongfe07bff2017-02-15 14:55:48 -0800491 if (!extendedInterface) {
492 // No interface extends the interface with the same name in @x.(y-1).
493 LOG(ERROR) << currentPackage.string() << " doesn't pass minor version uprev requirement. "
494 << "Requires at least one interface to extend an interface with the same name "
495 << "from " << prevPacakge.string() << ".";
496 return UNKNOWN_ERROR;
497 }
498
499 return OK;
Yifan Hong78b38d12017-02-13 18:14:46 +0000500}
501
Steven Morelandae028312017-04-18 22:31:50 -0700502status_t Coordinator::enforceHashes(const FQName &currentPackage) {
503 status_t err = OK;
504 std::vector<FQName> packageInterfaces;
505 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
506 if (err != OK) {
507 return err;
508 }
509
510 for (const FQName &currentFQName : packageInterfaces) {
511 AST *ast = parse(currentFQName);
512
513 if (ast == nullptr) {
514 err = UNKNOWN_ERROR;
515 continue;
516 }
517
518 std::string packageRootPath = getPackageRootPath(currentFQName);
519 std::string error;
520 std::vector<std::string> frozen = Hash::lookupHash(packageRootPath, currentFQName.string(), &error);
521
522 if (error.size() > 0) {
523 LOG(ERROR) << error;
524 err = UNKNOWN_ERROR;
525 continue;
526 }
527
528 // hash not define, interface not frozen
529 if (frozen.size() == 0) {
530 continue;
531 }
532
533 std::string currentHash = Hash::getHash(ast->getFilename()).hexString();
534
535 if(std::find(frozen.begin(), frozen.end(), currentHash) == frozen.end()) {
536 LOG(ERROR) << currentFQName.string() << " has hash " << currentHash
537 << " which does not match hash on record. This interface has "
538 << "been frozen. Do not change it!";
539 err = UNKNOWN_ERROR;
540 continue;
541 }
542 }
543
544 return err;
545}
546
Andreas Huberd2943e12016-08-05 11:59:31 -0700547// static
548bool Coordinator::MakeParentHierarchy(const std::string &path) {
549 static const mode_t kMode = 0755;
550
551 size_t start = 1; // Ignore leading '/'
552 size_t slashPos;
553 while ((slashPos = path.find("/", start)) != std::string::npos) {
554 std::string partial = path.substr(0, slashPos);
555
556 struct stat st;
557 if (stat(partial.c_str(), &st) < 0) {
558 if (errno != ENOENT) {
559 return false;
560 }
561
562 int res = mkdir(partial.c_str(), kMode);
563 if (res < 0) {
564 return false;
565 }
566 } else if (!S_ISDIR(st.st_mode)) {
567 return false;
568 }
569
570 start = slashPos + 1;
571 }
572
573 return true;
574}
575
Andreas Huber5345ec22016-07-29 13:33:27 -0700576} // namespace android
577