Coordinator.cpp revision 62709d73d7f260fae0a475f8d4d30eb3665e8168
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>
235715fedbd05231bf845e3a120c83b931b7f53aa3Steven Moreland#include <hidl-util/StringHelper.h>
24dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber#include <iterator>
25a72e0d2be173cebf62f728b9d215808bd862f219Iliyan Malchev#include <dirent.h>
26d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber#include <sys/stat.h>
275345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
280d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huberextern android::status_t parseFile(android::AST *ast);
295345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
305345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Hubernamespace android {
315345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
32dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas HuberCoordinator::Coordinator(
33dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        const std::vector<std::string> &packageRootPaths,
34dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        const std::vector<std::string> &packageRoots)
35dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    : mPackageRootPaths(packageRootPaths),
36dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber      mPackageRoots(packageRoots) {
37dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // empty
38dc981333b38f47f416b9b810dc80e5cf2d7ac68aAndreas Huber}
39dc981333b38f47f416b9b810dc80e5cf2d7ac68aAndreas Huber
40dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas HuberCoordinator::~Coordinator() {
41dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // empty
42dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber}
435345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
4439fa71827738f6c1340e4523946fe9bf704eef3aAndreas HuberAST *Coordinator::parse(const FQName &fqName, std::set<AST *> *parsedASTs) {
4568f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    CHECK(fqName.isFullyQualified());
4668f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
47d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland    auto it = mCache.find(fqName);
48d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland    if (it != mCache.end()) {
49d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland        AST *ast = (*it).second;
505345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
5139fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        if (ast != nullptr && parsedASTs != nullptr) {
5239fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber            parsedASTs->insert(ast);
5339fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        }
5439fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
555345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber        return ast;
565345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    }
575345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
5868f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    // Add this to the cache immediately, so we can discover circular imports.
59d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland    mCache[fqName] = nullptr;
6039fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
6139fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber    AST *typesAST = nullptr;
6268f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
6368f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    if (fqName.name() != "types") {
6468f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber        // Any interface file implicitly imports its package's types.hal.
65fece6ecab34d69d38f57419d2500017a7136083eYifan Hong        FQName typesName = fqName.getTypesForPackage();
6639fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        typesAST = parse(typesName, parsedASTs);
6768f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
6868f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber        // fall through.
6968f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    }
7068f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
71dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    std::string path = getPackagePath(fqName);
72dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
7368f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    path.append(fqName.name());
7468f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    path.append(".hal");
755345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
760d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber    AST *ast = new AST(this, path);
7739fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
7839fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber    if (typesAST != NULL) {
7939fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        // If types.hal for this AST's package existed, make it's defined
8039fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        // types available to the (about to be parsed) AST right away.
8139fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        ast->addImportedAST(typesAST);
8239fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber    }
8339fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
840d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber    status_t err = parseFile(ast);
8568f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
8668f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    if (err != OK) {
876e584b70065ce37615980aba5ed60d27a54da1c3Andreas Huber        // LOG(ERROR) << "parsing '" << path << "' FAILED.";
886e584b70065ce37615980aba5ed60d27a54da1c3Andreas Huber
8968f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber        delete ast;
9039fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        ast = nullptr;
915345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
9239fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        return nullptr;
9368f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber    }
9468f24590cda230fb92eac44ed0247f54f9b31ad0Andreas Huber
95a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    if (ast->package().package() != fqName.package()
96a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            || ast->package().version() != fqName.version()) {
9770a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber        fprintf(stderr,
9870a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                "ERROR: File at '%s' does not match expected package and/or "
990d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber                "version.\n",
10070a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                path.c_str());
101a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
102a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        err = UNKNOWN_ERROR;
103a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    } else {
104a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        std::string ifaceName;
105a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        if (ast->isInterface(&ifaceName)) {
106a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            if (fqName.name() == "types") {
10770a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                fprintf(stderr,
10870a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        "ERROR: File at '%s' declares an interface '%s' "
1090d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber                        "instead of the expected types common to the package.\n",
11070a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        path.c_str(),
11170a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        ifaceName.c_str());
112a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
113a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber                err = UNKNOWN_ERROR;
114a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            } else if (ifaceName != fqName.name()) {
11570a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                fprintf(stderr,
11670a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        "ERROR: File at '%s' does not declare interface type "
1170d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber                        "'%s'.\n",
11870a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        path.c_str(),
11970a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                        fqName.name().c_str());
120a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
121a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber                err = UNKNOWN_ERROR;
122a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            }
123a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        } else if (fqName.name() != "types") {
12470a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber            fprintf(stderr,
12570a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                    "ERROR: File at '%s' declares types rather than the "
1260d0f9a2e0195a8609f1939c35bd8907253b68249Andreas Huber                    "expected interface type '%s'.\n",
12770a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                    path.c_str(),
12870a59e1dc3dcf32f791d2dd7966111d4adf32ecaAndreas Huber                    fqName.name().c_str());
129a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
130a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber            err = UNKNOWN_ERROR;
1317c5ddfb41a806a7bf71581952d06b637a7670cf7Andreas Huber        } else if (ast->containsInterfaces()) {
1327c5ddfb41a806a7bf71581952d06b637a7670cf7Andreas Huber            fprintf(stderr,
1337c5ddfb41a806a7bf71581952d06b637a7670cf7Andreas Huber                    "ERROR: types.hal file at '%s' declares at least one "
1347c5ddfb41a806a7bf71581952d06b637a7670cf7Andreas Huber                    "interface type.\n",
1357c5ddfb41a806a7bf71581952d06b637a7670cf7Andreas Huber                    path.c_str());
1367c5ddfb41a806a7bf71581952d06b637a7670cf7Andreas Huber
1377c5ddfb41a806a7bf71581952d06b637a7670cf7Andreas Huber            err = UNKNOWN_ERROR;
138a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        }
139a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    }
140a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
141a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    if (err != OK) {
142a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber        delete ast;
14339fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        ast = nullptr;
144a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
14539fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber        return nullptr;
146a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber    }
147a2723d26427f7db19777dfed330047253e7a4e1bAndreas Huber
14839fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber    if (parsedASTs != nullptr) { parsedASTs->insert(ast); }
14939fa71827738f6c1340e4523946fe9bf704eef3aAndreas Huber
150d537ab02e1707597d70665fd8c75ca1ec9f57326Steven Moreland    mCache[fqName] = ast;
1515345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
1525345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    return ast;
1535345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber}
1545345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
155dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huberstd::vector<std::string>::const_iterator
156dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas HuberCoordinator::findPackageRoot(const FQName &fqName) const {
1575345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    CHECK(!fqName.package().empty());
1585345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    CHECK(!fqName.version().empty());
1595345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
160dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // Find the right package prefix and path for this FQName.  For
161dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
162dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // prefix:root is set to [ "android.hardware:hardware/interfaces",
163dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
164dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // prefix "android.hardware" and the package root
165dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // "hardware/interfaces".
166dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
167dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto it = mPackageRoots.begin();
16862709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland    auto ret = mPackageRoots.end();
169dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    for (; it != mPackageRoots.end(); it++) {
17062709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland        if (!fqName.inPackage(*it)) {
17162709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland            continue;
172dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        }
17362709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland
17462709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland        CHECK(ret == mPackageRoots.end())
17562709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland            << "Multiple package roots found for " << fqName.string()
17662709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland            << " (" << *it << " and " << *ret << ")";
17762709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland
17862709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland        ret = it;
179dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    }
18062709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland    CHECK(ret != mPackageRoots.end())
181401cd16db8a421aaf91338024cea9208549ef67eAndreas Huber        << "Unable to find package root for " << fqName.string();
182dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
18362709d73d7f260fae0a475f8d4d30eb3665e8168Steven Moreland    return ret;
184dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber}
185dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
186dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huberstd::string Coordinator::getPackageRoot(const FQName &fqName) const {
187dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto it = findPackageRoot(fqName);
188dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto prefix = *it;
189dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    return prefix;
190dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber}
191dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
1925bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchevstd::string Coordinator::getPackageRootPath(const FQName &fqName) const {
1935bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev    auto it = findPackageRoot(fqName);
1945bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev    auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
1955bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev    return root;
1965bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev}
1975bb14024064a51a044e51c14466e5b2ae8352505Iliyan Malchev
198c89340422f53046bfe24ff3e529161f9194120f8Yifan Hongstd::string Coordinator::getPackageRootOption(const FQName &fqName) const {
199c89340422f53046bfe24ff3e529161f9194120f8Yifan Hong    return getPackageRoot(fqName) + ":" + getPackageRootPath(fqName);
200c89340422f53046bfe24ff3e529161f9194120f8Yifan Hong}
201c89340422f53046bfe24ff3e529161f9194120f8Yifan Hong
202dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huberstd::string Coordinator::getPackagePath(
20397288acdcff66df30cc443c65ddb815e8d0cfeaaYifan Hong        const FQName &fqName, bool relative, bool sanitized) const {
204dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
205dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto it = findPackageRoot(fqName);
206dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto prefix = *it;
207dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    auto root = mPackageRootPaths[std::distance(mPackageRoots.begin(), it)];
208dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
209dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // Make sure the prefix ends on a '.' and the root path on a '/'
210dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    if ((*--prefix.end()) != '.') {
211dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        prefix += '.';
212dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    }
213dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
214dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    if ((*--root.end()) != '/') {
215dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        root += '/';
216dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    }
217dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber
218dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // Given FQName of "android.hardware.nfc@1.0::IFoo" and a prefix
219dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    // "android.hardware.", the suffix is "nfc@1.0::IFoo".
220dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber    const std::string packageSuffix = fqName.package().substr(prefix.length());
2215345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
222881227d860c59471eee31d39946e96ce2daa35d6Andreas Huber    std::string packagePath;
223881227d860c59471eee31d39946e96ce2daa35d6Andreas Huber    if (!relative) {
224dca261ff8a8fed807c6e8206360eb84b1ff9e0a9Andreas Huber        packagePath = root;
225881227d860c59471eee31d39946e96ce2daa35d6Andreas Huber    }
2265345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
2275345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    size_t startPos = 0;
2285345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    size_t dotPos;
2295345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    while ((dotPos = packageSuffix.find('.', startPos)) != std::string::npos) {
2305345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber        packagePath.append(packageSuffix.substr(startPos, dotPos - startPos));
2315345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber        packagePath.append("/");
2325345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
2335345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber        startPos = dotPos + 1;
2345345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    }
2355345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    CHECK_LT(startPos + 1, packageSuffix.length());
2365345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    packagePath.append(packageSuffix.substr(startPos));
2375345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    packagePath.append("/");
2385345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
23997288acdcff66df30cc443c65ddb815e8d0cfeaaYifan Hong    packagePath.append(sanitized ? fqName.sanitizedVersion() : fqName.version());
2405345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    packagePath.append("/");
2415345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
2425345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber    return packagePath;
2435345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber}
2445345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
245d2943e11533697b97aa5330f05fc144493748c0bAndreas Huberstatus_t Coordinator::getPackageInterfaceFiles(
246d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const FQName &package,
247d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        std::vector<std::string> *fileNames) const {
248d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    fileNames->clear();
2496cb08cf9f021a01d9d2b1eaec6729aac6ae70708Andreas Huber
250d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    const std::string packagePath = getPackagePath(package);
251d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
252d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    DIR *dir = opendir(packagePath.c_str());
253d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
254d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    if (dir == NULL) {
255261370ae8d57b78b01e4168abcf54d506f946f24Steven Moreland        LOG(ERROR) << "Could not open package path: " << packagePath;
256d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        return -errno;
257d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
258d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
259d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    struct dirent *ent;
260d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    while ((ent = readdir(dir)) != NULL) {
261d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        if (ent->d_type != DT_REG) {
2626cb08cf9f021a01d9d2b1eaec6729aac6ae70708Andreas Huber            continue;
2636cb08cf9f021a01d9d2b1eaec6729aac6ae70708Andreas Huber        }
2646cb08cf9f021a01d9d2b1eaec6729aac6ae70708Andreas Huber
265d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const auto suffix = ".hal";
266d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const auto suffix_len = std::strlen(suffix);
267d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const auto d_namelen = strlen(ent->d_name);
268e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber
269d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        if (d_namelen < suffix_len
270d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
271d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            continue;
272e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber        }
273d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
274d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
275e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber    }
276e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber
277d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    closedir(dir);
278d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    dir = NULL;
279d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
2805e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev    std::sort(fileNames->begin(), fileNames->end(),
2815e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev              [](const std::string& lhs, const std::string& rhs) -> bool {
2825e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  if (lhs == "types") {
2835e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                      return true;
2845e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  }
2855e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  if (rhs == "types") {
2865e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                      return false;
2875e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  }
2885e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev                  return lhs < rhs;
2895e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev              });
2905e8bcfad6dbb7b85fcd75ae64c569fd6efafb5b8Iliyan Malchev
291e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber    return OK;
292e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber}
293e61e3f7b138a992047a60c4b8c27f1c752ed57baAndreas Huber
294aa1868371f36507ff8f6337ec0e6bb02b2620981Steven Morelandstatus_t Coordinator::appendPackageInterfacesToVector(
295d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        const FQName &package,
296d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        std::vector<FQName> *packageInterfaces) const {
297d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    packageInterfaces->clear();
298d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
299d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    std::vector<std::string> fileNames;
300d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    status_t err = getPackageInterfaceFiles(package, &fileNames);
301d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
302d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    if (err != OK) {
303d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        return err;
304d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
305d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
306d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    for (const auto &fileName : fileNames) {
307d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        FQName subFQName(
30890ea87f36e60a8db0c12d8e7870d45c90c51922dYifan Hong                package.package() + package.atVersion() + "::" + fileName);
309d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
310d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        if (!subFQName.isValid()) {
311d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            LOG(WARNING)
312d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << "Whole-package import encountered invalid filename '"
313d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << fileName
314d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << "' in package "
315d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                << package.package()
31690ea87f36e60a8db0c12d8e7870d45c90c51922dYifan Hong                << package.atVersion();
317d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
318d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            continue;
319d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        }
320d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
321d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        packageInterfaces->push_back(subFQName);
322d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
323d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
324d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    return OK;
325d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber}
326d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
327d2943e11533697b97aa5330f05fc144493748c0bAndreas Huberstd::string Coordinator::convertPackageRootToPath(const FQName &fqName) const {
328d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    std::string packageRoot = getPackageRoot(fqName);
329d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
330d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    if (*(packageRoot.end()--) != '.') {
331d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        packageRoot += '.';
332d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
333d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
334d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
335d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
336d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    return packageRoot; // now converted to a path
337d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber}
338d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
339d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber// static
340d2943e11533697b97aa5330f05fc144493748c0bAndreas Huberbool Coordinator::MakeParentHierarchy(const std::string &path) {
341d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    static const mode_t kMode = 0755;
342d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
343d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    size_t start = 1;  // Ignore leading '/'
344d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    size_t slashPos;
345d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    while ((slashPos = path.find("/", start)) != std::string::npos) {
346d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        std::string partial = path.substr(0, slashPos);
347d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
348d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        struct stat st;
349d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        if (stat(partial.c_str(), &st) < 0) {
350d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            if (errno != ENOENT) {
351d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                return false;
352d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            }
353d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
354d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            int res = mkdir(partial.c_str(), kMode);
355d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            if (res < 0) {
356d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber                return false;
357d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            }
358d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        } else if (!S_ISDIR(st.st_mode)) {
359d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber            return false;
360d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        }
361d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
362d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber        start = slashPos + 1;
363d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    }
364d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
365d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber    return true;
366d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber}
367d2943e11533697b97aa5330f05fc144493748c0bAndreas Huber
3685345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber}  // namespace android
3695345ec2b1b7e4126b77aa2131b231a9eb5ee811dAndreas Huber
370