AssembleVintf.cpp revision a59d2567783cad6f675d2fc1f2fcce4bce3e34e3
1/*
2 * Copyright (C) 2017 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
17#include <stdlib.h>
18#include <unistd.h>
19
20#include <fstream>
21#include <iostream>
22#include <unordered_map>
23#include <sstream>
24#include <string>
25
26#include <vintf/parse_string.h>
27#include <vintf/parse_xml.h>
28
29namespace android {
30namespace vintf {
31
32/**
33 * Slurps the device manifest file and add build time flag to it.
34 */
35class AssembleVintf {
36public:
37    template<typename T>
38    static bool getFlag(const std::string& key, T* value) {
39        const char *envValue = getenv(key.c_str());
40        if (envValue == NULL) {
41            std::cerr << "Required " << key << " flag." << std::endl;
42            return false;
43        }
44
45        if (!parse(envValue, value)) {
46            std::cerr << "Cannot parse " << envValue << "." << std::endl;
47            return false;
48        }
49        return true;
50    }
51
52    static bool assemble(std::basic_istream<char>& inFile,
53                         std::basic_ostream<char>& outFile,
54                         bool isMatrix) {
55        std::stringstream ss;
56        ss << inFile.rdbuf();
57        std::string fileContent = ss.str();
58
59        HalManifest halManifest;
60        if (!gHalManifestConverter(&halManifest, fileContent)) {
61            std::cerr << "Illformed HAL manifest: " << gHalManifestConverter.lastError()
62                    << std::endl;
63            return false;
64        }
65
66        if (halManifest.mType == SchemaType::DEVICE) {
67            if (!getFlag("BOARD_SEPOLICY_VERS", &halManifest.device.mSepolicyVersion)) {
68                return false;
69            }
70        }
71
72        if (isMatrix) {
73            CompatibilityMatrix mat = halManifest.generateCompatibleMatrix();
74            std::string error;
75            if (!halManifest.checkCompatibility(mat, &error)) {
76                std::cerr << "FATAL ERROR: cannot generate a compatible matrix: "
77                          << error << std::endl;
78            }
79            outFile << "<!-- \n"
80                       "    Autogenerated skeleton compatibility matrix. \n"
81                       "    Use with caution. Modify it to suit your needs.\n"
82                       "    All HALs are set to optional.\n"
83                       "    Many entries other than HALs are zero-filled and\n"
84                       "    require human attention. \n"
85                       "-->\n"
86                    << gCompatibilityMatrixConverter(mat);
87        } else {
88            outFile << gHalManifestConverter(halManifest);
89        }
90
91        outFile.flush();
92
93        return true;
94    }
95};
96
97}  // namespace vintf
98}  // namespace android
99
100void help() {
101    std::cerr <<
102        "assemble_vintf -h\n"
103        "               Display this help text.\n"
104        "assemble_vintf -i <input file> [-o <output file>] [-m]\n"
105        "               Fill in build-time flags into the given manifest.\n"
106        "               If no designated output file, write to stdout.\n"
107        "               If -m is set, a compatible compatibility matrix is\n"
108        "               generated instead.\n";
109}
110
111int main(int argc, char **argv) {
112    std::ifstream inFile;
113    std::ofstream outFile;
114    std::ostream* outFileRef = &std::cout;
115    bool isMatrix = false;
116    int res;
117    while((res = getopt(argc, argv, "hi:o:m")) >= 0) {
118        switch (res) {
119            case 'i': {
120                inFile.open(optarg);
121                if (!inFile.is_open()) {
122                    std::cerr << "Failed to open " << optarg << std::endl;
123                    return 1;
124                }
125            } break;
126
127            case 'o': {
128                outFile.open(optarg);
129                if (!outFile.is_open()) {
130                    std::cerr << "Failed to open " << optarg << std::endl;
131                    return 1;
132                }
133                outFileRef = &outFile;
134            } break;
135
136            case 'm': {
137                isMatrix = true;
138            } break;
139
140            case 'h':
141            default: {
142                help();
143                return 1;
144            } break;
145        }
146    }
147
148    if (!inFile.is_open()) {
149        std::cerr << "Missing input file" << std::endl;
150        help();
151        return 1;
152    }
153
154    return ::android::vintf::AssembleVintf::assemble(inFile, *outFileRef, isMatrix)
155            ? 0 : 1;
156}
157
158