blob: 57da8bbd2760582f6540b9767af85ed4daf16f72 [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>
Andreas Huberdca261f2016-08-04 13:47:51 -070023#include <iterator>
Iliyan Malcheva72e0d22016-09-09 11:03:08 -070024#include <dirent.h>
Andreas Huberd2943e12016-08-05 11:59:31 -070025#include <sys/stat.h>
Andreas Huber5345ec22016-07-29 13:33:27 -070026
Andreas Huber0d0f9a22016-08-17 10:26:11 -070027extern android::status_t parseFile(android::AST *ast);
Andreas Huber5345ec22016-07-29 13:33:27 -070028
29namespace android {
30
Andreas Huberdca261f2016-08-04 13:47:51 -070031Coordinator::Coordinator(
32 const std::vector<std::string> &packageRootPaths,
33 const std::vector<std::string> &packageRoots)
34 : mPackageRootPaths(packageRootPaths),
35 mPackageRoots(packageRoots) {
36 // empty
Andreas Huberdc981332016-07-29 15:46:54 -070037}
38
Andreas Huberdca261f2016-08-04 13:47:51 -070039Coordinator::~Coordinator() {
40 // empty
41}
Andreas Huber5345ec22016-07-29 13:33:27 -070042
Andreas Huber39fa7182016-08-19 14:27:33 -070043AST *Coordinator::parse(const FQName &fqName, std::set<AST *> *parsedASTs) {
Andreas Huber68f24592016-07-29 14:53:48 -070044 CHECK(fqName.isFullyQualified());
45
Steven Morelandd537ab02016-09-12 10:32:01 -070046 auto it = mCache.find(fqName);
47 if (it != mCache.end()) {
48 AST *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -070049
Andreas Huber39fa7182016-08-19 14:27:33 -070050 if (ast != nullptr && parsedASTs != nullptr) {
51 parsedASTs->insert(ast);
52 }
53
Andreas Huber5345ec22016-07-29 13:33:27 -070054 return ast;
55 }
56
Andreas Huber68f24592016-07-29 14:53:48 -070057 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -070058 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -070059
60 AST *typesAST = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070061
Andreas Huber68f24592016-07-29 14:53:48 -070062 if (fqName.name() != "types") {
63 // Any interface file implicitly imports its package's types.hal.
64 FQName typesName(fqName.package(), fqName.version(), "types");
Andreas Huber39fa7182016-08-19 14:27:33 -070065 typesAST = parse(typesName, parsedASTs);
Andreas Huber68f24592016-07-29 14:53:48 -070066
67 // fall through.
68 }
69
Andreas Huberdca261f2016-08-04 13:47:51 -070070 std::string path = getPackagePath(fqName);
71
Andreas Huber68f24592016-07-29 14:53:48 -070072 path.append(fqName.name());
73 path.append(".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -070074
Andreas Huber0d0f9a22016-08-17 10:26:11 -070075 AST *ast = new AST(this, path);
Andreas Huber39fa7182016-08-19 14:27:33 -070076
77 if (typesAST != NULL) {
78 // If types.hal for this AST's package existed, make it's defined
79 // types available to the (about to be parsed) AST right away.
80 ast->addImportedAST(typesAST);
81 }
82
Andreas Huber0d0f9a22016-08-17 10:26:11 -070083 status_t err = parseFile(ast);
Andreas Huber5345ec22016-07-29 13:33:27 -070084
Andreas Huber68f24592016-07-29 14:53:48 -070085 if (err != OK) {
Andreas Huber6e584b72016-07-29 16:14:07 -070086 // LOG(ERROR) << "parsing '" << path << "' FAILED.";
87
Andreas Huber68f24592016-07-29 14:53:48 -070088 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -070089 ast = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070090
Andreas Huber39fa7182016-08-19 14:27:33 -070091 return nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -070092 }
93
Andreas Hubera2723d22016-07-29 15:36:07 -070094 if (ast->package().package() != fqName.package()
95 || ast->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -070096 fprintf(stderr,
97 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -070098 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -070099 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700100
101 err = UNKNOWN_ERROR;
102 } else {
103 std::string ifaceName;
104 if (ast->isInterface(&ifaceName)) {
105 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700106 fprintf(stderr,
107 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700108 "instead of the expected types common to the package.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700109 path.c_str(),
110 ifaceName.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700111
112 err = UNKNOWN_ERROR;
113 } else if (ifaceName != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700114 fprintf(stderr,
115 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700116 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700117 path.c_str(),
118 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700119
120 err = UNKNOWN_ERROR;
121 }
122 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700123 fprintf(stderr,
124 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700125 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700126 path.c_str(),
127 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700128
129 err = UNKNOWN_ERROR;
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700130 } else if (ast->containsInterfaces()) {
131 fprintf(stderr,
132 "ERROR: types.hal file at '%s' declares at least one "
133 "interface type.\n",
134 path.c_str());
135
136 err = UNKNOWN_ERROR;
Andreas Hubera2723d22016-07-29 15:36:07 -0700137 }
138 }
139
140 if (err != OK) {
141 delete ast;
Andreas Huber39fa7182016-08-19 14:27:33 -0700142 ast = nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700143
Andreas Huber39fa7182016-08-19 14:27:33 -0700144 return nullptr;
Andreas Hubera2723d22016-07-29 15:36:07 -0700145 }
146
Andreas Huber39fa7182016-08-19 14:27:33 -0700147 if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
148
Steven Morelandd537ab02016-09-12 10:32:01 -0700149 mCache[fqName] = ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700150
151 return ast;
152}
153
Andreas Huberdca261f2016-08-04 13:47:51 -0700154std::vector<std::string>::const_iterator
155Coordinator::findPackageRoot(const FQName &fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700156 CHECK(!fqName.package().empty());
157 CHECK(!fqName.version().empty());
Andreas Huber5345ec22016-07-29 13:33:27 -0700158
Andreas Huberdca261f2016-08-04 13:47:51 -0700159 // Find the right package prefix and path for this FQName. For
160 // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
161 // prefix:root is set to [ "android.hardware:hardware/interfaces",
162 // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
163 // prefix "android.hardware" and the package root
164 // "hardware/interfaces".
165
166 // TODO: This now returns on the first match. Throw an error if
167 // there are multiple hits.
168 auto it = mPackageRoots.begin();
169 for (; it != mPackageRoots.end(); it++) {
170 if (fqName.package().find(*it) != std::string::npos) {
171 break;
172 }
173 }
Andreas Huber401cd162016-08-26 10:40:30 -0700174 CHECK(it != mPackageRoots.end())
175 << "Unable to find package root for " << fqName.string();
Andreas Huberdca261f2016-08-04 13:47:51 -0700176
177 return it;
178}
179
180std::string Coordinator::getPackageRoot(const FQName &fqName) const {
181 auto it = findPackageRoot(fqName);
182 auto prefix = *it;
183 return prefix;
184}
185
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700186std::string Coordinator::getPackageRootPath(const FQName &fqName) const {
187 auto it = findPackageRoot(fqName);
188 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
189 return root;
190}
191
Andreas Huberdca261f2016-08-04 13:47:51 -0700192std::string Coordinator::getPackagePath(
193 const FQName &fqName, bool relative) const {
194
195 auto it = findPackageRoot(fqName);
196 auto prefix = *it;
197 auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
198
199 // Make sure the prefix ends on a '.' and the root path on a '/'
200 if ((*--prefix.end()) != '.') {
201 prefix += '.';
202 }
203
204 if ((*--root.end()) != '/') {
205 root += '/';
206 }
207
208 // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
209 // "android.hardware.", the suffix is "nfc@1.0::IFoo".
210 const std::string packageSuffix = fqName.package().substr(prefix.length());
Andreas Huber5345ec22016-07-29 13:33:27 -0700211
Andreas Huber881227d2016-08-02 14:20:21 -0700212 std::string packagePath;
213 if (!relative) {
Andreas Huberdca261f2016-08-04 13:47:51 -0700214 packagePath = root;
Andreas Huber881227d2016-08-02 14:20:21 -0700215 }
Andreas Huber5345ec22016-07-29 13:33:27 -0700216
217 size_t startPos = 0;
218 size_t dotPos;
219 while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
220 packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
221 packagePath.append("/");
222
223 startPos = dotPos + 1;
224 }
225 CHECK_LT(startPos + 1, packageSuffix.length());
226 packagePath.append(packageSuffix.substr(startPos));
227 packagePath.append("/");
228
Yifan Hong90ea87f2016-11-01 14:25:47 -0700229 packagePath.append(fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700230 packagePath.append("/");
231
232 return packagePath;
233}
234
Andreas Huberd2943e12016-08-05 11:59:31 -0700235status_t Coordinator::getPackageInterfaceFiles(
236 const FQName &package,
237 std::vector<std::string> *fileNames) const {
238 fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700239
Andreas Huberd2943e12016-08-05 11:59:31 -0700240 const std::string packagePath = getPackagePath(package);
241
242 DIR *dir = opendir(packagePath.c_str());
243
244 if (dir == NULL) {
Steven Moreland261370a2016-08-29 15:36:59 -0700245 LOG(ERROR) << "Could not open package path: " << packagePath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700246 return -errno;
247 }
248
249 struct dirent *ent;
250 while ((ent = readdir(dir)) != NULL) {
251 if (ent->d_type != DT_REG) {
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700252 continue;
253 }
254
Andreas Huberd2943e12016-08-05 11:59:31 -0700255 const auto suffix = ".hal";
256 const auto suffix_len = std::strlen(suffix);
257 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700258
Andreas Huberd2943e12016-08-05 11:59:31 -0700259 if (d_namelen < suffix_len
260 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
261 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700262 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700263
264 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
265 }
266
267 closedir(dir);
268 dir = NULL;
269
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700270 std::sort(fileNames->begin(), fileNames->end(),
271 [](const std::string& lhs, const std::string& rhs) -> bool {
272 if (lhs == "types") {
273 return true;
274 }
275 if (rhs == "types") {
276 return false;
277 }
278 return lhs < rhs;
279 });
280
Andreas Huberd2943e12016-08-05 11:59:31 -0700281 return OK;
282}
283
Steven Morelandaa186832016-09-26 13:51:43 -0700284status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700285 const FQName &package,
286 std::vector<FQName> *packageInterfaces) const {
287 packageInterfaces->clear();
288
289 std::vector<std::string> fileNames;
290 status_t err = getPackageInterfaceFiles(package, &fileNames);
291
292 if (err != OK) {
293 return err;
294 }
295
296 for (const auto &fileName : fileNames) {
297 FQName subFQName(
Yifan Hong90ea87f2016-11-01 14:25:47 -0700298 package.package() + package.atVersion() + "::" + fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700299
300 if (!subFQName.isValid()) {
301 LOG(WARNING)
302 << "Whole-package import encountered invalid filename '"
303 << fileName
304 << "' in package "
305 << package.package()
Yifan Hong90ea87f2016-11-01 14:25:47 -0700306 << package.atVersion();
Andreas Huberd2943e12016-08-05 11:59:31 -0700307
308 continue;
309 }
310
311 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700312 }
313
314 return OK;
315}
316
Andreas Huberd2943e12016-08-05 11:59:31 -0700317std::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
318 std::string packageRoot = getPackageRoot(fqName);
319
320 if (*(packageRoot.end()--) != '.') {
321 packageRoot += '.';
322 }
323
324 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
325
326 return packageRoot; // now converted to a path
327}
328
329// static
330bool Coordinator::MakeParentHierarchy(const std::string &path) {
331 static const mode_t kMode = 0755;
332
333 size_t start = 1; // Ignore leading '/'
334 size_t slashPos;
335 while ((slashPos = path.find("/", start)) != std::string::npos) {
336 std::string partial = path.substr(0, slashPos);
337
338 struct stat st;
339 if (stat(partial.c_str(), &st) < 0) {
340 if (errno != ENOENT) {
341 return false;
342 }
343
344 int res = mkdir(partial.c_str(), kMode);
345 if (res < 0) {
346 return false;
347 }
348 } else if (!S_ISDIR(st.st_mode)) {
349 return false;
350 }
351
352 start = slashPos + 1;
353 }
354
355 return true;
356}
357
Andreas Huber5345ec22016-07-29 13:33:27 -0700358} // namespace android
359