blob: f2bab3061f03d188cd4d510548269b1e38210a47 [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
167 // TODO: This now returns on the first match. Throw an error if
168 // there are multiple hits.
169 auto it = mPackageRoots.begin();
170 for (; it != mPackageRoots.end(); it++) {
Steven Moreland5715fed2017-01-16 11:06:47 -0800171 if (StringHelper::StartsWith(fqName.package(), *it)) {
Andreas Huberdca261f2016-08-04 13:47:51 -0700172 break;
173 }
174 }
Andreas Huber401cd162016-08-26 10:40:30 -0700175 CHECK(it != mPackageRoots.end())
176 << "Unable to find package root for " << fqName.string();
Andreas Huberdca261f2016-08-04 13:47:51 -0700177
178 return it;
179}
180
181std::string Coordinator::getPackageRoot(const FQName &fqName) const {
182 auto it = findPackageRoot(fqName);
183 auto prefix = *it;
184 return prefix;
185}
186
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700187std::string Coordinator::getPackageRootPath(const FQName &fqName) const {
188 auto it = findPackageRoot(fqName);
189 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
190 return root;
191}
192
Yifan Hongc8934042016-11-17 17:10:52 -0800193std::string Coordinator::getPackageRootOption(const FQName &fqName) const {
194 return getPackageRoot(fqName) + ":" + getPackageRootPath(fqName);
195}
196
Andreas Huberdca261f2016-08-04 13:47:51 -0700197std::string Coordinator::getPackagePath(
Yifan Hong97288ac2016-12-12 16:03:51 -0800198 const FQName &fqName, bool relative, bool sanitized) const {
Andreas Huberdca261f2016-08-04 13:47:51 -0700199
200 auto it = findPackageRoot(fqName);
201 auto prefix = *it;
202 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
203
204 // Make sure the prefix ends on a '.' and the root path on a '/'
205 if ((*--prefix.end()) != '.') {
206 prefix += '.';
207 }
208
209 if ((*--root.end()) != '/') {
210 root += '/';
211 }
212
213 // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
214 // "android.hardware.", the suffix is "nfc@1.0::IFoo".
215 const std::string packageSuffix = fqName.package().substr(prefix.length());
Andreas Huber5345ec22016-07-29 13:33:27 -0700216
Andreas Huber881227d2016-08-02 14:20:21 -0700217 std::string packagePath;
218 if (!relative) {
Andreas Huberdca261f2016-08-04 13:47:51 -0700219 packagePath = root;
Andreas Huber881227d2016-08-02 14:20:21 -0700220 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700221
222 size_t startPos = 0;
223 size_t dotPos;
224 while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
225 packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
226 packagePath.append("/");
227
228 startPos = dotPos + 1;
229 }
230 CHECK_LT(startPos + 1, packageSuffix.length());
231 packagePath.append(packageSuffix.substr(startPos));
232 packagePath.append("/");
233
Yifan Hong97288ac2016-12-12 16:03:51 -0800234 packagePath.append(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700235 packagePath.append("/");
236
237 return packagePath;
238}
239
Andreas Huberd2943e12016-08-05 11:59:31 -0700240status_t Coordinator::getPackageInterfaceFiles(
241 const FQName &package,
242 std::vector<std::string> *fileNames) const {
243 fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700244
Andreas Huberd2943e12016-08-05 11:59:31 -0700245 const std::string packagePath = getPackagePath(package);
246
247 DIR *dir = opendir(packagePath.c_str());
248
249 if (dir == NULL) {
Steven Moreland261370a2016-08-29 15:36:59 -0700250 LOG(ERROR) << "Could not open package path: " << packagePath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700251 return -errno;
252 }
253
254 struct dirent *ent;
255 while ((ent = readdir(dir)) != NULL) {
256 if (ent->d_type != DT_REG) {
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700257 continue;
258 }
259
Andreas Huberd2943e12016-08-05 11:59:31 -0700260 const auto suffix = ".hal";
261 const auto suffix_len = std::strlen(suffix);
262 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700263
Andreas Huberd2943e12016-08-05 11:59:31 -0700264 if (d_namelen < suffix_len
265 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
266 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700267 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700268
269 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
270 }
271
272 closedir(dir);
273 dir = NULL;
274
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700275 std::sort(fileNames->begin(), fileNames->end(),
276 [](const std::string& lhs, const std::string& rhs) -> bool {
277 if (lhs == "types") {
278 return true;
279 }
280 if (rhs == "types") {
281 return false;
282 }
283 return lhs < rhs;
284 });
285
Andreas Huberd2943e12016-08-05 11:59:31 -0700286 return OK;
287}
288
Steven Morelandaa186832016-09-26 13:51:43 -0700289status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700290 const FQName &package,
291 std::vector<FQName> *packageInterfaces) const {
292 packageInterfaces->clear();
293
294 std::vector<std::string> fileNames;
295 status_t err = getPackageInterfaceFiles(package, &fileNames);
296
297 if (err != OK) {
298 return err;
299 }
300
301 for (const auto &fileName : fileNames) {
302 FQName subFQName(
Yifan Hong90ea87f2016-11-01 14:25:47 -0700303 package.package() + package.atVersion() + "::" + fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700304
305 if (!subFQName.isValid()) {
306 LOG(WARNING)
307 << "Whole-package import encountered invalid filename '"
308 << fileName
309 << "' in package "
310 << package.package()
Yifan Hong90ea87f2016-11-01 14:25:47 -0700311 << package.atVersion();
Andreas Huberd2943e12016-08-05 11:59:31 -0700312
313 continue;
314 }
315
316 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700317 }
318
319 return OK;
320}
321
Andreas Huberd2943e12016-08-05 11:59:31 -0700322std::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
323 std::string packageRoot = getPackageRoot(fqName);
324
325 if (*(packageRoot.end()--) != '.') {
326 packageRoot += '.';
327 }
328
329 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
330
331 return packageRoot; // now converted to a path
332}
333
334// static
335bool Coordinator::MakeParentHierarchy(const std::string &path) {
336 static const mode_t kMode = 0755;
337
338 size_t start = 1; // Ignore leading '/'
339 size_t slashPos;
340 while ((slashPos = path.find("/", start)) != std::string::npos) {
341 std::string partial = path.substr(0, slashPos);
342
343 struct stat st;
344 if (stat(partial.c_str(), &st) < 0) {
345 if (errno != ENOENT) {
346 return false;
347 }
348
349 int res = mkdir(partial.c_str(), kMode);
350 if (res < 0) {
351 return false;
352 }
353 } else if (!S_ISDIR(st.st_mode)) {
354 return false;
355 }
356
357 start = slashPos + 1;
358 }
359
360 return true;
361}
362
Andreas Huber5345ec22016-07-29 13:33:27 -0700363} // namespace android
364