blob: 3364bf45a9b076a614ce2e557ea86d83fabc5d64 [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
2 * Copyright (C) 2016 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
Andreas Huberc9410c72016-07-28 12:18:40 -070017#include "AST.h"
Andreas Huber5345ec22016-07-29 13:33:27 -070018#include "Coordinator.h"
Andreas Huber0fa9e392016-08-31 09:05:44 -070019#include "Scope.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070020
Andreas Huber308d8a22017-11-06 14:46:52 -080021#include <android-base/logging.h>
Steven Moreland5bdfa702017-04-18 23:20:39 -070022#include <hidl-hash/Hash.h>
Steven Moreland7ae3d542017-01-18 16:46:01 -080023#include <hidl-util/FQName.h>
Steven Morelanda8153982017-11-28 15:22:28 -080024#include <hidl-util/Formatter.h>
Steven Morelandd177b122016-12-12 09:15:37 -080025#include <hidl-util/StringHelper.h>
Steven Morelanda8153982017-11-28 15:22:28 -080026#include <stdio.h>
27#include <sys/stat.h>
28#include <unistd.h>
Andreas Huber308d8a22017-11-06 14:46:52 -080029#include <iostream>
Iliyan Malchev5bb14022016-08-09 15:04:39 -070030#include <set>
Andreas Huberdca261f2016-08-04 13:47:51 -070031#include <string>
Andreas Huberdca261f2016-08-04 13:47:51 -070032#include <vector>
Andreas Huberc9410c72016-07-28 12:18:40 -070033
34using namespace android;
35
Steven Moreland5abcf012018-02-08 18:50:18 -080036enum class OutputMode {
37 NEEDS_DIR, // -o output option expects a directory
38 NEEDS_FILE, // -o output option expects a file
39 NEEDS_SRC, // for changes inside the source tree itself
40 NOT_NEEDED // does not create files
Iliyan Malchev5bb14022016-08-09 15:04:39 -070041};
Andreas Huberdca261f2016-08-04 13:47:51 -070042
Steven Moreland5abcf012018-02-08 18:50:18 -080043enum class GenerationGranularity {
44 PER_PACKAGE, // Files generated for each package
45 PER_FILE, // Files generated for each hal file
46 PER_TYPE, // Files generated for each hal file + each type in HAL files
47};
Iliyan Malchev5bb14022016-08-09 15:04:39 -070048
Steven Moreland5abcf012018-02-08 18:50:18 -080049// Represents a file that is generated by an -L option for an FQName
50struct FileGenerator {
51 using ShouldGenerateFunction = std::function<bool(const FQName& fqName)>;
52 using FileNameForFQName = std::function<std::string(const FQName& fqName)>;
53 using GenerationFunction = std::function<status_t(Formatter& out, const FQName& fqName,
54 const Coordinator* coordinator)>;
55
56 ShouldGenerateFunction mShouldGenerateForFqName; // If generate function applies to this target
57 FileNameForFQName mFileNameForFqName; // Target -> filename
58 GenerationFunction mGenerationFunction; // Function to generate output for file
59
Steven Moreland394af5c2018-02-09 14:41:46 -080060 std::string getFileName(const FQName& fqName) const {
61 return mFileNameForFqName ? mFileNameForFqName(fqName) : "";
62 }
63
Steven Moreland255c9a12018-02-26 13:10:27 -080064 status_t getOutputFile(const FQName& fqName, const Coordinator* coordinator,
65 Coordinator::Location location, std::string* file) const {
Steven Moreland394af5c2018-02-09 14:41:46 -080066 if (!mShouldGenerateForFqName(fqName)) {
Steven Moreland255c9a12018-02-26 13:10:27 -080067 return OK;
Steven Moreland394af5c2018-02-09 14:41:46 -080068 }
69
Steven Moreland255c9a12018-02-26 13:10:27 -080070 return coordinator->getFilepath(fqName, location, getFileName(fqName), file);
Steven Moreland394af5c2018-02-09 14:41:46 -080071 }
72
Steven Moreland255c9a12018-02-26 13:10:27 -080073 status_t appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
74 Coordinator::Location location,
75 std::vector<std::string>* outputFiles) const {
Steven Moreland394af5c2018-02-09 14:41:46 -080076 if (location == Coordinator::Location::STANDARD_OUT) {
Steven Moreland255c9a12018-02-26 13:10:27 -080077 return OK;
Steven Moreland394af5c2018-02-09 14:41:46 -080078 }
79
80 if (mShouldGenerateForFqName(fqName)) {
Steven Moreland255c9a12018-02-26 13:10:27 -080081 std::string fileName;
82 status_t err = getOutputFile(fqName, coordinator, location, &fileName);
83 if (err != OK) return err;
Steven Moreland394af5c2018-02-09 14:41:46 -080084
85 if (!fileName.empty()) {
86 outputFiles->push_back(fileName);
87 }
88 }
Steven Moreland255c9a12018-02-26 13:10:27 -080089 return OK;
Steven Moreland394af5c2018-02-09 14:41:46 -080090 }
91
Steven Moreland5abcf012018-02-08 18:50:18 -080092 status_t generate(const FQName& fqName, const Coordinator* coordinator,
93 Coordinator::Location location) const {
94 CHECK(mShouldGenerateForFqName != nullptr);
95 CHECK(mGenerationFunction != nullptr);
96
97 if (!mShouldGenerateForFqName(fqName)) {
98 return OK;
99 }
100
Steven Moreland394af5c2018-02-09 14:41:46 -0800101 Formatter out = coordinator->getFormatter(fqName, location, getFileName(fqName));
Steven Moreland255c9a12018-02-26 13:10:27 -0800102 if (!out.isValid()) {
103 return UNKNOWN_ERROR;
104 }
105
Steven Moreland5abcf012018-02-08 18:50:18 -0800106 return mGenerationFunction(out, fqName, coordinator);
107 }
108
109 // Helper methods for filling out this struct
110 static bool generateForTypes(const FQName& fqName) {
111 const auto names = fqName.names();
112 return names.size() > 0 && names[0] == "types";
113 }
114 static bool generateForInterfaces(const FQName& fqName) { return !generateForTypes(fqName); }
115 static bool alwaysGenerate(const FQName&) { return true; }
116};
117
118// Represents a -L option, takes a fqName and generates files
119struct OutputHandler {
Steven Moreland6ec9eb92018-02-16 14:21:49 -0800120 using ValidationFunction = std::function<bool(
121 const FQName& fqName, const Coordinator* coordinator, const std::string& language)>;
Steven Moreland5abcf012018-02-08 18:50:18 -0800122
123 std::string mKey; // -L in Android.bp
124 std::string mDescription; // for display in help menu
125 OutputMode mOutputMode; // how this option interacts with -o
126 Coordinator::Location mLocation; // how to compute location relative to the output directory
Steven Moreland394af5c2018-02-09 14:41:46 -0800127 GenerationGranularity mGenerationGranularity; // what to run generate function on
Steven Moreland5abcf012018-02-08 18:50:18 -0800128 ValidationFunction mValidate; // if a given fqName is allowed for this option
129 std::vector<FileGenerator> mGenerateFunctions; // run for each target at this granularity
130
131 const std::string& name() const { return mKey; }
132 const std::string& description() const { return mDescription; }
133
134 status_t generate(const FQName& fqName, const Coordinator* coordinator) const;
Steven Moreland6ec9eb92018-02-16 14:21:49 -0800135 status_t validate(const FQName& fqName, const Coordinator* coordinator,
136 const std::string& language) const {
137 return mValidate(fqName, coordinator, language);
Steven Moreland5abcf012018-02-08 18:50:18 -0800138 }
Steven Moreland394af5c2018-02-09 14:41:46 -0800139
140 status_t writeDepFile(const FQName& fqName, const Coordinator* coordinator) const;
141
142 private:
143 status_t appendTargets(const FQName& fqName, const Coordinator* coordinator,
144 std::vector<FQName>* targets) const;
145 status_t appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
146 std::vector<std::string>* outputFiles) const;
Steven Moreland5abcf012018-02-08 18:50:18 -0800147};
148
149// Helper method for GenerationGranularity::PER_TYPE
150// IFoo -> IFoo, types.hal (containing Bar, Baz) -> types.Bar, types.Baz
151static status_t appendPerTypeTargets(const FQName& fqName, const Coordinator* coordinator,
152 std::vector<FQName>* exportedPackageInterfaces) {
153 CHECK(fqName.isFullyQualified());
154 if (fqName.name() != "types") {
155 exportedPackageInterfaces->push_back(fqName);
156 return OK;
157 }
158
159 AST* typesAST = coordinator->parse(fqName);
160 if (typesAST == nullptr) {
161 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
162 return UNKNOWN_ERROR;
163 }
164
165 std::vector<NamedType*> rootTypes = typesAST->getRootScope()->getSubTypes();
166 for (const NamedType* rootType : rootTypes) {
167 if (rootType->isTypeDef()) continue;
168
169 FQName rootTypeName(fqName.package(), fqName.version(), "types." + rootType->localName());
170 exportedPackageInterfaces->push_back(rootTypeName);
171 }
172 return OK;
173}
174
Steven Moreland394af5c2018-02-09 14:41:46 -0800175status_t OutputHandler::appendTargets(const FQName& fqName, const Coordinator* coordinator,
176 std::vector<FQName>* targets) const {
Steven Moreland5abcf012018-02-08 18:50:18 -0800177 switch (mGenerationGranularity) {
178 case GenerationGranularity::PER_PACKAGE: {
Steven Moreland394af5c2018-02-09 14:41:46 -0800179 targets->push_back(fqName.getPackageAndVersion());
Steven Moreland5abcf012018-02-08 18:50:18 -0800180 } break;
181 case GenerationGranularity::PER_FILE: {
182 if (fqName.isFullyQualified()) {
Steven Moreland394af5c2018-02-09 14:41:46 -0800183 targets->push_back(fqName);
Steven Moreland5abcf012018-02-08 18:50:18 -0800184 break;
185 }
Steven Moreland394af5c2018-02-09 14:41:46 -0800186 status_t err = coordinator->appendPackageInterfacesToVector(fqName, targets);
Steven Moreland5abcf012018-02-08 18:50:18 -0800187 if (err != OK) return err;
188 } break;
189 case GenerationGranularity::PER_TYPE: {
190 if (fqName.isFullyQualified()) {
Steven Moreland394af5c2018-02-09 14:41:46 -0800191 status_t err = appendPerTypeTargets(fqName, coordinator, targets);
Steven Moreland5abcf012018-02-08 18:50:18 -0800192 if (err != OK) return err;
193 }
194
195 std::vector<FQName> packageInterfaces;
196 status_t err = coordinator->appendPackageInterfacesToVector(fqName, &packageInterfaces);
197 if (err != OK) return err;
198 for (const FQName& packageInterface : packageInterfaces) {
Steven Moreland394af5c2018-02-09 14:41:46 -0800199 err = appendPerTypeTargets(packageInterface, coordinator, targets);
Steven Moreland5abcf012018-02-08 18:50:18 -0800200 if (err != OK) return err;
201 }
202 } break;
203 default:
204 CHECK(!"Should be here");
205 }
206
Steven Moreland394af5c2018-02-09 14:41:46 -0800207 return OK;
208}
209
210status_t OutputHandler::generate(const FQName& fqName, const Coordinator* coordinator) const {
211 std::vector<FQName> targets;
212 status_t err = appendTargets(fqName, coordinator, &targets);
213 if (err != OK) return err;
214
Steven Moreland5abcf012018-02-08 18:50:18 -0800215 for (const FQName& fqName : targets) {
216 for (const FileGenerator& file : mGenerateFunctions) {
217 status_t err = file.generate(fqName, coordinator, mLocation);
218 if (err != OK) return err;
219 }
220 }
221
222 return OK;
223}
224
Steven Moreland394af5c2018-02-09 14:41:46 -0800225status_t OutputHandler::appendOutputFiles(const FQName& fqName, const Coordinator* coordinator,
226 std::vector<std::string>* outputFiles) const {
227 std::vector<FQName> targets;
228 status_t err = appendTargets(fqName, coordinator, &targets);
229 if (err != OK) return err;
230
231 for (const FQName& fqName : targets) {
232 for (const FileGenerator& file : mGenerateFunctions) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800233 err = file.appendOutputFiles(fqName, coordinator, mLocation, outputFiles);
234 if (err != OK) return err;
Steven Moreland394af5c2018-02-09 14:41:46 -0800235 }
236 }
237
238 return OK;
239}
240
241status_t OutputHandler::writeDepFile(const FQName& fqName, const Coordinator* coordinator) const {
242 std::vector<std::string> outputFiles;
243 status_t err = appendOutputFiles(fqName, coordinator, &outputFiles);
244 if (err != OK) return err;
245
246 // No need for dep files
247 if (outputFiles.empty()) {
248 return OK;
249 }
250
251 // Depfiles in Android for genrules should be for the 'main file'. Because hidl-gen doesn't have
252 // a main file for most targets, we are just outputting a depfile for one single file only.
253 const std::string forFile = outputFiles[0];
254
255 return coordinator->writeDepFile(forFile);
256}
257
Steven Moreland5abcf012018-02-08 18:50:18 -0800258// Use an AST function as a OutputHandler GenerationFunction
Steven Moreland6ec9eb92018-02-16 14:21:49 -0800259static FileGenerator::GenerationFunction astGenerationFunction(void (AST::*generate)(Formatter&)
Steven Moreland5abcf012018-02-08 18:50:18 -0800260 const = nullptr) {
261 return [generate](Formatter& out, const FQName& fqName,
262 const Coordinator* coordinator) -> status_t {
263 AST* ast = coordinator->parse(fqName);
264 if (ast == nullptr) {
265 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
266 return UNKNOWN_ERROR;
267 }
268
269 if (generate == nullptr) return OK; // just parsing AST
Steven Moreland6ec9eb92018-02-16 14:21:49 -0800270 (ast->*generate)(out);
271
272 return OK;
Steven Moreland5abcf012018-02-08 18:50:18 -0800273 };
274}
275
276// Common pattern: single file for package or standard out
277static FileGenerator singleFileGenerator(
278 const std::string& fileName, const FileGenerator::GenerationFunction& generationFunction) {
279 return {
280 FileGenerator::alwaysGenerate, [fileName](const FQName&) { return fileName; },
281 generationFunction,
282 };
283}
284
285static status_t generateJavaForPackage(Formatter& out, const FQName& fqName,
286 const Coordinator* coordinator) {
287 AST* ast;
Andreas Huberd29724f2016-09-14 09:33:13 -0700288 std::string limitToType;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700289
Steven Moreland5abcf012018-02-08 18:50:18 -0800290 // Required for legacy -Lmakefile files
Andreas Huber0fa9e392016-08-31 09:05:44 -0700291 if (fqName.name().find("types.") == 0) {
Andreas Huberd29724f2016-09-14 09:33:13 -0700292 limitToType = fqName.name().substr(strlen("types."));
Andreas Huber0fa9e392016-08-31 09:05:44 -0700293
Yifan Hongfece6ec2017-01-12 17:04:04 -0800294 FQName typesName = fqName.getTypesForPackage();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700295 ast = coordinator->parse(typesName);
296 } else {
297 ast = coordinator->parse(fqName);
298 }
Steven Moreland5abcf012018-02-08 18:50:18 -0800299 if (ast == nullptr) {
300 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700301 return UNKNOWN_ERROR;
302 }
Steven Moreland6ec9eb92018-02-16 14:21:49 -0800303 ast->generateJava(out, limitToType);
304 return OK;
Steven Moreland5abcf012018-02-08 18:50:18 -0800305};
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700306
Steven Morelandb65e5d92018-02-08 12:44:51 -0800307static status_t dumpDefinedButUnreferencedTypeNames(const FQName& packageFQName,
308 const Coordinator* coordinator) {
309 std::vector<FQName> packageInterfaces;
310 status_t err = coordinator->appendPackageInterfacesToVector(packageFQName, &packageInterfaces);
311 if (err != OK) return err;
312
Steven Moreland40b86352018-02-01 16:03:30 -0800313 std::set<FQName> unreferencedDefinitions;
314 std::set<FQName> unreferencedImports;
Steven Morelandb65e5d92018-02-08 12:44:51 -0800315 err = coordinator->addUnreferencedTypes(packageInterfaces, &unreferencedDefinitions,
316 &unreferencedImports);
317 if (err != OK) return err;
Andreas Huber308d8a22017-11-06 14:46:52 -0800318
Steven Moreland40b86352018-02-01 16:03:30 -0800319 for (const auto& fqName : unreferencedDefinitions) {
Andreas Huber308d8a22017-11-06 14:46:52 -0800320 std::cerr
321 << "VERBOSE: DEFINED-BUT-NOT-REFERENCED "
322 << fqName.string()
323 << std::endl;
324 }
325
Steven Moreland40b86352018-02-01 16:03:30 -0800326 for (const auto& fqName : unreferencedImports) {
Andreas Huber4f4b3822017-11-15 13:18:50 -0800327 std::cerr
328 << "VERBOSE: IMPORTED-BUT-NOT-REFERENCED "
329 << fqName.string()
330 << std::endl;
331 }
332
Andreas Huber308d8a22017-11-06 14:46:52 -0800333 return OK;
334}
335
Andreas Huberd2943e12016-08-05 11:59:31 -0700336static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700337 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700338}
Steven Moreland5715fed2017-01-16 11:06:47 -0800339
Steven Morelande6d7f092018-02-08 13:25:45 -0800340static status_t isPackageJavaCompatible(const FQName& packageFQName, const Coordinator* coordinator,
341 bool* compatible) {
Andreas Huber75ae95d2016-10-12 16:08:26 -0700342 std::vector<FQName> todo;
343 status_t err =
344 coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
345
346 if (err != OK) {
347 return err;
348 }
349
350 std::set<FQName> seen;
351 for (const auto &iface : todo) {
352 seen.insert(iface);
353 }
354
355 // Form the transitive closure of all imported interfaces (and types.hal-s)
356 // If any one of them is not java compatible, this package isn't either.
357 while (!todo.empty()) {
358 const FQName fqName = todo.back();
359 todo.pop_back();
360
361 AST *ast = coordinator->parse(fqName);
362
363 if (ast == nullptr) {
364 return UNKNOWN_ERROR;
365 }
366
367 if (!ast->isJavaCompatible()) {
368 *compatible = false;
369 return OK;
370 }
371
372 std::set<FQName> importedPackages;
373 ast->getImportedPackages(&importedPackages);
374
375 for (const auto &package : importedPackages) {
376 std::vector<FQName> packageInterfaces;
377 status_t err = coordinator->appendPackageInterfacesToVector(
378 package, &packageInterfaces);
379
380 if (err != OK) {
381 return err;
382 }
383
384 for (const auto &iface : packageInterfaces) {
385 if (seen.find(iface) != seen.end()) {
386 continue;
387 }
388
389 todo.push_back(iface);
390 seen.insert(iface);
391 }
392 }
393 }
394
395 *compatible = true;
396 return OK;
397}
398
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700399static bool packageNeedsJavaCode(
400 const std::vector<FQName> &packageInterfaces, AST *typesAST) {
Steven Morelandadc25022017-10-11 12:42:19 -0700401 if (packageInterfaces.size() == 0) {
402 return false;
403 }
404
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700405 // If there is more than just a types.hal file to this package we'll
406 // definitely need to generate Java code.
407 if (packageInterfaces.size() > 1
408 || packageInterfaces[0].name() != "types") {
409 return true;
410 }
411
412 CHECK(typesAST != nullptr);
413
414 // We'll have to generate Java code if types.hal contains any non-typedef
415 // type declarations.
416
Timur Iskhakovcb0ba522017-07-17 20:01:37 -0700417 Scope* rootScope = typesAST->getRootScope();
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700418 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
419
420 for (const auto &subType : subTypes) {
421 if (!subType->isTypeDef()) {
422 return true;
423 }
424 }
425
426 return false;
427}
428
Steven Moreland6ec9eb92018-02-16 14:21:49 -0800429bool validateIsPackage(const FQName& fqName, const Coordinator*,
430 const std::string& /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700431 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700432 fprintf(stderr, "ERROR: Expecting package name\n");
Steven Moreland05951b32017-05-12 17:22:22 -0700433 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700434 }
435
436 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700437 fprintf(stderr, "ERROR: Expecting package version\n");
Steven Moreland05951b32017-05-12 17:22:22 -0700438 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700439 }
440
441 if (!fqName.name().empty()) {
442 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700443 "ERROR: Expecting only package name and version.\n");
Steven Moreland05951b32017-05-12 17:22:22 -0700444 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700445 }
446
Steven Moreland05951b32017-05-12 17:22:22 -0700447 return true;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700448}
449
Steven Morelandf7f2a9a2017-07-21 18:05:38 -0700450bool isHidlTransportPackage(const FQName& fqName) {
Steven Morelande1b157e2018-03-06 14:18:32 -0800451 return fqName.package() == gIBaseFqName.package() ||
452 fqName.package() == gIManagerFqName.package();
Steven Moreland77cf7642017-06-15 14:49:39 -0700453}
454
Steven Morelandc7946c92017-08-08 14:48:32 -0700455bool isSystemProcessSupportedPackage(const FQName& fqName) {
456 // Technically, so is hidl IBase + IServiceManager, but
457 // these are part of libhidltransport.
Jiyong Park45ec8d12017-11-21 10:39:22 +0900458 return fqName.string() == "android.hardware.graphics.common@1.0" ||
Steven Moreland40f11352018-01-23 11:30:43 -0800459 fqName.string() == "android.hardware.graphics.common@1.1" ||
Steven Morelandc7946c92017-08-08 14:48:32 -0700460 fqName.string() == "android.hardware.graphics.mapper@2.0" ||
Chia-I Wu620cc392017-09-28 15:33:21 -0700461 fqName.string() == "android.hardware.graphics.mapper@2.1" ||
Steven Morelandc7946c92017-08-08 14:48:32 -0700462 fqName.string() == "android.hardware.renderscript@1.0" ||
Howard Chen01dfc6d2017-11-30 15:37:12 +0800463 fqName.string() == "android.hidl.memory.token@1.0" ||
Steven Morelandc7946c92017-08-08 14:48:32 -0700464 fqName.string() == "android.hidl.memory@1.0";
465}
466
Steven Moreland5edf5282017-07-20 12:56:58 -0700467bool isSystemPackage(const FQName &package) {
468 return package.inPackage("android.hidl") ||
469 package.inPackage("android.system") ||
470 package.inPackage("android.frameworks") ||
471 package.inPackage("android.hardware");
472}
473
Steven Morelanda8153982017-11-28 15:22:28 -0800474// TODO(b/69862859): remove special case
Steven Moreland255c9a12018-02-26 13:10:27 -0800475status_t isTestPackage(const FQName& fqName, const Coordinator* coordinator, bool* isTestPackage) {
Steven Morelanda8153982017-11-28 15:22:28 -0800476 const auto fileExists = [](const std::string& file) {
477 struct stat buf;
478 return stat(file.c_str(), &buf) == 0;
479 };
480
Steven Moreland255c9a12018-02-26 13:10:27 -0800481 std::string path;
482 status_t err = coordinator->getFilepath(fqName, Coordinator::Location::PACKAGE_ROOT,
483 ".hidl_for_test", &path);
484 if (err != OK) return err;
485
Steven Morelanda8153982017-11-28 15:22:28 -0800486 const bool exists = fileExists(path);
487
488 if (exists) {
489 coordinator->onFileAccess(path, "r");
490 }
491
Steven Moreland255c9a12018-02-26 13:10:27 -0800492 *isTestPackage = exists;
493 return OK;
Steven Morelanda8153982017-11-28 15:22:28 -0800494}
495
Steven Moreland5abcf012018-02-08 18:50:18 -0800496static status_t generateAdapterMainSource(Formatter& out, const FQName& packageFQName,
Steven Morelande6d7f092018-02-08 13:25:45 -0800497 const Coordinator* coordinator) {
Steven Moreland9a6da7a2017-09-15 16:21:24 -0700498 std::vector<FQName> packageInterfaces;
499 status_t err =
500 coordinator->appendPackageInterfacesToVector(packageFQName,
501 &packageInterfaces);
502 if (err != OK) {
503 return err;
504 }
505
506 out << "#include <hidladapter/HidlBinderAdapter.h>\n";
507
508 for (auto &interface : packageInterfaces) {
509 if (interface.name() == "types") {
510 continue;
511 }
512 AST::generateCppPackageInclude(out, interface, interface.getInterfaceAdapterName());
513 }
514
515 out << "int main(int argc, char** argv) ";
516 out.block([&] {
517 out << "return ::android::hardware::adapterMain<\n";
518 out.indent();
519 for (auto &interface : packageInterfaces) {
520 if (interface.name() == "types") {
521 continue;
522 }
523 out << interface.getInterfaceAdapterFqName().cppName();
524
525 if (&interface != &packageInterfaces.back()) {
526 out << ",\n";
527 }
528 }
529 out << ">(\"" << packageFQName.string() << "\", argc, argv);\n";
530 out.unindent();
531 }).endl();
532 return OK;
533}
534
Steven Moreland5abcf012018-02-08 18:50:18 -0800535static status_t generateAndroidBpForPackage(Formatter& out, const FQName& packageFQName,
Steven Morelande6d7f092018-02-08 13:25:45 -0800536 const Coordinator* coordinator) {
Steven Moreland77730892018-03-06 14:39:41 -0800537 CHECK(!packageFQName.isFullyQualified() && packageFQName.name().empty());
Steven Moreland40069d52017-10-03 09:36:51 -0700538
539 std::vector<FQName> packageInterfaces;
540
541 status_t err = coordinator->appendPackageInterfacesToVector(packageFQName, &packageInterfaces);
542
543 if (err != OK) {
544 return err;
545 }
546
547 std::set<FQName> importedPackagesHierarchy;
Steven Moreland887b84c2017-10-09 18:40:58 -0700548 std::vector<const Type *> exportedTypes;
Steven Moreland40069d52017-10-03 09:36:51 -0700549 AST* typesAST = nullptr;
550
551 for (const auto& fqName : packageInterfaces) {
552 AST* ast = coordinator->parse(fqName);
553
554 if (ast == NULL) {
555 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
556
557 return UNKNOWN_ERROR;
558 }
559
560 if (fqName.name() == "types") {
561 typesAST = ast;
562 }
563
564 ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
Steven Moreland887b84c2017-10-09 18:40:58 -0700565 ast->appendToExportedTypesVector(&exportedTypes);
Steven Moreland40069d52017-10-03 09:36:51 -0700566 }
567
Steven Moreland313a0132017-11-03 14:23:14 -0700568 bool needsJavaCode = packageNeedsJavaCode(packageInterfaces, typesAST);
569
570 bool genJavaConstants = needsJavaCode && !exportedTypes.empty();
Steven Moreland887b84c2017-10-09 18:40:58 -0700571
572 bool isJavaCompatible;
573 err = isPackageJavaCompatible(packageFQName, coordinator, &isJavaCompatible);
574 if (err != OK) return err;
Steven Moreland313a0132017-11-03 14:23:14 -0700575 bool genJavaLibrary = needsJavaCode && isJavaCompatible;
576
Steven Moreland255c9a12018-02-26 13:10:27 -0800577 bool generateForTest;
578 err = isTestPackage(packageFQName, coordinator, &generateForTest);
579 if (err != OK) return err;
580
Steven Moreland313a0132017-11-03 14:23:14 -0700581 bool isVndk = !generateForTest && isSystemPackage(packageFQName);
582 bool isVndkSp = isVndk && isSystemProcessSupportedPackage(packageFQName);
Steven Moreland887b84c2017-10-09 18:40:58 -0700583
Steven Moreland255c9a12018-02-26 13:10:27 -0800584 std::string packageRoot;
585 err = coordinator->getPackageRoot(packageFQName, &packageRoot);
586 if (err != OK) return err;
587
Steven Moreland313a0132017-11-03 14:23:14 -0700588 out << "// This file is autogenerated by hidl-gen -Landroidbp.\n\n";
Steven Moreland40069d52017-10-03 09:36:51 -0700589
Steven Moreland313a0132017-11-03 14:23:14 -0700590 out << "hidl_interface ";
Steven Moreland40069d52017-10-03 09:36:51 -0700591 out.block([&] {
Steven Moreland313a0132017-11-03 14:23:14 -0700592 out << "name: \"" << makeLibraryName(packageFQName) << "\",\n";
Steven Moreland89a9ebb2017-12-04 10:18:00 -0800593 if (!coordinator->getOwner().empty()) {
594 out << "owner: \"" << coordinator->getOwner() << "\",\n";
595 }
Steven Moreland255c9a12018-02-26 13:10:27 -0800596 out << "root: \"" << packageRoot << "\",\n";
Steven Moreland313a0132017-11-03 14:23:14 -0700597 if (isHidlTransportPackage(packageFQName)) {
598 out << "core_interface: true,\n";
599 }
600 if (isVndk) {
601 out << "vndk: ";
602 out.block([&]() {
603 out << "enabled: true,\n";
604 if (isVndkSp) {
605 out << "support_system_process: true,\n";
606 }
607 }) << ",\n";
608 }
609 (out << "srcs: [\n").indent([&] {
Steven Moreland40069d52017-10-03 09:36:51 -0700610 for (const auto& fqName : packageInterfaces) {
611 out << "\"" << fqName.name() << ".hal\",\n";
612 }
Steven Moreland313a0132017-11-03 14:23:14 -0700613 }) << "],\n";
614 if (!importedPackagesHierarchy.empty()) {
615 (out << "interfaces: [\n").indent([&] {
616 for (const auto& fqName : importedPackagesHierarchy) {
617 out << "\"" << fqName.string() << "\",\n";
618 }
619 }) << "],\n";
620 }
621 if (typesAST != nullptr) {
622 (out << "types: [\n").indent([&] {
623 std::vector<NamedType *> subTypes = typesAST->getRootScope()->getSubTypes();
624 std::sort(
625 subTypes.begin(),
626 subTypes.end(),
627 [](const NamedType *a, const NamedType *b) -> bool {
628 return a->fqName() < b->fqName();
629 });
630
631 for (const auto &type : subTypes) {
632 if (type->isTypeDef()) {
633 continue;
634 }
635
636 out << "\"" << type->localName() << "\",\n";
637 }
638 }) << "],\n";
639 }
640 // Explicity call this out for developers.
641 out << "gen_java: " << (genJavaLibrary ? "true" : "false") << ",\n";
642 if (genJavaConstants) {
643 out << "gen_java_constants: true,\n";
644 }
Steven Moreland40069d52017-10-03 09:36:51 -0700645 }).endl().endl();
646
Steven Moreland40069d52017-10-03 09:36:51 -0700647 return OK;
648}
649
Steven Moreland5abcf012018-02-08 18:50:18 -0800650static status_t generateAndroidBpImplForPackage(Formatter& out, const FQName& packageFQName,
Steven Morelande6d7f092018-02-08 13:25:45 -0800651 const Coordinator* coordinator) {
Iliyan Malchev4923f932016-09-09 13:04:59 -0700652 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700653
654 std::vector<FQName> packageInterfaces;
655
656 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700657 coordinator->appendPackageInterfacesToVector(packageFQName,
658 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700659
660 if (err != OK) {
661 return err;
662 }
663
664 std::set<FQName> importedPackages;
665
666 for (const auto &fqName : packageInterfaces) {
667 AST *ast = coordinator->parse(fqName);
668
669 if (ast == NULL) {
670 fprintf(stderr,
671 "ERROR: Could not parse %s. Aborting.\n",
672 fqName.string().c_str());
673
674 return UNKNOWN_ERROR;
675 }
676
677 ast->getImportedPackages(&importedPackages);
678 }
679
Yifan Hong958ee462016-12-06 17:09:51 -0800680 out << "cc_library_shared {\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800681 out.indent([&] {
Steven Moreland92f1f452018-01-04 17:55:27 -0800682 out << "// FIXME: this should only be -impl for a passthrough hal.\n"
683 << "// In most cases, to convert this to a binderized implementation, you should:\n"
684 << "// - change '-impl' to '-service' here and make it a cc_binary instead of a\n"
685 << "// cc_library_shared.\n"
686 << "// - add a *.rc file for this module.\n"
687 << "// - delete HIDL_FETCH_I* functions.\n"
688 << "// - call configureRpcThreadpool and registerAsService on the instance.\n"
689 << "// You may also want to append '-impl/-service' with a specific identifier like\n"
690 << "// '-vendor' or '-<hardware identifier>' etc to distinguish it.\n";
Steven Moreland89a9ebb2017-12-04 10:18:00 -0800691 out << "name: \"" << libraryName << "\",\n";
692 if (!coordinator->getOwner().empty()) {
693 out << "owner: \"" << coordinator->getOwner() << "\",\n";
694 }
Steven Moreland92f1f452018-01-04 17:55:27 -0800695 out << "relative_install_path: \"hw\",\n";
696 if (coordinator->getOwner().empty()) {
697 out << "// FIXME: this should be 'vendor: true' for modules that will eventually be\n"
698 "// on AOSP.\n";
699 }
700 out << "proprietary: true,\n";
701 out << "srcs: [\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800702 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800703 for (const auto &fqName : packageInterfaces) {
704 if (fqName.name() == "types") {
705 continue;
706 }
707 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
708 }
709 });
710 out << "],\n"
711 << "shared_libs: [\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800712 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800713 out << "\"libhidlbase\",\n"
714 << "\"libhidltransport\",\n"
Yifan Hong958ee462016-12-06 17:09:51 -0800715 << "\"libutils\",\n"
716 << "\"" << makeLibraryName(packageFQName) << "\",\n";
Yifan Honge0f7d692016-10-20 17:51:33 -0700717
Yifan Hong958ee462016-12-06 17:09:51 -0800718 for (const auto &importedPackage : importedPackages) {
Steven Morelanddadd1842017-05-09 13:24:54 -0700719 if (isHidlTransportPackage(importedPackage)) {
720 continue;
721 }
722
Yifan Hong958ee462016-12-06 17:09:51 -0800723 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
724 }
725 });
726 out << "],\n";
727 });
728 out << "}\n";
Steven Moreland197d56c2016-09-09 10:03:58 -0700729
730 return OK;
731}
732
Steven Moreland6ec9eb92018-02-16 14:21:49 -0800733bool validateForSource(const FQName& fqName, const Coordinator* coordinator,
734 const std::string& language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700735 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700736 fprintf(stderr, "ERROR: Expecting package name\n");
Steven Moreland05951b32017-05-12 17:22:22 -0700737 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700738 }
739
740 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700741 fprintf(stderr, "ERROR: Expecting package version\n");
Steven Moreland05951b32017-05-12 17:22:22 -0700742 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700743 }
744
Andreas Huber0fa9e392016-08-31 09:05:44 -0700745 const std::string &name = fqName.name();
746 if (!name.empty()) {
747 if (name.find('.') == std::string::npos) {
Steven Moreland05951b32017-05-12 17:22:22 -0700748 return true;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700749 }
750
751 if (language != "java" || name.find("types.") != 0) {
752 // When generating java sources for "types.hal", output can be
753 // constrained to just one of the top-level types declared
754 // by using the extended syntax
755 // android.hardware.Foo@1.0::types.TopLevelTypeName.
756 // In all other cases (different language, not 'types') the dot
757 // notation in the name is illegal in this context.
Steven Moreland05951b32017-05-12 17:22:22 -0700758 return false;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700759 }
760
Steven Moreland05951b32017-05-12 17:22:22 -0700761 return true;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700762 }
763
Steven Moreland6ec9eb92018-02-16 14:21:49 -0800764 if (language == "java") {
765 bool isJavaCompatible;
766 status_t err = isPackageJavaCompatible(fqName, coordinator, &isJavaCompatible);
767 if (err != OK) return false;
768
769 if (!isJavaCompatible) {
770 fprintf(stderr,
771 "ERROR: %s is not Java compatible. The Java backend"
772 " does NOT support union types nor native handles. "
773 "In addition, vectors of arrays are limited to at most "
774 "one-dimensional arrays and vectors of {vectors,interfaces} are"
775 " not supported.\n",
776 fqName.string().c_str());
777 return false;
778 }
779 }
780
Steven Moreland05951b32017-05-12 17:22:22 -0700781 return true;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700782}
783
Steven Moreland5abcf012018-02-08 18:50:18 -0800784FileGenerator::GenerationFunction generateExportHeaderForPackage(bool forJava) {
785 return [forJava](Formatter& out, const FQName& packageFQName,
786 const Coordinator* coordinator) -> status_t {
Steven Moreland77730892018-03-06 14:39:41 -0800787 CHECK(!packageFQName.package().empty() && !packageFQName.version().empty() &&
788 packageFQName.name().empty());
Andreas Huber019d21d2016-10-03 12:59:47 -0700789
Steven Morelandf47912d2017-05-12 16:25:44 -0700790 std::vector<FQName> packageInterfaces;
Andreas Huber019d21d2016-10-03 12:59:47 -0700791
Steven Morelandf47912d2017-05-12 16:25:44 -0700792 status_t err = coordinator->appendPackageInterfacesToVector(
793 packageFQName, &packageInterfaces);
Andreas Huber019d21d2016-10-03 12:59:47 -0700794
Steven Morelandf47912d2017-05-12 16:25:44 -0700795 if (err != OK) {
796 return err;
Andreas Huber019d21d2016-10-03 12:59:47 -0700797 }
798
Steven Morelandf47912d2017-05-12 16:25:44 -0700799 std::vector<const Type *> exportedTypes;
Andreas Huber019d21d2016-10-03 12:59:47 -0700800
Steven Morelandf47912d2017-05-12 16:25:44 -0700801 for (const auto &fqName : packageInterfaces) {
802 AST *ast = coordinator->parse(fqName);
803
804 if (ast == NULL) {
805 fprintf(stderr,
806 "ERROR: Could not parse %s. Aborting.\n",
807 fqName.string().c_str());
808
809 return UNKNOWN_ERROR;
810 }
811
812 ast->appendToExportedTypesVector(&exportedTypes);
813 }
814
815 if (exportedTypes.empty()) {
816 return OK;
817 }
818
Steven Morelanda885d252017-09-25 18:44:43 -0700819 if (!out.isValid()) {
820 return UNKNOWN_ERROR;
Steven Morelandf47912d2017-05-12 16:25:44 -0700821 }
822
Steven Moreland255c9a12018-02-26 13:10:27 -0800823 std::string packagePath;
824 err = coordinator->getPackagePath(packageFQName, false /* relative */,
825 false /* sanitized */, &packagePath);
826 if (err != OK) return err;
827
Steven Morelandf47912d2017-05-12 16:25:44 -0700828 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
829 << "// Source: " << packageFQName.string() << "\n"
Steven Moreland255c9a12018-02-26 13:10:27 -0800830 << "// Location: " << packagePath << "\n\n";
Steven Morelandf47912d2017-05-12 16:25:44 -0700831
832 std::string guard;
833 if (forJava) {
834 out << "package " << packageFQName.javaPackage() << ";\n\n";
835 out << "public class Constants {\n";
836 out.indent();
837 } else {
838 guard = "HIDL_GENERATED_";
839 guard += StringHelper::Uppercase(packageFQName.tokenName());
840 guard += "_";
841 guard += "EXPORTED_CONSTANTS_H_";
842
843 out << "#ifndef "
844 << guard
845 << "\n#define "
846 << guard
847 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
848 }
849
850 for (const auto &type : exportedTypes) {
851 type->emitExportedHeader(out, forJava);
852 }
853
854 if (forJava) {
855 out.unindent();
856 out << "}\n";
857 } else {
858 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
859 << guard
860 << "\n";
861 }
862
Andreas Huber019d21d2016-10-03 12:59:47 -0700863 return OK;
Steven Morelandf47912d2017-05-12 16:25:44 -0700864 };
Andreas Huber019d21d2016-10-03 12:59:47 -0700865}
866
Steven Moreland5abcf012018-02-08 18:50:18 -0800867static status_t generateHashOutput(Formatter& out, const FQName& fqName,
868 const Coordinator* coordinator) {
869 CHECK(fqName.isFullyQualified());
Steven Morelandf2e44692017-04-18 20:19:09 -0700870
Steven Moreland5abcf012018-02-08 18:50:18 -0800871 AST* ast = coordinator->parse(fqName, {} /* parsed */,
872 Coordinator::Enforce::NO_HASH /* enforcement */);
873
874 if (ast == NULL) {
875 fprintf(stderr, "ERROR: Could not parse %s. Aborting.\n", fqName.string().c_str());
876
877 return UNKNOWN_ERROR;
Steven Morelandf2e44692017-04-18 20:19:09 -0700878 }
879
Steven Moreland5abcf012018-02-08 18:50:18 -0800880 out << Hash::getHash(ast->getFilename()).hexString() << " " << fqName.string() << "\n";
Steven Morelandf2e44692017-04-18 20:19:09 -0700881
882 return OK;
883}
884
Steven Moreland5abcf012018-02-08 18:50:18 -0800885template <typename T>
886std::vector<T> operator+(const std::vector<T>& lhs, const std::vector<T>& rhs) {
887 std::vector<T> ret;
888 ret.reserve(lhs.size() + rhs.size());
889 ret.insert(ret.begin(), lhs.begin(), lhs.end());
890 ret.insert(ret.end(), rhs.begin(), rhs.end());
891 return ret;
892}
893
Steven Moreland0241a842017-10-06 10:26:07 -0700894// clang-format off
Steven Moreland5abcf012018-02-08 18:50:18 -0800895static const std::vector<FileGenerator> kCppHeaderFormats = {
896 {
897 FileGenerator::alwaysGenerate,
898 [](const FQName& fqName) { return fqName.name() + ".h"; },
899 astGenerationFunction(&AST::generateInterfaceHeader),
Steven Moreland3b1ce262017-04-21 14:19:59 -0700900 },
Steven Moreland5abcf012018-02-08 18:50:18 -0800901 {
902 FileGenerator::alwaysGenerate,
903 [](const FQName& fqName) {
904 return fqName.isInterfaceName() ? fqName.getInterfaceHwName() + ".h" : "hwtypes.h";
905 },
906 astGenerationFunction(&AST::generateHwBinderHeader),
907 },
908 {
909 FileGenerator::generateForInterfaces,
910 [](const FQName& fqName) { return fqName.getInterfaceStubName() + ".h"; },
911 astGenerationFunction(&AST::generateStubHeader),
912 },
913 {
914 FileGenerator::generateForInterfaces,
915 [](const FQName& fqName) { return fqName.getInterfaceProxyName() + ".h"; },
916 astGenerationFunction(&AST::generateProxyHeader),
917 },
918 {
919 FileGenerator::generateForInterfaces,
920 [](const FQName& fqName) { return fqName.getInterfacePassthroughName() + ".h"; },
921 astGenerationFunction(&AST::generatePassthroughHeader),
922 },
923};
Steven Moreland3b1ce262017-04-21 14:19:59 -0700924
Steven Moreland5abcf012018-02-08 18:50:18 -0800925static const std::vector<FileGenerator> kCppSourceFormats = {
926 {
927 FileGenerator::alwaysGenerate,
928 [](const FQName& fqName) {
929 return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + "All.cpp" : "types.cpp";
930 },
931 astGenerationFunction(&AST::generateCppSource),
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700932 },
Steven Moreland5abcf012018-02-08 18:50:18 -0800933};
Steven Moreland1cbf0362017-05-09 14:32:53 -0700934
Steven Moreland5abcf012018-02-08 18:50:18 -0800935static const std::vector<FileGenerator> kCppImplHeaderFormats = {
936 {
937 FileGenerator::generateForInterfaces,
938 [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".h"; },
939 astGenerationFunction(&AST::generateCppImplHeader),
Andreas Huber019d21d2016-10-03 12:59:47 -0700940 },
Steven Moreland5abcf012018-02-08 18:50:18 -0800941};
Andreas Huber019d21d2016-10-03 12:59:47 -0700942
Steven Moreland5abcf012018-02-08 18:50:18 -0800943static const std::vector<FileGenerator> kCppImplSourceFormats = {
944 {
945 FileGenerator::generateForInterfaces,
946 [](const FQName& fqName) { return fqName.getInterfaceBaseName() + ".cpp"; },
947 astGenerationFunction(&AST::generateCppImplSource),
Steven Moreland9c387612016-09-07 09:54:26 -0700948 },
Steven Moreland5abcf012018-02-08 18:50:18 -0800949};
Steven Moreland9c387612016-09-07 09:54:26 -0700950
Steven Moreland5abcf012018-02-08 18:50:18 -0800951static const std::vector<FileGenerator> kCppAdapterHeaderFormats = {
952 {
953 FileGenerator::alwaysGenerate,
954 [](const FQName& fqName) {
955 return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".h" : "Atypes.h";
956 },
957 astGenerationFunction(&AST::generateCppAdapterHeader),
Steven Moreland9a6da7a2017-09-15 16:21:24 -0700958 },
Steven Moreland5abcf012018-02-08 18:50:18 -0800959};
Steven Moreland9a6da7a2017-09-15 16:21:24 -0700960
Steven Moreland5abcf012018-02-08 18:50:18 -0800961static const std::vector<FileGenerator> kCppAdapterSourceFormats = {
962 {
963 FileGenerator::alwaysGenerate,
964 [](const FQName& fqName) {
965 return fqName.isInterfaceName() ? fqName.getInterfaceAdapterName() + ".cpp" : "Atypes.cpp";
966 },
967 astGenerationFunction(&AST::generateCppAdapterSource),
Andreas Huber2831d512016-08-15 09:33:47 -0700968 },
Steven Moreland5abcf012018-02-08 18:50:18 -0800969};
Andreas Huber2831d512016-08-15 09:33:47 -0700970
Steven Moreland5abcf012018-02-08 18:50:18 -0800971static const std::vector<OutputHandler> kFormats = {
972 {
973 "check",
974 "Parses the interface to see if valid but doesn't write any files.",
975 OutputMode::NOT_NEEDED,
976 Coordinator::Location::STANDARD_OUT,
977 GenerationGranularity::PER_FILE,
978 validateForSource,
979 {
980 {
981 FileGenerator::alwaysGenerate,
982 nullptr /* filename for fqname */,
983 astGenerationFunction(),
984 },
985 },
Andreas Huber1c507272016-10-05 14:33:21 -0700986 },
Steven Moreland5abcf012018-02-08 18:50:18 -0800987 {
988 "c++",
989 "(internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.",
990 OutputMode::NEEDS_DIR,
991 Coordinator::Location::GEN_OUTPUT,
992 GenerationGranularity::PER_FILE,
993 validateForSource,
994 kCppHeaderFormats + kCppSourceFormats,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700995 },
Steven Moreland5abcf012018-02-08 18:50:18 -0800996 {
997 "c++-headers",
998 "(internal) Generates C++ headers for interface files for talking to HIDL interfaces.",
999 OutputMode::NEEDS_DIR,
1000 Coordinator::Location::GEN_OUTPUT,
1001 GenerationGranularity::PER_FILE,
1002 validateForSource,
1003 kCppHeaderFormats,
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001004 },
Steven Moreland5abcf012018-02-08 18:50:18 -08001005 {
1006 "c++-sources",
1007 "(internal) Generates C++ sources for interface files for talking to HIDL interfaces.",
1008 OutputMode::NEEDS_DIR,
1009 Coordinator::Location::GEN_OUTPUT,
1010 GenerationGranularity::PER_FILE,
1011 validateForSource,
1012 kCppSourceFormats,
Dan Willemsen676abdc2016-09-28 19:42:22 -07001013 },
Steven Moreland5abcf012018-02-08 18:50:18 -08001014 {
1015 "export-header",
1016 "Generates a header file from @export enumerations to help maintain legacy code.",
1017 OutputMode::NEEDS_FILE,
1018 Coordinator::Location::DIRECT,
1019 GenerationGranularity::PER_PACKAGE,
1020 validateIsPackage,
1021 {singleFileGenerator("", generateExportHeaderForPackage(false /* forJava */))}
Steven Morelandf2e44692017-04-18 20:19:09 -07001022 },
Steven Moreland5abcf012018-02-08 18:50:18 -08001023 {
1024 "c++-impl",
1025 "Generates boilerplate implementation of a hidl interface in C++ (for convenience).",
1026 OutputMode::NEEDS_DIR,
1027 Coordinator::Location::DIRECT,
1028 GenerationGranularity::PER_FILE,
1029 validateForSource,
1030 kCppImplHeaderFormats + kCppImplSourceFormats,
1031 },
1032 {
1033 "c++-impl-headers",
1034 "c++-impl but headers only",
1035 OutputMode::NEEDS_DIR,
1036 Coordinator::Location::DIRECT,
1037 GenerationGranularity::PER_FILE,
1038 validateForSource,
1039 kCppImplHeaderFormats,
1040 },
1041 {
1042 "c++-impl-sources",
1043 "c++-impl but sources only",
1044 OutputMode::NEEDS_DIR,
1045 Coordinator::Location::DIRECT,
1046 GenerationGranularity::PER_FILE,
1047 validateForSource,
1048 kCppImplSourceFormats,
1049 },
1050 {
1051 "c++-adapter",
1052 "Takes a x.(y+n) interface and mocks an x.y interface.",
1053 OutputMode::NEEDS_DIR,
1054 Coordinator::Location::GEN_OUTPUT,
1055 GenerationGranularity::PER_FILE,
1056 validateForSource,
1057 kCppAdapterHeaderFormats + kCppAdapterSourceFormats,
1058 },
1059 {
1060 "c++-adapter-headers",
1061 "c++-adapter but helper headers only",
1062 OutputMode::NEEDS_DIR,
1063 Coordinator::Location::GEN_OUTPUT,
1064 GenerationGranularity::PER_FILE,
1065 validateForSource,
1066 kCppAdapterHeaderFormats,
1067 },
1068 {
1069 "c++-adapter-sources",
1070 "c++-adapter but helper sources only",
1071 OutputMode::NEEDS_DIR,
1072 Coordinator::Location::GEN_OUTPUT,
1073 GenerationGranularity::PER_FILE,
1074 validateForSource,
1075 kCppAdapterSourceFormats,
1076 },
1077 {
1078 "c++-adapter-main",
1079 "c++-adapter but the adapter binary source only",
1080 OutputMode::NEEDS_DIR,
1081 Coordinator::Location::DIRECT,
1082 GenerationGranularity::PER_PACKAGE,
1083 validateIsPackage,
1084 {singleFileGenerator("main.cpp", generateAdapterMainSource)},
1085 },
1086 {
1087 "java",
1088 "(internal) Generates Java library for talking to HIDL interfaces in Java.",
1089 OutputMode::NEEDS_DIR,
1090 Coordinator::Location::GEN_SANITIZED,
1091 GenerationGranularity::PER_TYPE,
1092 validateForSource,
1093 {
1094 {
1095 FileGenerator::alwaysGenerate,
1096 [](const FQName& fqName) {
1097 return StringHelper::LTrim(fqName.name(), "types.") + ".java";
1098 },
1099 generateJavaForPackage,
1100 },
1101 }
1102 },
1103 {
1104 "java-constants",
1105 "(internal) Like export-header but for Java (always created by -Lmakefile if @export exists).",
1106 OutputMode::NEEDS_DIR,
1107 Coordinator::Location::GEN_SANITIZED,
1108 GenerationGranularity::PER_PACKAGE,
1109 validateIsPackage,
1110 {singleFileGenerator("Constants.java", generateExportHeaderForPackage(true /* forJava */))}
1111 },
1112 {
1113 "vts",
1114 "(internal) Generates vts proto files for use in vtsd.",
1115 OutputMode::NEEDS_DIR,
1116 Coordinator::Location::GEN_OUTPUT,
1117 GenerationGranularity::PER_FILE,
1118 validateForSource,
1119 {
1120 {
1121 FileGenerator::alwaysGenerate,
1122 [](const FQName& fqName) {
1123 return fqName.isInterfaceName() ? fqName.getInterfaceBaseName() + ".vts" : "types.vts";
1124 },
1125 astGenerationFunction(&AST::generateVts),
1126 },
1127 }
1128 },
1129 {
1130 "makefile",
1131 "(removed) Used to generate makefiles for -Ljava and -Ljava-constants.",
1132 OutputMode::NEEDS_SRC,
1133 Coordinator::Location::PACKAGE_ROOT,
1134 GenerationGranularity::PER_PACKAGE,
Steven Moreland6ec9eb92018-02-16 14:21:49 -08001135 [](const FQName &, const Coordinator*, const std::string &) {
Steven Moreland5abcf012018-02-08 18:50:18 -08001136 fprintf(stderr, "ERROR: makefile output is not supported. Use -Landroidbp for all build file generation.\n");
1137 return false;
1138 },
1139 {},
1140 },
1141 {
1142 "androidbp",
1143 "(internal) Generates Soong bp files for -Lc++-headers, -Lc++-sources, -Ljava, -Ljava-constants, and -Lc++-adapter.",
1144 OutputMode::NEEDS_SRC,
1145 Coordinator::Location::PACKAGE_ROOT,
1146 GenerationGranularity::PER_PACKAGE,
1147 validateIsPackage,
1148 {singleFileGenerator("Android.bp", generateAndroidBpForPackage)},
1149 },
1150 {
1151 "androidbp-impl",
1152 "Generates boilerplate bp files for implementation created with -Lc++-impl.",
1153 OutputMode::NEEDS_DIR,
1154 Coordinator::Location::DIRECT,
1155 GenerationGranularity::PER_PACKAGE,
1156 validateIsPackage,
1157 {singleFileGenerator("Android.bp", generateAndroidBpImplForPackage)},
1158 },
1159 {
1160 "hash",
1161 "Prints hashes of interface in `current.txt` format to standard out.",
1162 OutputMode::NOT_NEEDED,
1163 Coordinator::Location::STANDARD_OUT,
1164 GenerationGranularity::PER_FILE,
1165 validateForSource,
1166 {
1167 {
1168 FileGenerator::alwaysGenerate,
1169 nullptr /* file name for fqName */,
1170 generateHashOutput,
1171 },
1172 }
Steven Morelandf2e44692017-04-18 20:19:09 -07001173 },
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001174};
Steven Moreland0241a842017-10-06 10:26:07 -07001175// clang-format on
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001176
1177static void usage(const char *me) {
1178 fprintf(stderr,
Steven Moreland89a9ebb2017-12-04 10:18:00 -08001179 "usage: %s [-p <root path>] -o <output path> -L <language> [-O <owner>] (-r <interface "
Steven Morelanda12df112018-02-15 14:32:46 -08001180 "root>)+ [-v] [-d <depfile>] FQNAME...\n\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001181 me);
1182
Steven Morelanda12df112018-02-15 14:32:46 -08001183 fprintf(stderr,
1184 "Process FQNAME, PACKAGE(.SUBPACKAGE)*@[0-9]+.[0-9]+(::TYPE)?, to create output.\n\n");
1185
Steven Moreland97e52332017-05-12 16:47:19 -07001186 fprintf(stderr, " -h: Prints this menu.\n");
1187 fprintf(stderr, " -L <language>: The following options are available:\n");
Steven Moreland5abcf012018-02-08 18:50:18 -08001188 for (auto& e : kFormats) {
Steven Moreland97e52332017-05-12 16:47:19 -07001189 fprintf(stderr, " %-16s: %s\n", e.name().c_str(), e.description().c_str());
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001190 }
Steven Moreland89a9ebb2017-12-04 10:18:00 -08001191 fprintf(stderr, " -O <owner>: The owner of the module for -Landroidbp(-impl)?.\n");
Steven Moreland97e52332017-05-12 16:47:19 -07001192 fprintf(stderr, " -o <output path>: Location to output files.\n");
1193 fprintf(stderr, " -p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.\n");
1194 fprintf(stderr, " -r <package:path root>: E.g., android.hardware:hardware/interfaces.\n");
Steven Morelanda838ceb2018-02-06 13:19:23 -08001195 fprintf(stderr, " -v: verbose output.\n");
Steven Moreland394af5c2018-02-09 14:41:46 -08001196 fprintf(stderr, " -d <depfile>: location of depfile to write to.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001197}
1198
Andreas Gampec4ce9262017-04-27 21:03:20 -07001199// hidl is intentionally leaky. Turn off LeakSanitizer by default.
1200extern "C" const char *__asan_default_options() {
Evgenii Stepanova3ee97c2017-08-16 14:59:29 -07001201 return "detect_leaks=0";
Andreas Gampec4ce9262017-04-27 21:03:20 -07001202}
1203
Andreas Huberb82318c2016-08-02 14:45:54 -07001204int main(int argc, char **argv) {
Andreas Huber737080b2016-08-02 15:38:04 -07001205 const char *me = argv[0];
Steven Moreland3db99f22017-05-11 16:21:46 -07001206 if (argc == 1) {
1207 usage(me);
1208 exit(1);
1209 }
1210
Steven Moreland5abcf012018-02-08 18:50:18 -08001211 const OutputHandler* outputFormat = nullptr;
Steven Moreland47792c42017-09-20 10:03:20 -07001212 Coordinator coordinator;
1213 std::string outputPath;
1214
Andreas Huberb82318c2016-08-02 14:45:54 -07001215 int res;
Steven Moreland394af5c2018-02-09 14:41:46 -08001216 while ((res = getopt(argc, argv, "hp:o:O:r:L:vd:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -07001217 switch (res) {
Steven Moreland394af5c2018-02-09 14:41:46 -08001218 case 'p': {
Steven Moreland0d93b142018-01-04 17:26:30 -08001219 if (!coordinator.getRootPath().empty()) {
1220 fprintf(stderr, "ERROR: -p <root path> can only be specified once.\n");
1221 exit(1);
1222 }
Steven Moreland47792c42017-09-20 10:03:20 -07001223 coordinator.setRootPath(optarg);
Steven Morelandf7fa0682017-05-11 16:14:55 -07001224 break;
1225 }
1226
Steven Moreland394af5c2018-02-09 14:41:46 -08001227 case 'v': {
Steven Moreland37c57ee2017-09-25 19:08:56 -07001228 coordinator.setVerbose(true);
1229 break;
1230 }
1231
Steven Moreland394af5c2018-02-09 14:41:46 -08001232 case 'd': {
1233 coordinator.setDepFile(optarg);
1234 break;
1235 }
1236
1237 case 'o': {
Steven Moreland0d93b142018-01-04 17:26:30 -08001238 if (!outputPath.empty()) {
1239 fprintf(stderr, "ERROR: -o <output path> can only be specified once.\n");
1240 exit(1);
1241 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001242 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -07001243 break;
1244 }
1245
Steven Moreland89a9ebb2017-12-04 10:18:00 -08001246 case 'O': {
1247 if (!coordinator.getOwner().empty()) {
1248 fprintf(stderr, "ERROR: -O <owner> can only be specified once.\n");
1249 exit(1);
1250 }
1251 coordinator.setOwner(optarg);
1252 break;
1253 }
1254
Steven Moreland394af5c2018-02-09 14:41:46 -08001255 case 'r': {
Andreas Huberdca261f2016-08-04 13:47:51 -07001256 std::string val(optarg);
1257 auto index = val.find_first_of(':');
Steven Moreland4ff74202017-04-21 14:24:47 -07001258 if (index == std::string::npos) {
1259 fprintf(stderr, "ERROR: -r option must contain ':': %s\n", val.c_str());
1260 exit(1);
1261 }
Andreas Huberdca261f2016-08-04 13:47:51 -07001262
Steven Moreland13594d12017-09-28 23:27:50 +00001263 auto root = val.substr(0, index);
1264 auto path = val.substr(index + 1);
Steven Moreland47792c42017-09-20 10:03:20 -07001265
1266 std::string error;
1267 status_t err = coordinator.addPackagePath(root, path, &error);
1268 if (err != OK) {
1269 fprintf(stderr, "%s\n", error.c_str());
1270 exit(1);
1271 }
1272
Andreas Huberdca261f2016-08-04 13:47:51 -07001273 break;
1274 }
1275
Steven Moreland394af5c2018-02-09 14:41:46 -08001276 case 'L': {
Steven Morelanddd583842017-04-19 13:09:57 -07001277 if (outputFormat != nullptr) {
1278 fprintf(stderr,
1279 "ERROR: only one -L option allowed. \"%s\" already specified.\n",
1280 outputFormat->name().c_str());
1281 exit(1);
1282 }
Steven Moreland5abcf012018-02-08 18:50:18 -08001283 for (auto& e : kFormats) {
Steven Morelanddd583842017-04-19 13:09:57 -07001284 if (e.name() == optarg) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001285 outputFormat = &e;
1286 break;
1287 }
1288 }
Steven Morelanddd583842017-04-19 13:09:57 -07001289 if (outputFormat == nullptr) {
1290 fprintf(stderr,
1291 "ERROR: unrecognized -L option: \"%s\".\n",
1292 optarg);
1293 exit(1);
1294 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001295 break;
1296 }
1297
Andreas Huberb82318c2016-08-02 14:45:54 -07001298 case '?':
1299 case 'h':
Steven Moreland394af5c2018-02-09 14:41:46 -08001300 default: {
Andreas Huber737080b2016-08-02 15:38:04 -07001301 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -07001302 exit(1);
1303 break;
1304 }
1305 }
1306 }
1307
Steven Moreland0d93b142018-01-04 17:26:30 -08001308 if (coordinator.getRootPath().empty()) {
1309 const char* ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
1310 if (ANDROID_BUILD_TOP != nullptr) {
1311 coordinator.setRootPath(ANDROID_BUILD_TOP);
1312 }
1313 }
1314
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001315 if (outputFormat == nullptr) {
Steven Morelanddd583842017-04-19 13:09:57 -07001316 fprintf(stderr,
1317 "ERROR: no -L option provided.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001318 exit(1);
1319 }
1320
Andreas Huberb82318c2016-08-02 14:45:54 -07001321 argc -= optind;
1322 argv += optind;
1323
Steven Moreland3effa832017-06-16 16:17:41 -07001324 if (argc == 0) {
1325 fprintf(stderr, "ERROR: no fqname specified.\n");
1326 usage(me);
1327 exit(1);
1328 }
1329
Andreas Huber737080b2016-08-02 15:38:04 -07001330 // Valid options are now in argv[0] .. argv[argc - 1].
1331
Andreas Huber019d21d2016-10-03 12:59:47 -07001332 switch (outputFormat->mOutputMode) {
Steven Moreland5abcf012018-02-08 18:50:18 -08001333 case OutputMode::NEEDS_DIR:
1334 case OutputMode::NEEDS_FILE: {
Andreas Huber019d21d2016-10-03 12:59:47 -07001335 if (outputPath.empty()) {
1336 usage(me);
1337 exit(1);
1338 }
1339
Steven Moreland5abcf012018-02-08 18:50:18 -08001340 if (outputFormat->mOutputMode == OutputMode::NEEDS_DIR) {
Howard Chen30f6b492017-08-24 16:50:12 +08001341 if (outputPath.back() != '/') {
Andreas Huber019d21d2016-10-03 12:59:47 -07001342 outputPath += "/";
1343 }
1344 }
1345 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001346 }
Steven Moreland5abcf012018-02-08 18:50:18 -08001347 case OutputMode::NEEDS_SRC: {
Steven Morelanda171b562017-05-12 15:18:03 -07001348 if (outputPath.empty()) {
Steven Moreland47792c42017-09-20 10:03:20 -07001349 outputPath = coordinator.getRootPath();
Steven Morelanda171b562017-05-12 15:18:03 -07001350 }
Howard Chen30f6b492017-08-24 16:50:12 +08001351 if (outputPath.back() != '/') {
1352 outputPath += "/";
1353 }
Steven Morelanda171b562017-05-12 15:18:03 -07001354
1355 break;
1356 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001357
1358 default:
1359 outputPath.clear(); // Unused.
1360 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001361 }
1362
Steven Moreland6d3d3c82018-02-08 11:49:34 -08001363 coordinator.setOutputPath(outputPath);
1364
Steven Moreland25c81662017-05-12 14:57:36 -07001365 coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
1366 coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
1367 coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
1368 coordinator.addDefaultPackagePath("android.system", "system/hardware/interfaces");
Andreas Huber5345ec22016-07-29 13:33:27 -07001369
Andreas Huber737080b2016-08-02 15:38:04 -07001370 for (int i = 0; i < argc; ++i) {
Steven Morelande1b157e2018-03-06 14:18:32 -08001371 FQName fqName;
1372 if (!FQName::parse(argv[i], &fqName)) {
Steven Morelanda12df112018-02-15 14:32:46 -08001373 fprintf(stderr, "ERROR: Invalid fully-qualified name as argument: %s.\n", argv[i]);
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001374 exit(1);
1375 }
Andreas Huber881227d2016-08-02 14:20:21 -07001376
Steven Morelanda12df112018-02-15 14:32:46 -08001377 // TODO(b/65200821): remove
1378 gCurrentCompileName = "_" + StringHelper::Uppercase(fqName.tokenName());
1379
Steven Morelandb65e5d92018-02-08 12:44:51 -08001380 // Dump extra verbose output
1381 if (coordinator.isVerbose()) {
1382 status_t err =
1383 dumpDefinedButUnreferencedTypeNames(fqName.getPackageAndVersion(), &coordinator);
1384 if (err != OK) return err;
1385 }
1386
Steven Moreland6ec9eb92018-02-16 14:21:49 -08001387 if (!outputFormat->validate(fqName, &coordinator, outputFormat->name())) {
Steven Morelandf2e44692017-04-18 20:19:09 -07001388 fprintf(stderr,
1389 "ERROR: output handler failed.\n");
Andreas Hubere61e3f72016-08-03 10:22:03 -07001390 exit(1);
1391 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001392
Steven Moreland1125cf32018-02-08 13:15:27 -08001393 status_t err = outputFormat->generate(fqName, &coordinator);
Steven Moreland394af5c2018-02-09 14:41:46 -08001394 if (err != OK) exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001395
Steven Moreland394af5c2018-02-09 14:41:46 -08001396 err = outputFormat->writeDepFile(fqName, &coordinator);
1397 if (err != OK) exit(1);
Andreas Hubereb1081f2016-07-28 13:13:24 -07001398 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001399
Andreas Huberd2943e12016-08-05 11:59:31 -07001400 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001401}