AssembleVintf.cpp revision bfb3c1dc59144dd784d1d81af3ce81c97ea2e45a
14d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong/*
24d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * Copyright (C) 2017 The Android Open Source Project
34d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong *
44d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * Licensed under the Apache License, Version 2.0 (the "License");
54d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * you may not use this file except in compliance with the License.
64d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * You may obtain a copy of the License at
74d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong *
84d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong *      http://www.apache.org/licenses/LICENSE-2.0
94d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong *
104d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * Unless required by applicable law or agreed to in writing, software
114d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * distributed under the License is distributed on an "AS IS" BASIS,
124d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * See the License for the specific language governing permissions and
144d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * limitations under the License.
154d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong */
164d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
179aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong#include <getopt.h>
184d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <stdlib.h>
194d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <unistd.h>
204d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
214d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <fstream>
224d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <iostream>
234d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <unordered_map>
244d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <sstream>
254d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <string>
264d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
274d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <vintf/parse_string.h>
284d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <vintf/parse_xml.h>
294d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
304d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongnamespace android {
314d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongnamespace vintf {
324d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
334d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong/**
344d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * Slurps the device manifest file and add build time flag to it.
354d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong */
364d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongclass AssembleVintf {
374d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongpublic:
384d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    template<typename T>
394d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    static bool getFlag(const std::string& key, T* value) {
404d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        const char *envValue = getenv(key.c_str());
414d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        if (envValue == NULL) {
424d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            std::cerr << "Required " << key << " flag." << std::endl;
434d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            return false;
444d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        }
454d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
464d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        if (!parse(envValue, value)) {
474d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            std::cerr << "Cannot parse " << envValue << "." << std::endl;
484d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            return false;
494d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        }
504d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        return true;
514d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    }
524d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
534650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong    static std::string read(std::basic_istream<char>& is) {
544650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong        std::stringstream ss;
554650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong        ss << is.rdbuf();
564650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong        return ss.str();
574650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong    }
584650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
599aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    std::basic_ostream<char>& out() const {
609aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return mOutFileRef == nullptr ? std::cout : *mOutFileRef;
619aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
629aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
639aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool assembleHalManifest(HalManifest* halManifest) {
644650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong        std::string error;
654d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
669aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        if (halManifest->mType == SchemaType::DEVICE) {
679aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!getFlag("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) {
689aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
694d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            }
709aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
714d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
729aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        if (mOutputMatrix) {
739aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            CompatibilityMatrix generatedMatrix = halManifest->generateCompatibleMatrix();
749aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!halManifest->checkCompatibility(generatedMatrix, &error)) {
759aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                std::cerr << "FATAL ERROR: cannot generate a compatible matrix: " << error
769aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                          << std::endl;
77a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong            }
789aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            out() << "<!-- \n"
799aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    Autogenerated skeleton compatibility matrix. \n"
809aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    Use with caution. Modify it to suit your needs.\n"
819aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    All HALs are set to optional.\n"
829aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    Many entries other than HALs are zero-filled and\n"
839aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    require human attention. \n"
849aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "-->\n"
859aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                  << gCompatibilityMatrixConverter(generatedMatrix);
869aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        } else {
879aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            out() << gHalManifestConverter(*halManifest);
889aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
899aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        out().flush();
909aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
919aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        if (mCheckFile.is_open()) {
929aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            CompatibilityMatrix checkMatrix;
939aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!gCompatibilityMatrixConverter(&checkMatrix, read(mCheckFile))) {
949aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                std::cerr << "Cannot parse check file as a compatibility matrix: "
959aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                          << gCompatibilityMatrixConverter.lastError() << std::endl;
969aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
974650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong            }
989aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!halManifest->checkCompatibility(checkMatrix, &error)) {
999aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                std::cerr << "Not compatible: " << error << std::endl;
1009aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
1019aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            }
1029aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
1034650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
1049aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return true;
1059aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
1069aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
1079aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool assembleCompatibilityMatrix(CompatibilityMatrix* matrix) {
1089aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        std::string error;
1099aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
1109aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        KernelSepolicyVersion kernelSepolicyVers;
1119aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        Version sepolicyVers;
1129aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        if (matrix->mType == SchemaType::FRAMEWORK) {
1139aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!getFlag("BOARD_SEPOLICY_VERS", &sepolicyVers)) {
1149aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
1159aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            }
1169aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!getFlag("POLICYVERS", &kernelSepolicyVers)) {
1179aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
1189aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            }
1199aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            matrix->framework.mSepolicy =
1209aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                Sepolicy(kernelSepolicyVers, {{sepolicyVers.majorVer, sepolicyVers.minorVer}});
121a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong        }
1229aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        out() << gCompatibilityMatrixConverter(*matrix);
1239aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        out().flush();
124a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong
1259aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        if (mCheckFile.is_open()) {
1269aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            HalManifest checkManifest;
1279aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!gHalManifestConverter(&checkManifest, read(mCheckFile))) {
1289aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                std::cerr << "Cannot parse check file as a HAL manifest: "
1299aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                          << gHalManifestConverter.lastError() << std::endl;
1309aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
1311e5a054a0c3790364428dbfbe8625836a3087776Yifan Hong            }
1329aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!checkManifest.checkCompatibility(*matrix, &error)) {
1339aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                std::cerr << "Not compatible: " << error << std::endl;
1349aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
1359aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            }
1369aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
1379aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
1389aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return true;
1399aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
1409aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
141bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    enum AssembleStatus { SUCCESS, FAIL_AND_EXIT, TRY_NEXT };
142bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    template <typename Schema, typename AssembleFunc>
143bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    AssembleStatus tryAssemble(const XmlConverter<Schema>& converter, const std::string& schemaName,
144bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                               AssembleFunc assemble) {
145bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        Schema schema;
146bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (!converter(&schema, read(mInFiles.front()))) {
147bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            return TRY_NEXT;
148bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        }
149bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        auto firstType = schema.type();
150bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) {
151bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            Schema additionalSchema;
152bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            if (!converter(&additionalSchema, read(*it))) {
153bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                std::cerr << "File \"" << mInFilePaths[std::distance(mInFiles.begin(), it)]
154bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                          << "\" is not a valid " << firstType << " " << schemaName
155bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                          << " (but the first file is a valid " << firstType << " " << schemaName
156bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                          << "). Error: " << converter.lastError() << std::endl;
157bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                return FAIL_AND_EXIT;
158bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            }
159bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            if (additionalSchema.type() != firstType) {
160bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                std::cerr << "File \"" << mInFilePaths[std::distance(mInFiles.begin(), it)]
161bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                          << "\" is a " << additionalSchema.type() << " " << schemaName
162bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                          << " (but a " << firstType << " " << schemaName << " is expected)."
163bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                          << std::endl;
164bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                return FAIL_AND_EXIT;
165bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            }
166bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            schema.addAll(std::move(additionalSchema));
167bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        }
168bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        return assemble(&schema) ? SUCCESS : FAIL_AND_EXIT;
169bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    }
170bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong
1719aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool assemble() {
172bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        using std::placeholders::_1;
173bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (mInFiles.empty()) {
1749aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            std::cerr << "Missing input file." << std::endl;
1759aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            return false;
1769aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
1779aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
178bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        auto status = tryAssemble(gHalManifestConverter, "manifest",
179bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                                  std::bind(&AssembleVintf::assembleHalManifest, this, _1));
180bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (status == SUCCESS) return true;
181bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (status == FAIL_AND_EXIT) return false;
1829aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
183bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        resetInFiles();
1844650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
185bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        status = tryAssemble(gCompatibilityMatrixConverter, "compatibility matrix",
186bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                             std::bind(&AssembleVintf::assembleCompatibilityMatrix, this, _1));
187bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (status == SUCCESS) return true;
188bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (status == FAIL_AND_EXIT) return false;
1894d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
190959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong        std::cerr << "Input file has unknown format." << std::endl
191959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong                  << "Error when attempting to convert to manifest: "
192959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong                  << gHalManifestConverter.lastError() << std::endl
193959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong                  << "Error when attempting to convert to compatibility matrix: "
194959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong                  << gCompatibilityMatrixConverter.lastError() << std::endl;
195959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong        return false;
1964d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    }
1979aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
1989aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool openOutFile(const char* path) {
1999aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        mOutFileRef = std::make_unique<std::ofstream>();
2009aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        mOutFileRef->open(path);
2019aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return mOutFileRef->is_open();
2029aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
2039aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
2049aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool openInFile(const char* path) {
205bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        mInFilePaths.push_back(path);
206bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        mInFiles.push_back({});
207bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        mInFiles.back().open(path);
208bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        return mInFiles.back().is_open();
2099aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
2109aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
2119aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool openCheckFile(const char* path) {
2129aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        mCheckFile.open(path);
2139aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return mCheckFile.is_open();
2149aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
2159aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
216bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    void resetInFiles() {
217bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        for (auto& inFile : mInFiles) {
218bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            inFile.clear();
219bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            inFile.seekg(0);
220bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        }
221bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    }
222bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong
2239aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    void setOutputMatrix() { mOutputMatrix = true; }
2249aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
2259aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong   private:
226bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    std::vector<std::string> mInFilePaths;
227bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    std::vector<std::ifstream> mInFiles;
2289aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    std::unique_ptr<std::ofstream> mOutFileRef;
2299aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    std::ifstream mCheckFile;
2309aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool mOutputMatrix = false;
2314d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong};
2324d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
2334d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong}  // namespace vintf
2344d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong}  // namespace android
2354d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
2364d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongvoid help() {
2379aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    std::cerr << "assemble_vintf: Checks if a given manifest / matrix file is valid and \n"
2389aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "    fill in build-time flags into the given file.\n"
2399aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "assemble_vintf -h\n"
2409aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               Display this help text.\n"
241bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "assemble_vintf -i <input file>[:<input file>[...]] [-o <output file>] [-m]\n"
242bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               [-c [<check file>]]\n"
2439aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               Fill in build-time flags into the given file.\n"
244bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "    -i <input file>[:<input file>[...]]\n"
245bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               A list of input files. Format is automatically detected for the\n"
246bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               first file, and the remaining files must have the same format.\n"
247bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               Files other than the first file should only have <hal> defined;\n"
248bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               other entries are ignored.\n"
2499aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "    -o <output file>\n"
2509aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               Optional output file. If not specified, write to stdout.\n"
2519aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "    -m\n"
2529aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               a compatible compatibility matrix is\n"
2539aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               generated instead; for example, given a device manifest,\n"
2549aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               a framework compatibility matrix is generated. This flag\n"
2559aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               is ignored when input is a compatibility matrix.\n"
2569aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "    -c [<check file>]\n"
2579aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               After writing the output file, check compatibility between\n"
2589aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               output file and check file.\n"
2599aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               If -c is set but the check file is not specified, a warning\n"
2609aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               message is written to stderr. Return 0.\n"
2619aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               If the check file is specified but is not compatible, an error\n"
2629aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               message is written to stderr. Return 1.\n";
2634d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong}
2644d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
2654d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongint main(int argc, char **argv) {
2669aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    const struct option longopts[] = {{0, 0, 0, 0}};
2679aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
268bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    std::string outFilePath;
2699aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    ::android::vintf::AssembleVintf assembleVintf;
2704d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    int res;
2719aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    int optind;
2729aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    while ((res = getopt_long(argc, argv, "hi:o:mc:", longopts, &optind)) >= 0) {
2734d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        switch (res) {
2744d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            case 'i': {
275bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                char* inFilePath = strtok(optarg, ":");
276bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                while (inFilePath != NULL) {
277bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                    if (!assembleVintf.openInFile(inFilePath)) {
278bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                        std::cerr << "Failed to open " << optarg << std::endl;
279bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                        return 1;
280bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                    }
281bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                    inFilePath = strtok(NULL, ":");
2824d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                }
2834d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            } break;
2844d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
2854d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            case 'o': {
286bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                outFilePath = optarg;
2879aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                if (!assembleVintf.openOutFile(optarg)) {
2884d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                    std::cerr << "Failed to open " << optarg << std::endl;
2894d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                    return 1;
2904d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                }
2914d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            } break;
2924d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
293a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong            case 'm': {
2949aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                assembleVintf.setOutputMatrix();
295a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong            } break;
296a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong
2974650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong            case 'c': {
2984650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                if (strlen(optarg) != 0) {
2999aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                    if (!assembleVintf.openCheckFile(optarg)) {
3004650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                        std::cerr << "Failed to open " << optarg << std::endl;
3014650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                        return 1;
3024650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                    }
3034650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                } else {
3044650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                    std::cerr << "WARNING: no compatibility check is done on "
305bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                              << (outFilePath.empty() ? "output" : outFilePath) << std::endl;
3064650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                }
3074650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong            } break;
3084650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
3094d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            case 'h':
3104d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            default: {
3114d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                help();
3124d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                return 1;
3134d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            } break;
3144d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        }
3154d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    }
3164d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
3179aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool success = assembleVintf.assemble();
3184650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
3194650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong    return success ? 0 : 1;
3204d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong}
3214d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
322