• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <getopt.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 
21 #include <fstream>
22 #include <iostream>
23 #include <unordered_map>
24 #include <sstream>
25 #include <string>
26 
27 #include <vintf/parse_string.h>
28 #include <vintf/parse_xml.h>
29 
30 namespace android {
31 namespace vintf {
32 
33 /**
34  * Slurps the device manifest file and add build time flag to it.
35  */
36 class AssembleVintf {
37 public:
38     template<typename T>
getFlag(const std::string & key,T * value)39     static bool getFlag(const std::string& key, T* value) {
40         const char *envValue = getenv(key.c_str());
41         if (envValue == NULL) {
42             std::cerr << "Required " << key << " flag." << std::endl;
43             return false;
44         }
45 
46         if (!parse(envValue, value)) {
47             std::cerr << "Cannot parse " << envValue << "." << std::endl;
48             return false;
49         }
50         return true;
51     }
52 
read(std::basic_istream<char> & is)53     static std::string read(std::basic_istream<char>& is) {
54         std::stringstream ss;
55         ss << is.rdbuf();
56         return ss.str();
57     }
58 
out() const59     std::basic_ostream<char>& out() const {
60         return mOutFileRef == nullptr ? std::cout : *mOutFileRef;
61     }
62 
assembleHalManifest(HalManifest * halManifest)63     bool assembleHalManifest(HalManifest* halManifest) {
64         std::string error;
65 
66         if (halManifest->mType == SchemaType::DEVICE) {
67             if (!getFlag("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) {
68                 return false;
69             }
70         }
71 
72         if (mOutputMatrix) {
73             CompatibilityMatrix generatedMatrix = halManifest->generateCompatibleMatrix();
74             if (!halManifest->checkCompatibility(generatedMatrix, &error)) {
75                 std::cerr << "FATAL ERROR: cannot generate a compatible matrix: " << error
76                           << std::endl;
77             }
78             out() << "<!-- \n"
79                      "    Autogenerated skeleton compatibility matrix. \n"
80                      "    Use with caution. Modify it to suit your needs.\n"
81                      "    All HALs are set to optional.\n"
82                      "    Many entries other than HALs are zero-filled and\n"
83                      "    require human attention. \n"
84                      "-->\n"
85                   << gCompatibilityMatrixConverter(generatedMatrix);
86         } else {
87             out() << gHalManifestConverter(*halManifest);
88         }
89         out().flush();
90 
91         if (mCheckFile.is_open()) {
92             CompatibilityMatrix checkMatrix;
93             if (!gCompatibilityMatrixConverter(&checkMatrix, read(mCheckFile))) {
94                 std::cerr << "Cannot parse check file as a compatibility matrix: "
95                           << gCompatibilityMatrixConverter.lastError() << std::endl;
96                 return false;
97             }
98             if (!halManifest->checkCompatibility(checkMatrix, &error)) {
99                 std::cerr << "Not compatible: " << error << std::endl;
100                 return false;
101             }
102         }
103 
104         return true;
105     }
106 
assembleCompatibilityMatrix(CompatibilityMatrix * matrix)107     bool assembleCompatibilityMatrix(CompatibilityMatrix* matrix) {
108         std::string error;
109 
110         KernelSepolicyVersion kernelSepolicyVers;
111         Version sepolicyVers;
112         if (matrix->mType == SchemaType::FRAMEWORK) {
113             if (!getFlag("BOARD_SEPOLICY_VERS", &sepolicyVers)) {
114                 return false;
115             }
116             if (!getFlag("POLICYVERS", &kernelSepolicyVers)) {
117                 return false;
118             }
119             matrix->framework.mSepolicy =
120                 Sepolicy(kernelSepolicyVers, {{sepolicyVers.majorVer, sepolicyVers.minorVer}});
121         }
122         out() << gCompatibilityMatrixConverter(*matrix);
123         out().flush();
124 
125         if (mCheckFile.is_open()) {
126             HalManifest checkManifest;
127             if (!gHalManifestConverter(&checkManifest, read(mCheckFile))) {
128                 std::cerr << "Cannot parse check file as a HAL manifest: "
129                           << gHalManifestConverter.lastError() << std::endl;
130                 return false;
131             }
132             if (!checkManifest.checkCompatibility(*matrix, &error)) {
133                 std::cerr << "Not compatible: " << error << std::endl;
134                 return false;
135             }
136         }
137 
138         return true;
139     }
140 
assemble()141     bool assemble() {
142         if (!mInFile.is_open()) {
143             std::cerr << "Missing input file." << std::endl;
144             return false;
145         }
146 
147         std::string fileContent = read(mInFile);
148 
149         HalManifest halManifest;
150         if (gHalManifestConverter(&halManifest, fileContent)) {
151             if (assembleHalManifest(&halManifest)) {
152                 return true;
153             }
154         }
155 
156         CompatibilityMatrix matrix;
157         if (gCompatibilityMatrixConverter(&matrix, fileContent)) {
158             if (assembleCompatibilityMatrix(&matrix)) {
159                 return true;
160             }
161         }
162 
163         std::cerr << "Input file has unknown format." << std::endl
164                   << "Error when attempting to convert to manifest: "
165                   << gHalManifestConverter.lastError() << std::endl
166                   << "Error when attempting to convert to compatibility matrix: "
167                   << gCompatibilityMatrixConverter.lastError() << std::endl;
168         return false;
169     }
170 
openOutFile(const char * path)171     bool openOutFile(const char* path) {
172         mOutFileRef = std::make_unique<std::ofstream>();
173         mOutFileRef->open(path);
174         return mOutFileRef->is_open();
175     }
176 
openInFile(const char * path)177     bool openInFile(const char* path) {
178         mInFile.open(path);
179         return mInFile.is_open();
180     }
181 
openCheckFile(const char * path)182     bool openCheckFile(const char* path) {
183         mCheckFile.open(path);
184         return mCheckFile.is_open();
185     }
186 
setOutputMatrix()187     void setOutputMatrix() { mOutputMatrix = true; }
188 
189    private:
190     std::ifstream mInFile;
191     std::unique_ptr<std::ofstream> mOutFileRef;
192     std::ifstream mCheckFile;
193     bool mOutputMatrix = false;
194 };
195 
196 }  // namespace vintf
197 }  // namespace android
198 
help()199 void help() {
200     std::cerr << "assemble_vintf: Checks if a given manifest / matrix file is valid and \n"
201                  "    fill in build-time flags into the given file.\n"
202                  "assemble_vintf -h\n"
203                  "               Display this help text.\n"
204                  "assemble_vintf -i <input file> [-o <output file>] [-m] [-c [<check file>]]\n"
205                  "               [--kernel=<version>:<android-base.cfg>]\n"
206                  "               Fill in build-time flags into the given file.\n"
207                  "    -i <input file>\n"
208                  "               Input file. Format is automatically detected.\n"
209                  "    -o <output file>\n"
210                  "               Optional output file. If not specified, write to stdout.\n"
211                  "    -m\n"
212                  "               a compatible compatibility matrix is\n"
213                  "               generated instead; for example, given a device manifest,\n"
214                  "               a framework compatibility matrix is generated. This flag\n"
215                  "               is ignored when input is a compatibility matrix.\n"
216                  "    -c [<check file>]\n"
217                  "               After writing the output file, check compatibility between\n"
218                  "               output file and check file.\n"
219                  "               If -c is set but the check file is not specified, a warning\n"
220                  "               message is written to stderr. Return 0.\n"
221                  "               If the check file is specified but is not compatible, an error\n"
222                  "               message is written to stderr. Return 1.\n";
223 }
224 
main(int argc,char ** argv)225 int main(int argc, char **argv) {
226     const struct option longopts[] = {{0, 0, 0, 0}};
227 
228     std::string inFilePath;
229     ::android::vintf::AssembleVintf assembleVintf;
230     int res;
231     int optind;
232     while ((res = getopt_long(argc, argv, "hi:o:mc:", longopts, &optind)) >= 0) {
233         switch (res) {
234             case 'i': {
235                 inFilePath = optarg;
236                 if (!assembleVintf.openInFile(optarg)) {
237                     std::cerr << "Failed to open " << optarg << std::endl;
238                     return 1;
239                 }
240             } break;
241 
242             case 'o': {
243                 if (!assembleVintf.openOutFile(optarg)) {
244                     std::cerr << "Failed to open " << optarg << std::endl;
245                     return 1;
246                 }
247             } break;
248 
249             case 'm': {
250                 assembleVintf.setOutputMatrix();
251             } break;
252 
253             case 'c': {
254                 if (strlen(optarg) != 0) {
255                     if (!assembleVintf.openCheckFile(optarg)) {
256                         std::cerr << "Failed to open " << optarg << std::endl;
257                         return 1;
258                     }
259                 } else {
260                     std::cerr << "WARNING: no compatibility check is done on "
261                               << inFilePath << std::endl;
262                 }
263             } break;
264 
265             case 'h':
266             default: {
267                 help();
268                 return 1;
269             } break;
270         }
271     }
272 
273     bool success = assembleVintf.assemble();
274 
275     return success ? 0 : 1;
276 }
277 
278