blob: 6155fcf95105894412c7de336efbe4eec41b0f40 [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 Morelandc59326e2017-06-20 15:19:30 -070066AST* Coordinator::parse(const FQName& fqName, std::set<AST*>* parsedASTs,
67 Enforce enforcement) const {
Andreas Huber68f24592016-07-29 14:53:48 -070068 CHECK(fqName.isFullyQualified());
69
Steven Morelandd537ab02016-09-12 10:32:01 -070070 auto it = mCache.find(fqName);
71 if (it != mCache.end()) {
72 AST *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -070073
Andreas Huber39fa7182016-08-19 14:27:33 -070074 if (ast != nullptr && parsedASTs != nullptr) {
75 parsedASTs->insert(ast);
76 }
77
Andreas Huber5345ec22016-07-29 13:33:27 -070078 return ast;
79 }
80
Andreas Huber68f24592016-07-29 14:53:48 -070081 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -070082 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -070083
84 AST *typesAST = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070085
Andreas Huber68f24592016-07-29 14:53:48 -070086 if (fqName.name() != "types") {
87 // Any interface file implicitly imports its package's types.hal.
Yifan Hongfece6ec2017-01-12 17:04:04 -080088 FQName typesName = fqName.getTypesForPackage();
Yifan Hongf619fc72017-04-07 15:40:06 -070089 // Do not enforce on imports.
Steven Morelandc59326e2017-06-20 15:19:30 -070090 typesAST = parse(typesName, parsedASTs, Enforce::NONE);
Andreas Huber68f24592016-07-29 14:53:48 -070091
92 // fall through.
93 }
94
Steven Morelandb90d3272017-05-26 10:02:39 -070095 std::string path = getAbsolutePackagePath(fqName);
Andreas Huberdca261f2016-08-04 13:47:51 -070096
Andreas Huber68f24592016-07-29 14:53:48 -070097 path.append(fqName.name());
98 path.append(".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -070099
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700100 AST *ast = new AST(this, path);
Andreas Huber39fa7182016-08-19 14:27:33 -0700101
102 if (typesAST != NULL) {
103 // If types.hal for this AST's package existed, make it's defined
104 // types available to the (about to be parsed) AST right away.
105 ast->addImportedAST(typesAST);
106 }
107
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700108 status_t err = parseFile(ast);
Andreas Huber5345ec22016-07-29 13:33:27 -0700109
Andreas Huber68f24592016-07-29 14:53:48 -0700110 if (err != OK) {
111 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700112 ast = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700113
Andreas Huber39fa7182016-08-19 14:27:33 -0700114 return nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700115 }
116
Andreas Hubera2723d22016-07-29 15:36:07 -0700117 if (ast->package().package() != fqName.package()
118 || ast->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700119 fprintf(stderr,
120 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700121 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700122 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700123
124 err = UNKNOWN_ERROR;
125 } else {
Steven Moreland19f11b52017-05-12 18:22:21 -0700126 if (ast->isInterface()) {
Andreas Hubera2723d22016-07-29 15:36:07 -0700127 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700128 fprintf(stderr,
129 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700130 "instead of the expected types common to the package.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700131 path.c_str(),
Steven Moreland19f11b52017-05-12 18:22:21 -0700132 ast->getInterface()->localName().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700133
134 err = UNKNOWN_ERROR;
Steven Moreland19f11b52017-05-12 18:22:21 -0700135 } else if (ast->getInterface()->localName() != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700136 fprintf(stderr,
137 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700138 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700139 path.c_str(),
140 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700141
142 err = UNKNOWN_ERROR;
143 }
144 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700145 fprintf(stderr,
146 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700147 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700148 path.c_str(),
149 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700150
151 err = UNKNOWN_ERROR;
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700152 } else if (ast->containsInterfaces()) {
153 fprintf(stderr,
154 "ERROR: types.hal file at '%s' declares at least one "
155 "interface type.\n",
156 path.c_str());
157
158 err = UNKNOWN_ERROR;
Andreas Hubera2723d22016-07-29 15:36:07 -0700159 }
160 }
161
162 if (err != OK) {
163 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700164 ast = nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700165
Andreas Huber39fa7182016-08-19 14:27:33 -0700166 return nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700167 }
168
Andreas Huber39fa7182016-08-19 14:27:33 -0700169 if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
170
Yifan Hongfe07bff2017-02-15 14:55:48 -0800171 // put it into the cache now, so that enforceRestrictionsOnPackage can
172 // parse fqName.
Steven Morelandd537ab02016-09-12 10:32:01 -0700173 mCache[fqName] = ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700174
Steven Morelandc59326e2017-06-20 15:19:30 -0700175 // For each .hal file that hidl-gen parses, the whole package will be checked.
176 err = enforceRestrictionsOnPackage(fqName, enforcement);
177 if (err != OK) {
178 mCache[fqName] = nullptr;
179 delete ast;
180 ast = nullptr;
181 return nullptr;
Yifan Hong78b38d12017-02-13 18:14:46 +0000182 }
183
Andreas Huber5345ec22016-07-29 13:33:27 -0700184 return ast;
185}
186
Andreas Huberdca261f2016-08-04 13:47:51 -0700187std::vector<std::string>::const_iterator
188Coordinator::findPackageRoot(const FQName &fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700189 CHECK(!fqName.package().empty());
190 CHECK(!fqName.version().empty());
Andreas Huber5345ec22016-07-29 13:33:27 -0700191
Andreas Huberdca261f2016-08-04 13:47:51 -0700192 // Find the right package prefix and path for this FQName. For
193 // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
194 // prefix:root is set to [ "android.hardware:hardware/interfaces",
195 // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
196 // prefix "android.hardware" and the package root
197 // "hardware/interfaces".
198
Andreas Huberdca261f2016-08-04 13:47:51 -0700199 auto it = mPackageRoots.begin();
Steven Moreland62709d72017-01-18 10:14:51 -0800200 auto ret = mPackageRoots.end();
Andreas Huberdca261f2016-08-04 13:47:51 -0700201 for (; it != mPackageRoots.end(); it++) {
Steven Moreland62709d72017-01-18 10:14:51 -0800202 if (!fqName.inPackage(*it)) {
203 continue;
Andreas Huberdca261f2016-08-04 13:47:51 -0700204 }
Steven Moreland62709d72017-01-18 10:14:51 -0800205
206 CHECK(ret == mPackageRoots.end())
207 << "Multiple package roots found for " << fqName.string()
208 << " (" << *it << " and " << *ret << ")";
209
210 ret = it;
Andreas Huberdca261f2016-08-04 13:47:51 -0700211 }
Steven Moreland62709d72017-01-18 10:14:51 -0800212 CHECK(ret != mPackageRoots.end())
Andreas Huber401cd162016-08-26 10:40:30 -0700213 << "Unable to find package root for " << fqName.string();
Andreas Huberdca261f2016-08-04 13:47:51 -0700214
Steven Moreland62709d72017-01-18 10:14:51 -0800215 return ret;
Andreas Huberdca261f2016-08-04 13:47:51 -0700216}
217
Steven Morelandb90d3272017-05-26 10:02:39 -0700218std::string Coordinator::getAbsolutePackagePath(const FQName& fqName) const {
219 const std::string packagePath = getPackagePath(fqName);
220
221 if (StringHelper::StartsWith(packagePath, "/") || mRootPath.empty()) {
222 return packagePath;
223 }
224
225 return StringHelper::RTrim(mRootPath, "/") + "/" + packagePath;
226}
227
Andreas Huberdca261f2016-08-04 13:47:51 -0700228std::string Coordinator::getPackageRoot(const FQName &fqName) const {
229 auto it = findPackageRoot(fqName);
230 auto prefix = *it;
231 return prefix;
232}
233
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700234std::string Coordinator::getPackageRootPath(const FQName &fqName) const {
235 auto it = findPackageRoot(fqName);
236 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
237 return root;
238}
239
Yifan Hongc8934042016-11-17 17:10:52 -0800240std::string Coordinator::getPackageRootOption(const FQName &fqName) const {
241 return getPackageRoot(fqName) + ":" + getPackageRootPath(fqName);
242}
243
Andreas Huberdca261f2016-08-04 13:47:51 -0700244std::string Coordinator::getPackagePath(
Yifan Hong97288ac2016-12-12 16:03:51 -0800245 const FQName &fqName, bool relative, bool sanitized) const {
Andreas Huberdca261f2016-08-04 13:47:51 -0700246
247 auto it = findPackageRoot(fqName);
248 auto prefix = *it;
249 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
250
251 // Make sure the prefix ends on a '.' and the root path on a '/'
252 if ((*--prefix.end()) != '.') {
253 prefix += '.';
254 }
255
256 if ((*--root.end()) != '/') {
257 root += '/';
258 }
259
260 // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
261 // "android.hardware.", the suffix is "nfc@1.0::IFoo".
262 const std::string packageSuffix = fqName.package().substr(prefix.length());
Andreas Huber5345ec22016-07-29 13:33:27 -0700263
Andreas Huber881227d2016-08-02 14:20:21 -0700264 std::string packagePath;
265 if (!relative) {
Andreas Huberdca261f2016-08-04 13:47:51 -0700266 packagePath = root;
Andreas Huber881227d2016-08-02 14:20:21 -0700267 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700268
269 size_t startPos = 0;
270 size_t dotPos;
271 while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
272 packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
273 packagePath.append("/");
274
275 startPos = dotPos + 1;
276 }
277 CHECK_LT(startPos + 1, packageSuffix.length());
278 packagePath.append(packageSuffix.substr(startPos));
279 packagePath.append("/");
280
Yifan Hong97288ac2016-12-12 16:03:51 -0800281 packagePath.append(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700282 packagePath.append("/");
283
284 return packagePath;
285}
286
Andreas Huberd2943e12016-08-05 11:59:31 -0700287status_t Coordinator::getPackageInterfaceFiles(
288 const FQName &package,
289 std::vector<std::string> *fileNames) const {
290 fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700291
Steven Morelandb90d3272017-05-26 10:02:39 -0700292 const std::string packagePath = getAbsolutePackagePath(package);
Andreas Huberd2943e12016-08-05 11:59:31 -0700293
294 DIR *dir = opendir(packagePath.c_str());
295
296 if (dir == NULL) {
Steven Moreland028d5a32017-05-12 15:45:56 -0700297 fprintf(stderr,
298 "ERROR: Could not open package path %s for package %s:\n%s\n",
299 getPackagePath(package).c_str(),
300 package.string().c_str(),
301 packagePath.c_str());
Andreas Huberd2943e12016-08-05 11:59:31 -0700302 return -errno;
303 }
304
305 struct dirent *ent;
306 while ((ent = readdir(dir)) != NULL) {
307 if (ent->d_type != DT_REG) {
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700308 continue;
309 }
310
Andreas Huberd2943e12016-08-05 11:59:31 -0700311 const auto suffix = ".hal";
312 const auto suffix_len = std::strlen(suffix);
313 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700314
Andreas Huberd2943e12016-08-05 11:59:31 -0700315 if (d_namelen < suffix_len
316 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
317 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700318 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700319
320 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
321 }
322
323 closedir(dir);
324 dir = NULL;
325
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700326 std::sort(fileNames->begin(), fileNames->end(),
327 [](const std::string& lhs, const std::string& rhs) -> bool {
328 if (lhs == "types") {
329 return true;
330 }
331 if (rhs == "types") {
332 return false;
333 }
334 return lhs < rhs;
335 });
336
Andreas Huberd2943e12016-08-05 11:59:31 -0700337 return OK;
338}
339
Steven Morelandaa186832016-09-26 13:51:43 -0700340status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700341 const FQName &package,
342 std::vector<FQName> *packageInterfaces) const {
343 packageInterfaces->clear();
344
345 std::vector<std::string> fileNames;
346 status_t err = getPackageInterfaceFiles(package, &fileNames);
347
348 if (err != OK) {
349 return err;
350 }
351
352 for (const auto &fileName : fileNames) {
353 FQName subFQName(
Yifan Hong90ea87f2016-11-01 14:25:47 -0700354 package.package() + package.atVersion() + "::" + fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700355
356 if (!subFQName.isValid()) {
357 LOG(WARNING)
358 << "Whole-package import encountered invalid filename '"
359 << fileName
360 << "' in package "
361 << package.package()
Yifan Hong90ea87f2016-11-01 14:25:47 -0700362 << package.atVersion();
Andreas Huberd2943e12016-08-05 11:59:31 -0700363
364 continue;
365 }
366
367 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700368 }
369
370 return OK;
371}
372
Andreas Huberd2943e12016-08-05 11:59:31 -0700373std::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
374 std::string packageRoot = getPackageRoot(fqName);
375
376 if (*(packageRoot.end()--) != '.') {
377 packageRoot += '.';
378 }
379
380 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
381
382 return packageRoot; // now converted to a path
383}
384
Steven Morelandc59326e2017-06-20 15:19:30 -0700385status_t Coordinator::enforceRestrictionsOnPackage(const FQName& fqName,
386 Enforce enforcement) const {
387 CHECK(enforcement == Enforce::FULL || enforcement == Enforce::NO_HASH ||
388 enforcement == Enforce::NONE);
Yifan Hong78b38d12017-02-13 18:14:46 +0000389
Yifan Hong78b38d12017-02-13 18:14:46 +0000390 // need fqName to be something like android.hardware.foo@1.0.
391 // name and valueName is ignored.
392 if (fqName.package().empty() || fqName.version().empty()) {
393 LOG(ERROR) << "Cannot enforce restrictions on package " << fqName.string()
394 << ": package or version is missing.";
395 return BAD_VALUE;
396 }
Steven Morelandc59326e2017-06-20 15:19:30 -0700397
398 if (enforcement == Enforce::NONE) {
399 return OK;
400 }
401
Yifan Hong78b38d12017-02-13 18:14:46 +0000402 FQName package = fqName.getPackageAndVersion();
403 // look up cache.
404 if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) {
405 return OK;
406 }
407
408 // enforce all rules.
Steven Moreland218625a2017-04-18 22:31:50 -0700409 status_t err;
410
411 err = enforceMinorVersionUprevs(package);
412 if (err != OK) {
413 return err;
414 }
415
Steven Morelandc59326e2017-06-20 15:19:30 -0700416 if (enforcement != Enforce::NO_HASH) {
417 err = enforceHashes(package);
418 if (err != OK) {
419 return err;
420 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000421 }
422
423 // cache it so that it won't need to be enforced again.
424 mPackagesEnforced.insert(package);
425 return OK;
426}
427
Steven Moreland28b9b532017-05-12 17:02:58 -0700428status_t Coordinator::enforceMinorVersionUprevs(const FQName &currentPackage) const {
Yifan Hong78b38d12017-02-13 18:14:46 +0000429 if(!currentPackage.hasVersion()) {
430 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
431 << ": missing version.";
432 return UNKNOWN_ERROR;
433 }
434
435 if (currentPackage.getPackageMinorVersion() == 0) {
436 return OK; // ignore for @x.0
437 }
438
439 bool hasPrevPackage = false;
Steven Morelandad79f562017-05-11 14:36:54 -0700440 FQName prevPackage = currentPackage;
441 while (prevPackage.getPackageMinorVersion() > 0) {
442 prevPackage = prevPackage.downRev();
Steven Morelandb90d3272017-05-26 10:02:39 -0700443 if (existdir(getAbsolutePackagePath(prevPackage).c_str())) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000444 hasPrevPackage = true;
445 break;
446 }
447 }
448 if (!hasPrevPackage) {
449 // no @x.z, where z < y, exist.
450 return OK;
451 }
452
Steven Morelandad79f562017-05-11 14:36:54 -0700453 if (prevPackage != currentPackage.downRev()) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000454 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
Steven Morelandad79f562017-05-11 14:36:54 -0700455 << ": Found package " << prevPackage.string() << " but missing "
Yifan Hong78b38d12017-02-13 18:14:46 +0000456 << currentPackage.downRev().string() << "; you cannot skip a minor version.";
457 return UNKNOWN_ERROR;
458 }
459
460 status_t err;
461 std::vector<FQName> packageInterfaces;
462 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
463 if (err != OK) {
464 return err;
465 }
466
Yifan Hongfe07bff2017-02-15 14:55:48 -0800467 bool extendedInterface = false;
Yifan Hong78b38d12017-02-13 18:14:46 +0000468 for (const FQName &currentFQName : packageInterfaces) {
469 if (currentFQName.name() == "types") {
470 continue; // ignore types.hal
471 }
Steven Morelandad79f562017-05-11 14:36:54 -0700472
Yifan Hong78b38d12017-02-13 18:14:46 +0000473 const Interface *iface = nullptr;
474 AST *currentAST = parse(currentFQName);
475 if (currentAST != nullptr) {
476 iface = currentAST->getInterface();
477 }
478 if (iface == nullptr) {
Yifan Hongfe07bff2017-02-15 14:55:48 -0800479 if (currentAST == nullptr) {
480 LOG(WARNING) << "Warning: Skipping " << currentFQName.string()
481 << " because it could not be found or parsed"
482 << " or " << currentPackage.string()
483 << " doesn't pass all requirements.";
484 } else {
485 LOG(WARNING) << "Warning: Skipping " << currentFQName.string()
486 << " because the file might contain more than one interface.";
487 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000488 continue;
489 }
490
Yifan Hong78b38d12017-02-13 18:14:46 +0000491 if (iface->superType() == nullptr) {
Steven Morelandad79f562017-05-11 14:36:54 -0700492 CHECK(iface->isIBase());
Yifan Hong78b38d12017-02-13 18:14:46 +0000493 continue;
494 }
495
Steven Morelandad79f562017-05-11 14:36:54 -0700496 // Assume that currentFQName == android.hardware.foo@2.2::IFoo.
497 FQName lastFQName(prevPackage.package(), prevPackage.version(),
498 currentFQName.name());
499 AST *lastAST = parse(lastFQName);
500
501 for (; lastFQName.getPackageMinorVersion() > 0 &&
502 (lastAST == nullptr || lastAST->getInterface() == nullptr)
503 ; lastFQName = lastFQName.downRev(), lastAST = parse(lastFQName)) {
504 // nothing
505 }
506
507 // Then lastFQName == android.hardware.foo@2.1::IFoo or
508 // lastFQName == android.hardware.foo@2.0::IFoo if 2.1 doesn't exist.
509
510 bool lastFQNameExists = lastAST != nullptr && lastAST->getInterface() != nullptr;
511
512 if (iface->superType()->fqName() != lastFQName && lastFQNameExists) {
513 LOG(ERROR) << "Cannot enforce minor version uprevs for " << currentPackage.string()
514 << ": " << iface->fqName().string() << " extends "
515 << iface->superType()->fqName().string()
516 << ", which is not allowed. It must extend " << lastFQName.string();
517 return UNKNOWN_ERROR;
518 }
519
520 // at least one interface must extend the previous version
521 if (lastFQName.getPackageAndVersion() == prevPackage.getPackageAndVersion()) {
522 extendedInterface = true;
523 }
524
Yifan Hong78b38d12017-02-13 18:14:46 +0000525 LOG(VERBOSE) << "enforceMinorVersionUprevs: " << currentFQName.string() << " passes.";
Yifan Hong78b38d12017-02-13 18:14:46 +0000526 }
527
Yifan Hongfe07bff2017-02-15 14:55:48 -0800528 if (!extendedInterface) {
529 // No interface extends the interface with the same name in @x.(y-1).
530 LOG(ERROR) << currentPackage.string() << " doesn't pass minor version uprev requirement. "
531 << "Requires at least one interface to extend an interface with the same name "
Steven Morelandad79f562017-05-11 14:36:54 -0700532 << "from " << prevPackage.string() << ".";
Yifan Hongfe07bff2017-02-15 14:55:48 -0800533 return UNKNOWN_ERROR;
534 }
535
536 return OK;
Yifan Hong78b38d12017-02-13 18:14:46 +0000537}
538
Steven Moreland28b9b532017-05-12 17:02:58 -0700539status_t Coordinator::enforceHashes(const FQName &currentPackage) const {
Steven Moreland218625a2017-04-18 22:31:50 -0700540 status_t err = OK;
541 std::vector<FQName> packageInterfaces;
542 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
543 if (err != OK) {
544 return err;
545 }
546
547 for (const FQName &currentFQName : packageInterfaces) {
548 AST *ast = parse(currentFQName);
549
550 if (ast == nullptr) {
551 err = UNKNOWN_ERROR;
552 continue;
553 }
554
Steven Moreland5bdfa702017-04-18 23:20:39 -0700555 std::string hashPath = getPackageRootPath(currentFQName) + "/current.txt";
Steven Moreland218625a2017-04-18 22:31:50 -0700556 std::string error;
Steven Moreland5bdfa702017-04-18 23:20:39 -0700557 std::vector<std::string> frozen = Hash::lookupHash(hashPath, currentFQName.string(), &error);
Steven Moreland218625a2017-04-18 22:31:50 -0700558
559 if (error.size() > 0) {
560 LOG(ERROR) << error;
561 err = UNKNOWN_ERROR;
562 continue;
563 }
564
565 // hash not define, interface not frozen
566 if (frozen.size() == 0) {
567 continue;
568 }
569
570 std::string currentHash = Hash::getHash(ast->getFilename()).hexString();
571
572 if(std::find(frozen.begin(), frozen.end(), currentHash) == frozen.end()) {
573 LOG(ERROR) << currentFQName.string() << " has hash " << currentHash
574 << " which does not match hash on record. This interface has "
575 << "been frozen. Do not change it!";
576 err = UNKNOWN_ERROR;
577 continue;
578 }
579 }
580
581 return err;
582}
583
Andreas Huberd2943e12016-08-05 11:59:31 -0700584bool Coordinator::MakeParentHierarchy(const std::string &path) {
585 static const mode_t kMode = 0755;
586
587 size_t start = 1; // Ignore leading '/'
588 size_t slashPos;
589 while ((slashPos = path.find("/", start)) != std::string::npos) {
590 std::string partial = path.substr(0, slashPos);
591
592 struct stat st;
593 if (stat(partial.c_str(), &st) < 0) {
594 if (errno != ENOENT) {
595 return false;
596 }
597
598 int res = mkdir(partial.c_str(), kMode);
599 if (res < 0) {
600 return false;
601 }
602 } else if (!S_ISDIR(st.st_mode)) {
603 return false;
604 }
605
606 start = slashPos + 1;
607 }
608
609 return true;
610}
611
Andreas Huber5345ec22016-07-29 13:33:27 -0700612} // namespace android
613