blob: bb1f9a0a5d58963ac93cfe68d56c74c049228dd4 [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
19#include "AST.h"
Andreas Huber5345ec22016-07-29 13:33:27 -070020
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -070021#include <algorithm>
Andreas Huber5345ec22016-07-29 13:33:27 -070022#include <android-base/logging.h>
Steven Moreland5715fed2017-01-16 11:06:47 -080023#include <hidl-util/StringHelper.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070024#include <iterator>
Iliyan Malcheva72e0d22016-09-09 11:03:08 -070025#include <dirent.h>
Andreas Huberd2943e12016-08-05 11:59:31 -070026#include <sys/stat.h>
Andreas Huber5345ec22016-07-29 13:33:27 -070027
Andreas Huber0d0f9a22016-08-17 10:26:11 -070028extern android::status_t parseFile(android::AST *ast);
Andreas Huber5345ec22016-07-29 13:33:27 -070029
30namespace android {
31
Andreas Huberdca261f2016-08-04 13:47:51 -070032Coordinator::Coordinator(
33 const std::vector<std::string> &packageRootPaths,
34 const std::vector<std::string> &packageRoots)
35 : mPackageRootPaths(packageRootPaths),
36 mPackageRoots(packageRoots) {
37 // empty
Andreas Huberdc981332016-07-29 15:46:54 -070038}
39
Andreas Huberdca261f2016-08-04 13:47:51 -070040Coordinator::~Coordinator() {
41 // empty
42}
Andreas Huber5345ec22016-07-29 13:33:27 -070043
Andreas Huber39fa7182016-08-19 14:27:33 -070044AST *Coordinator::parse(const FQName &fqName, std::set<AST *> *parsedASTs) {
Andreas Huber68f24592016-07-29 14:53:48 -070045 CHECK(fqName.isFullyQualified());
46
Steven Morelandd537ab02016-09-12 10:32:01 -070047 auto it = mCache.find(fqName);
48 if (it != mCache.end()) {
49 AST *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -070050
Andreas Huber39fa7182016-08-19 14:27:33 -070051 if (ast != nullptr && parsedASTs != nullptr) {
52 parsedASTs->insert(ast);
53 }
54
Andreas Huber5345ec22016-07-29 13:33:27 -070055 return ast;
56 }
57
Andreas Huber68f24592016-07-29 14:53:48 -070058 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -070059 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -070060
61 AST *typesAST = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070062
Andreas Huber68f24592016-07-29 14:53:48 -070063 if (fqName.name() != "types") {
64 // Any interface file implicitly imports its package's types.hal.
Yifan Hongfece6ec2017-01-12 17:04:04 -080065 FQName typesName = fqName.getTypesForPackage();
Andreas Huber39fa7182016-08-19 14:27:33 -070066 typesAST = parse(typesName, parsedASTs);
Andreas Huber68f24592016-07-29 14:53:48 -070067
68 // fall through.
69 }
70
Andreas Huberdca261f2016-08-04 13:47:51 -070071 std::string path = getPackagePath(fqName);
72
Andreas Huber68f24592016-07-29 14:53:48 -070073 path.append(fqName.name());
74 path.append(".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -070075
Andreas Huber0d0f9a22016-08-17 10:26:11 -070076 AST *ast = new AST(this, path);
Andreas Huber39fa7182016-08-19 14:27:33 -070077
78 if (typesAST != NULL) {
79 // If types.hal for this AST's package existed, make it's defined
80 // types available to the (about to be parsed) AST right away.
81 ast->addImportedAST(typesAST);
82 }
83
Andreas Huber0d0f9a22016-08-17 10:26:11 -070084 status_t err = parseFile(ast);
Andreas Huber5345ec22016-07-29 13:33:27 -070085
Andreas Huber68f24592016-07-29 14:53:48 -070086 if (err != OK) {
Andreas Huber6e584b72016-07-29 16:14:07 -070087 // LOG(ERROR) << "parsing '" << path << "' FAILED.";
88
Andreas Huber68f24592016-07-29 14:53:48 -070089 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -070090 ast = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070091
Andreas Huber39fa7182016-08-19 14:27:33 -070092 return nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070093 }
94
Andreas Hubera2723d22016-07-29 15:36:07 -070095 if (ast->package().package() != fqName.package()
96 || ast->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -070097 fprintf(stderr,
98 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -070099 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700100 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700101
102 err = UNKNOWN_ERROR;
103 } else {
104 std::string ifaceName;
105 if (ast->isInterface(&ifaceName)) {
106 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700107 fprintf(stderr,
108 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700109 "instead of the expected types common to the package.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700110 path.c_str(),
111 ifaceName.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700112
113 err = UNKNOWN_ERROR;
114 } else if (ifaceName != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700115 fprintf(stderr,
116 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700117 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700118 path.c_str(),
119 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700120
121 err = UNKNOWN_ERROR;
122 }
123 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700124 fprintf(stderr,
125 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700126 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700127 path.c_str(),
128 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700129
130 err = UNKNOWN_ERROR;
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700131 } else if (ast->containsInterfaces()) {
132 fprintf(stderr,
133 "ERROR: types.hal file at '%s' declares at least one "
134 "interface type.\n",
135 path.c_str());
136
137 err = UNKNOWN_ERROR;
Andreas Hubera2723d22016-07-29 15:36:07 -0700138 }
139 }
140
141 if (err != OK) {
142 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700143 ast = nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700144
Andreas Huber39fa7182016-08-19 14:27:33 -0700145 return nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700146 }
147
Andreas Huber39fa7182016-08-19 14:27:33 -0700148 if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
149
Steven Morelandd537ab02016-09-12 10:32:01 -0700150 mCache[fqName] = ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700151
152 return ast;
153}
154
Andreas Huberdca261f2016-08-04 13:47:51 -0700155std::vector<std::string>::const_iterator
156Coordinator::findPackageRoot(const FQName &fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700157 CHECK(!fqName.package().empty());
158 CHECK(!fqName.version().empty());
Andreas Huber5345ec22016-07-29 13:33:27 -0700159
Andreas Huberdca261f2016-08-04 13:47:51 -0700160 // Find the right package prefix and path for this FQName. For
161 // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
162 // prefix:root is set to [ "android.hardware:hardware/interfaces",
163 // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
164 // prefix "android.hardware" and the package root
165 // "hardware/interfaces".
166
Andreas Huberdca261f2016-08-04 13:47:51 -0700167 auto it = mPackageRoots.begin();
Steven Moreland62709d72017-01-18 10:14:51 -0800168 auto ret = mPackageRoots.end();
Andreas Huberdca261f2016-08-04 13:47:51 -0700169 for (; it != mPackageRoots.end(); it++) {
Steven Moreland62709d72017-01-18 10:14:51 -0800170 if (!fqName.inPackage(*it)) {
171 continue;
Andreas Huberdca261f2016-08-04 13:47:51 -0700172 }
Steven Moreland62709d72017-01-18 10:14:51 -0800173
174 CHECK(ret == mPackageRoots.end())
175 << "Multiple package roots found for " << fqName.string()
176 << " (" << *it << " and " << *ret << ")";
177
178 ret = it;
Andreas Huberdca261f2016-08-04 13:47:51 -0700179 }
Steven Moreland62709d72017-01-18 10:14:51 -0800180 CHECK(ret != mPackageRoots.end())
Andreas Huber401cd162016-08-26 10:40:30 -0700181 << "Unable to find package root for " << fqName.string();
Andreas Huberdca261f2016-08-04 13:47:51 -0700182
Steven Moreland62709d72017-01-18 10:14:51 -0800183 return ret;
Andreas Huberdca261f2016-08-04 13:47:51 -0700184}
185
186std::string Coordinator::getPackageRoot(const FQName &fqName) const {
187 auto it = findPackageRoot(fqName);
188 auto prefix = *it;
189 return prefix;
190}
191
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700192std::string Coordinator::getPackageRootPath(const FQName &fqName) const {
193 auto it = findPackageRoot(fqName);
194 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
195 return root;
196}
197
Yifan Hongc8934042016-11-17 17:10:52 -0800198std::string Coordinator::getPackageRootOption(const FQName &fqName) const {
199 return getPackageRoot(fqName) + ":" + getPackageRootPath(fqName);
200}
201
Andreas Huberdca261f2016-08-04 13:47:51 -0700202std::string Coordinator::getPackagePath(
Yifan Hong97288ac2016-12-12 16:03:51 -0800203 const FQName &fqName, bool relative, bool sanitized) const {
Andreas Huberdca261f2016-08-04 13:47:51 -0700204
205 auto it = findPackageRoot(fqName);
206 auto prefix = *it;
207 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
208
209 // Make sure the prefix ends on a '.' and the root path on a '/'
210 if ((*--prefix.end()) != '.') {
211 prefix += '.';
212 }
213
214 if ((*--root.end()) != '/') {
215 root += '/';
216 }
217
218 // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
219 // "android.hardware.", the suffix is "nfc@1.0::IFoo".
220 const std::string packageSuffix = fqName.package().substr(prefix.length());
Andreas Huber5345ec22016-07-29 13:33:27 -0700221
Andreas Huber881227d2016-08-02 14:20:21 -0700222 std::string packagePath;
223 if (!relative) {
Andreas Huberdca261f2016-08-04 13:47:51 -0700224 packagePath = root;
Andreas Huber881227d2016-08-02 14:20:21 -0700225 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700226
227 size_t startPos = 0;
228 size_t dotPos;
229 while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
230 packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
231 packagePath.append("/");
232
233 startPos = dotPos + 1;
234 }
235 CHECK_LT(startPos + 1, packageSuffix.length());
236 packagePath.append(packageSuffix.substr(startPos));
237 packagePath.append("/");
238
Yifan Hong97288ac2016-12-12 16:03:51 -0800239 packagePath.append(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700240 packagePath.append("/");
241
242 return packagePath;
243}
244
Andreas Huberd2943e12016-08-05 11:59:31 -0700245status_t Coordinator::getPackageInterfaceFiles(
246 const FQName &package,
247 std::vector<std::string> *fileNames) const {
248 fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700249
Andreas Huberd2943e12016-08-05 11:59:31 -0700250 const std::string packagePath = getPackagePath(package);
251
252 DIR *dir = opendir(packagePath.c_str());
253
254 if (dir == NULL) {
Steven Moreland261370a2016-08-29 15:36:59 -0700255 LOG(ERROR) << "Could not open package path: " << packagePath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700256 return -errno;
257 }
258
259 struct dirent *ent;
260 while ((ent = readdir(dir)) != NULL) {
261 if (ent->d_type != DT_REG) {
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700262 continue;
263 }
264
Andreas Huberd2943e12016-08-05 11:59:31 -0700265 const auto suffix = ".hal";
266 const auto suffix_len = std::strlen(suffix);
267 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700268
Andreas Huberd2943e12016-08-05 11:59:31 -0700269 if (d_namelen < suffix_len
270 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
271 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700272 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700273
274 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
275 }
276
277 closedir(dir);
278 dir = NULL;
279
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700280 std::sort(fileNames->begin(), fileNames->end(),
281 [](const std::string& lhs, const std::string& rhs) -> bool {
282 if (lhs == "types") {
283 return true;
284 }
285 if (rhs == "types") {
286 return false;
287 }
288 return lhs < rhs;
289 });
290
Andreas Huberd2943e12016-08-05 11:59:31 -0700291 return OK;
292}
293
Steven Morelandaa186832016-09-26 13:51:43 -0700294status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700295 const FQName &package,
296 std::vector<FQName> *packageInterfaces) const {
297 packageInterfaces->clear();
298
299 std::vector<std::string> fileNames;
300 status_t err = getPackageInterfaceFiles(package, &fileNames);
301
302 if (err != OK) {
303 return err;
304 }
305
306 for (const auto &fileName : fileNames) {
307 FQName subFQName(
Yifan Hong90ea87f2016-11-01 14:25:47 -0700308 package.package() + package.atVersion() + "::" + fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700309
310 if (!subFQName.isValid()) {
311 LOG(WARNING)
312 << "Whole-package import encountered invalid filename '"
313 << fileName
314 << "' in package "
315 << package.package()
Yifan Hong90ea87f2016-11-01 14:25:47 -0700316 << package.atVersion();
Andreas Huberd2943e12016-08-05 11:59:31 -0700317
318 continue;
319 }
320
321 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700322 }
323
324 return OK;
325}
326
Andreas Huberd2943e12016-08-05 11:59:31 -0700327std::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
328 std::string packageRoot = getPackageRoot(fqName);
329
330 if (*(packageRoot.end()--) != '.') {
331 packageRoot += '.';
332 }
333
334 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
335
336 return packageRoot; // now converted to a path
337}
338
339// static
340bool Coordinator::MakeParentHierarchy(const std::string &path) {
341 static const mode_t kMode = 0755;
342
343 size_t start = 1; // Ignore leading '/'
344 size_t slashPos;
345 while ((slashPos = path.find("/", start)) != std::string::npos) {
346 std::string partial = path.substr(0, slashPos);
347
348 struct stat st;
349 if (stat(partial.c_str(), &st) < 0) {
350 if (errno != ENOENT) {
351 return false;
352 }
353
354 int res = mkdir(partial.c_str(), kMode);
355 if (res < 0) {
356 return false;
357 }
358 } else if (!S_ISDIR(st.st_mode)) {
359 return false;
360 }
361
362 start = slashPos + 1;
363 }
364
365 return true;
366}
367
Andreas Huber5345ec22016-07-29 13:33:27 -0700368} // namespace android
369