Coordinator.cpp revision aa1868371f36507ff8f6337ec0e6bb02b2620981
11aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber/*
21aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * Copyright (C) 2016 The Android Open Source Project
31aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber *
41aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
51aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * you may not use this file except in compliance with the License.
61aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * You may obtain a copy of the License at
71aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber *
81aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
91aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber *
101aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * Unless required by applicable law or agreed to in writing, software
111aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
121aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * See the License for the specific language governing permissions and
141aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber * limitations under the License.
151aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber */
161aec397b1fdea7db4120dbe55b6995bb2a9d9138Andreas Huber
175345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber#include "Coordinator.h"
185345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
195345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber#include "AST.h"
205345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
215e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev#include <algorithm>
225345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber#include <android-base/logging.h>
23dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber#include <iterator>
24a72e0d2be173cebf62f728b9d215808bd862f219Iliyan Malchev#include <dirent.h>
25d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber#include <sys/stat.h>
265345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
270d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huberextern android::status_t parseFile(android::AST *ast);
285345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
295345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Hubernamespace android {
305345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
31dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas HuberCoordinator::Coordinator(
32dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        const std::vector<std::string> &packageRootPaths,
33dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        const std::vector<std::string> &packageRoots)
34dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    : mPackageRootPaths(packageRootPaths),
35dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber      mPackageRoots(packageRoots) {
36dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // empty
37dc981333b38f47f416b9b810dc80e5cf2d7ac68aAndreas Huber}
38dc981333b38f47f416b9b810dc80e5cf2d7ac68aAndreas Huber
39dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas HuberCoordinator::~Coordinator() {
40dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // empty
41dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber}
425345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
4339fa71827738f6c1340e4523946fe9bf704eef3aAndreas HuberAST *Coordinator::parse(const FQName &fqName, std::set<AST *> *parsedASTs) {
4468f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    CHECK(fqName.isFullyQualified());
4568f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
46d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland    auto it = mCache.find(fqName);
47d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland    if (it != mCache.end()) {
48d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland        AST *ast = (*it).second;
495345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
5039fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        if (ast != nullptr && parsedASTs != nullptr) {
5139fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber            parsedASTs->insert(ast);
5239fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        }
5339fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
545345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber        return ast;
555345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    }
565345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
5768f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    // Add this to the cache immediately, so we can discover circular imports.
58d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland    mCache[fqName] = nullptr;
5939fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
6039fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber    AST *typesAST = nullptr;
6168f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
6268f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    if (fqName.name() != "types") {
6368f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber        // Any interface file implicitly imports its package's types.hal.
6468f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber        FQName typesName(fqName.package(), fqName.version(), "types");
6539fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        typesAST = parse(typesName, parsedASTs);
6668f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
6768f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber        // fall through.
6868f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    }
6968f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
70dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    std::string path = getPackagePath(fqName);
71dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
7268f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    path.append(fqName.name());
7368f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    path.append(".hal");
745345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
750d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber    AST *ast = new AST(this, path);
7639fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
7739fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber    if (typesAST != NULL) {
7839fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        // If types.hal for this AST's package existed, make it's defined
7939fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        // types available to the (about to be parsed) AST right away.
8039fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        ast->addImportedAST(typesAST);
8139fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber    }
8239fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
830d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber    status_t err = parseFile(ast);
8468f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
8568f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    if (err != OK) {
866e584b70065ce37615980aba5ed60d27a54da1c3Andreas Huber        // LOG(ERROR) << "parsing '" << path << "' FAILED.";
876e584b70065ce37615980aba5ed60d27a54da1c3Andreas Huber
8868f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber        delete ast;
8939fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        ast = nullptr;
905345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
9139fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        return nullptr;
9268f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    }
9368f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
94a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    if (ast->package().package() != fqName.package()
95a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            || ast->package().version() != fqName.version()) {
9670a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber        fprintf(stderr,
9770a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                "ERROR: File at '%s' does not match expected package and/or "
980d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber                "version.\n",
9970a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                path.c_str());
100a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
101a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        err = UNKNOWN_ERROR;
102a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    } else {
103a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        std::string ifaceName;
104a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        if (ast->isInterface(&ifaceName)) {
105a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            if (fqName.name() == "types") {
10670a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                fprintf(stderr,
10770a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        "ERROR: File at '%s' declares an interface '%s' "
1080d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber                        "instead of the expected types common to the package.\n",
10970a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        path.c_str(),
11070a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        ifaceName.c_str());
111a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
112a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber                err = UNKNOWN_ERROR;
113a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            } else if (ifaceName != fqName.name()) {
11470a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                fprintf(stderr,
11570a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        "ERROR: File at '%s' does not declare interface type "
1160d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber                        "'%s'.\n",
11770a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        path.c_str(),
11870a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        fqName.name().c_str());
119a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
120a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber                err = UNKNOWN_ERROR;
121a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            }
122a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        } else if (fqName.name() != "types") {
12370a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber            fprintf(stderr,
12470a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                    "ERROR: File at '%s' declares types rather than the "
1250d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber                    "expected interface type '%s'.\n",
12670a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                    path.c_str(),
12770a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                    fqName.name().c_str());
128a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
129a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            err = UNKNOWN_ERROR;
130a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        }
131a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    }
132a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
133a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    if (err != OK) {
134a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        delete ast;
13539fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        ast = nullptr;
136a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
13739fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        return nullptr;
138a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    }
139a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
14039fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber    if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
14139fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
142d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland    mCache[fqName] = ast;
1435345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
1445345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    return ast;
1455345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber}
1465345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
147dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huberstd::vector<std::string>::const_iterator
148dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas HuberCoordinator::findPackageRoot(const FQName &fqName) const {
1495345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    CHECK(!fqName.package().empty());
1505345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    CHECK(!fqName.version().empty());
1515345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
152dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // Find the right package prefix and path for this FQName.  For
153dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
154dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // prefix:root is set to [ "android.hardware:hardware/interfaces",
155dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
156dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // prefix "android.hardware" and the package root
157dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // "hardware/interfaces".
158dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
159dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // TODO: This now returns on the first match.  Throw an error if
160dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // there are multiple hits.
161dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto it = mPackageRoots.begin();
162dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    for (; it != mPackageRoots.end(); it++) {
163dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        if (fqName.package().find(*it) != std::string::npos) {
164dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber            break;
165dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        }
166dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    }
167401cd16db8a421aaf91338024cea9208549ef67eAndreas Huber    CHECK(it != mPackageRoots.end())
168401cd16db8a421aaf91338024cea9208549ef67eAndreas Huber        << "Unable to find package root for " << fqName.string();
169dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
170dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    return it;
171dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber}
172dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
173dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huberstd::string Coordinator::getPackageRoot(const FQName &fqName) const {
174dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto it = findPackageRoot(fqName);
175dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto prefix = *it;
176dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    return prefix;
177dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber}
178dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
1795bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchevstd::string Coordinator::getPackageRootPath(const FQName &fqName) const {
1805bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev    auto it = findPackageRoot(fqName);
1815bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev    auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
1825bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev    return root;
1835bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev}
1845bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev
185dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huberstd::string Coordinator::getPackagePath(
186dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        const FQName &fqName, bool relative) const {
187dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
188dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto it = findPackageRoot(fqName);
189dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto prefix = *it;
190dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
191dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
192dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // Make sure the prefix ends on a '.' and the root path on a '/'
193dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    if ((*--prefix.end()) != '.') {
194dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        prefix += '.';
195dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    }
196dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
197dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    if ((*--root.end()) != '/') {
198dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        root += '/';
199dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    }
200dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
201dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
202dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // "android.hardware.", the suffix is "nfc@1.0::IFoo".
203dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    const std::string packageSuffix = fqName.package().substr(prefix.length());
2045345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
205881227d860c59471eee31d39946e96ce2daa35d6Andreas Huber    std::string packagePath;
206881227d860c59471eee31d39946e96ce2daa35d6Andreas Huber    if (!relative) {
207dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        packagePath = root;
208881227d860c59471eee31d39946e96ce2daa35d6Andreas Huber    }
2095345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
2105345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    size_t startPos = 0;
2115345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    size_t dotPos;
2125345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
2135345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber        packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
2145345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber        packagePath.append("/");
2155345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
2165345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber        startPos = dotPos + 1;
2175345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    }
2185345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    CHECK_LT(startPos + 1, packageSuffix.length());
2195345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    packagePath.append(packageSuffix.substr(startPos));
2205345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    packagePath.append("/");
2215345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
2225345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    CHECK_EQ(fqName.version().find('@'), 0u);
2235345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    packagePath.append(fqName.version().substr(1));
2245345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    packagePath.append("/");
2255345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
2265345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    return packagePath;
2275345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber}
2285345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
229d2943e11533697b97aa5330f05fc144493748c0bAndreas Huberstatus_t Coordinator::getPackageInterfaceFiles(
230d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const FQName &package,
231d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        std::vector<std::string> *fileNames) const {
232d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    fileNames->clear();
2336cb08cf9f021a01d9d2b1eaec6729aac6ae70708Andreas Huber
234d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    const std::string packagePath = getPackagePath(package);
235d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
236d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    DIR *dir = opendir(packagePath.c_str());
237d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
238d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    if (dir == NULL) {
239261370ae8d57b78b01e4168abcf54d506f946f24Steven Moreland        LOG(ERROR) << "Could not open package path: " << packagePath;
240d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        return -errno;
241d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
242d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
243d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    struct dirent *ent;
244d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    while ((ent = readdir(dir)) != NULL) {
245d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        if (ent->d_type != DT_REG) {
2466cb08cf9f021a01d9d2b1eaec6729aac6ae70708Andreas Huber            continue;
2476cb08cf9f021a01d9d2b1eaec6729aac6ae70708Andreas Huber        }
2486cb08cf9f021a01d9d2b1eaec6729aac6ae70708Andreas Huber
249d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const auto suffix = ".hal";
250d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const auto suffix_len = std::strlen(suffix);
251d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const auto d_namelen = strlen(ent->d_name);
252e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber
253d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        if (d_namelen < suffix_len
254d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
255d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            continue;
256e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber        }
257d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
258d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
259e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber    }
260e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber
261d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    closedir(dir);
262d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    dir = NULL;
263d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
2645e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev    std::sort(fileNames->begin(), fileNames->end(),
2655e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev              [](const std::string& lhs, const std::string& rhs) -> bool {
2665e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  if (lhs == "types") {
2675e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                      return true;
2685e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  }
2695e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  if (rhs == "types") {
2705e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                      return false;
2715e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  }
2725e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  return lhs < rhs;
2735e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev              });
2745e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev
275e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber    return OK;
276e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber}
277e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber
278aa1868371f36507ff8f6337ec0e6bb02b2620981Steven Morelandstatus_t Coordinator::appendPackageInterfacesToVector(
279d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const FQName &package,
280d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        std::vector<FQName> *packageInterfaces) const {
281d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    packageInterfaces->clear();
282d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
283d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    std::vector<std::string> fileNames;
284d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    status_t err = getPackageInterfaceFiles(package, &fileNames);
285d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
286d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    if (err != OK) {
287d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        return err;
288d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
289d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
290d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    for (const auto &fileName : fileNames) {
291d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        FQName subFQName(
292d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                package.package() + package.version() + "::" + fileName);
293d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
294d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        if (!subFQName.isValid()) {
295d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            LOG(WARNING)
296d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << "Whole-package import encountered invalid filename '"
297d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << fileName
298d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << "' in package "
299d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << package.package()
300d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << package.version();
301d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
302d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            continue;
303d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        }
304d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
305d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        packageInterfaces->push_back(subFQName);
306d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
307d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
308d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    return OK;
309d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber}
310d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
311d2943e11533697b97aa5330f05fc144493748c0bAndreas Huberstd::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
312d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    std::string packageRoot = getPackageRoot(fqName);
313d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
314d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    if (*(packageRoot.end()--) != '.') {
315d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        packageRoot += '.';
316d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
317d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
318d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
319d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
320d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    return packageRoot; // now converted to a path
321d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber}
322d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
323d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber// static
324d2943e11533697b97aa5330f05fc144493748c0bAndreas Huberbool Coordinator::MakeParentHierarchy(const std::string &path) {
325d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    static const mode_t kMode = 0755;
326d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
327d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    size_t start = 1;  // Ignore leading '/'
328d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    size_t slashPos;
329d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    while ((slashPos = path.find("/", start)) != std::string::npos) {
330d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        std::string partial = path.substr(0, slashPos);
331d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
332d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        struct stat st;
333d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        if (stat(partial.c_str(), &st) < 0) {
334d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            if (errno != ENOENT) {
335d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                return false;
336d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            }
337d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
338d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            int res = mkdir(partial.c_str(), kMode);
339d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            if (res < 0) {
340d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                return false;
341d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            }
342d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        } else if (!S_ISDIR(st.st_mode)) {
343d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            return false;
344d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        }
345d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
346d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        start = slashPos + 1;
347d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
348d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
349d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    return true;
350d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber}
351d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
3525345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber}  // namespace android
3535345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
354