1 /*
2 * Copyright (C) 2020 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 <android-base/logging.h>
18 #include <android-base/strings.h>
19 #include <hidl-util/FQName.h>
20 #include <hidl-util/Formatter.h>
21 #include <hidl-util/StringHelper.h>
22 #include <limits>
23 #include <set>
24 #include <string>
25 #include <vector>
26
27 #include "AidlHelper.h"
28 #include "ArrayType.h"
29 #include "CompoundType.h"
30 #include "ConstantExpression.h"
31 #include "Coordinator.h"
32 #include "EnumType.h"
33 #include "Interface.h"
34 #include "NamedType.h"
35 #include "ScalarType.h"
36 #include "Scope.h"
37 #include "VectorType.h"
38
39 namespace android {
40
translateHeaderFile(const FQName & fqName,AidlBackend backend)41 std::string AidlHelper::translateHeaderFile(const FQName& fqName, AidlBackend backend) {
42 switch (backend) {
43 case AidlBackend::NDK:
44 return AidlHelper::getAidlPackagePath(fqName) + "/translate-ndk.h";
45 case AidlBackend::CPP:
46 return AidlHelper::getAidlPackagePath(fqName) + "/translate-cpp.h";
47 default:
48 LOG(FATAL) << "Unexpected AidlBackend value";
49 return "";
50 }
51 }
52
translateSourceFile(const FQName & fqName,AidlBackend backend)53 std::string AidlHelper::translateSourceFile(const FQName& fqName, AidlBackend backend) {
54 switch (backend) {
55 case AidlBackend::NDK:
56 return "translate/" + AidlHelper::getAidlPackagePath(fqName) + "/translate-ndk.cpp";
57 case AidlBackend::CPP:
58 return "translate/" + AidlHelper::getAidlPackagePath(fqName) + "/translate-cpp.cpp";
59 case AidlBackend::JAVA:
60 return "translate/" + AidlHelper::getAidlPackagePath(fqName) + "/Translate.java";
61 default:
62 LOG(FATAL) << "Unexpected AidlBackend value";
63 return "";
64 }
65 }
66
aidlTypePackage(const NamedType & type,AidlBackend backend)67 static const std::string aidlTypePackage(const NamedType& type, AidlBackend backend) {
68 const std::string prefix = (backend == AidlBackend::NDK) ? "aidl::" : std::string();
69 const std::string separator = (backend == AidlBackend::JAVA) ? "." : "::";
70 return prefix +
71 base::Join(base::Split(AidlHelper::getAidlPackage(type.fqName()), "."), separator) +
72 separator + AidlHelper::getAidlType(type, type.fqName(), backend);
73 }
74
emitEnumStaticAssert(Formatter & out,const NamedType & namedType,AidlBackend backend)75 static void emitEnumStaticAssert(Formatter& out, const NamedType& namedType, AidlBackend backend) {
76 CHECK(namedType.isEnum());
77 const auto& enumType = static_cast<const EnumType&>(namedType);
78
79 std::vector<const EnumValue*> values;
80 for (const EnumType* type : enumType.typeChain()) {
81 if (!AidlHelper::shouldBeExpanded(enumType.fqName(), type->fqName())) {
82 break;
83 }
84 values.insert(values.end(), type->values().rbegin(), type->values().rend());
85 }
86
87 for (auto it = values.rbegin(); it != values.rend(); ++it) {
88 out << "static_assert(" << aidlTypePackage(namedType, backend) << "::" << (*it)->name()
89 << " == static_cast<" << aidlTypePackage(namedType, backend) << ">("
90 << namedType.fullName() << "::" << (*it)->name() << "));\n";
91 };
92
93 out << "\n";
94 }
95
emitStaticAsserts(Formatter & out,const std::set<const NamedType * > & namedTypes,AidlBackend backend)96 static void emitStaticAsserts(Formatter& out, const std::set<const NamedType*>& namedTypes,
97 AidlBackend backend) {
98 CHECK(backend != AidlBackend::JAVA);
99 for (const auto& namedType : namedTypes) {
100 if (namedType->isEnum()) {
101 emitEnumStaticAssert(out, *namedType, backend);
102 }
103 }
104 }
105
namedTypeTranslation(Formatter & out,const std::set<const NamedType * > & namedTypes,const FieldWithVersion & field,const CompoundType * parent,AidlBackend backend)106 static void namedTypeTranslation(Formatter& out, const std::set<const NamedType*>& namedTypes,
107 const FieldWithVersion& field, const CompoundType* parent,
108 AidlBackend backend) {
109 const NamedType* type = static_cast<const NamedType*>(field.field->get());
110 if (namedTypes.find(type) == namedTypes.end()) {
111 std::optional<const ReplacedTypeInfo> replacedType =
112 AidlHelper::getAidlReplacedType(type->fqName());
113 if (replacedType) {
114 std::optional<std::function<void(Formatter&)>> translateField =
115 replacedType.value().translateField;
116 if (translateField) {
117 translateField.value()(out);
118 }
119 } else {
120 AidlHelper::notes() << "An unknown named type was found in translation: "
121 << type->fqName().string() + "\n";
122 out << "// FIXME Unknown type: " << type->fqName().string() << "\n";
123 out << "// That type's package needs to be converted separately and the corresponding "
124 "translate function should be added here.\n";
125 }
126 } else {
127 if (parent->style() == CompoundType::STYLE_STRUCT) {
128 if (backend == AidlBackend::JAVA) {
129 out << "out." << field.field->name() << " = h2aTranslate(in." << field.fullName
130 << ");\n";
131 } else {
132 out << "if (!translate(in." << field.fullName << ", &out->" << field.field->name()
133 << ")) return false;\n";
134 }
135 } else {
136 if (backend == AidlBackend::JAVA) {
137 out << "out.set" << StringHelper::Capitalize(field.field->name())
138 << "(h2aTranslate(in." << field.fullName << "()));\n";
139 } else {
140 out << "{\n";
141 out << aidlTypePackage(*type, backend) << " " << field.field->name() << ";\n";
142 out << "if (!translate(in." << field.fullName + "(), &" << field.field->name()
143 << ")) return false;\n";
144 out << "out->set<" << aidlTypePackage(*parent, backend) << "::" << field.fullName
145 << ">(" << field.field->name() << ");\n";
146 out << "}\n";
147 }
148 }
149 }
150 }
151
h2aScalarChecks(Formatter & out,const Type & type,const std::string & inputAccess,AidlBackend backend)152 static void h2aScalarChecks(Formatter& out, const Type& type, const std::string& inputAccess,
153 AidlBackend backend) {
154 static const std::map<ScalarType::Kind, std::pair<std::string, size_t>> kSignedMaxSize{
155 {ScalarType::KIND_UINT8,
156 {"std::numeric_limits<int8_t>::max()", std::numeric_limits<int8_t>::max()}},
157 {ScalarType::KIND_UINT16, {"", 0}},
158 {ScalarType::KIND_INT16, {"", 0}},
159 {ScalarType::KIND_UINT32,
160 {"std::numeric_limits<int32_t>::max()", std::numeric_limits<int32_t>::max()}},
161 {ScalarType::KIND_UINT64,
162 {"std::numeric_limits<int64_t>::max()", std::numeric_limits<int64_t>::max()}}};
163 const ScalarType* scalarType = type.resolveToScalarType();
164 if (scalarType != nullptr && !type.isEnum()) {
165 const auto& it = kSignedMaxSize.find(scalarType->getKind());
166 // *int16_t is a special case for both HIDL and AIDL. For uint16_t, checks are only
167 // needed in the Java backend.
168 if (backend != AidlBackend::JAVA && scalarType->getKind() == ScalarType::KIND_UINT16) {
169 return;
170 }
171 if (it != kSignedMaxSize.end()) {
172 out << "// FIXME This requires conversion between signed and unsigned. Change this if "
173 "it doesn't suit your needs.\n";
174 if (scalarType->getKind() == ScalarType::KIND_UINT16 ||
175 scalarType->getKind() == ScalarType::KIND_INT16) {
176 // HIDL uses a signed 16-bit char in Java for uint16_t and int16_t
177 // AIDL uses an unsigned 16-bit char/char16_t, so this is signed to unsigned.
178 out << "if (" << inputAccess << " < 0) {\n";
179 } else {
180 std::string affix = (scalarType->getKind() == ScalarType::KIND_UINT64) ? "L" : "";
181 std::string limit = (backend == AidlBackend::JAVA)
182 ? std::to_string(it->second.second) + affix
183 : it->second.first;
184 out << "if (" << inputAccess << " > " << limit << " || " << inputAccess
185 << " < 0) {\n";
186 }
187 if (backend == AidlBackend::JAVA) {
188 out.indent([&] {
189 out << "throw new RuntimeException(\"Unsafe conversion between signed and "
190 "unsigned scalars for field: "
191 << inputAccess << "\");\n";
192 });
193 } else {
194 out.indent([&] { out << "return false;\n"; });
195 }
196 out << "}\n";
197 }
198 }
199 }
200
wrapToString16(const std::string & payload,AidlBackend backend)201 static std::string wrapToString16(const std::string& payload, AidlBackend backend) {
202 if (backend == AidlBackend::CPP) {
203 return "String16(" + payload + ".c_str())";
204 } else {
205 return payload;
206 }
207 }
208
wrapStaticCast(const std::string & payload,const Type & type,const FQName & fqName,AidlBackend backend)209 static std::string wrapStaticCast(const std::string& payload, const Type& type,
210 const FQName& fqName, AidlBackend backend) {
211 static const std::map<std::string, std::string> kAidlBackendScalarTypes{
212 {"boolean", "bool"}, {"byte", "int8_t"}, {"char", "char16_t"}, {"int", "int32_t"},
213 {"long", "int64_t"}, {"float", "float"}, {"double", "double"}};
214 if (type.isEnum()) {
215 return "static_cast<" +
216 aidlTypePackage(static_cast<const android::NamedType&>(type), backend) + ">(" +
217 payload + ")";
218 }
219 const auto& it = kAidlBackendScalarTypes.find(AidlHelper::getAidlType(type, fqName));
220 if (it != kAidlBackendScalarTypes.end()) {
221 return "static_cast<" + it->second + ">(" + payload + ")";
222 } else {
223 return payload;
224 }
225 }
226
wrapCppSource(const std::string & payload,const Type & type,const FQName & fqName,AidlBackend backend)227 static std::string wrapCppSource(const std::string& payload, const Type& type, const FQName& fqName,
228 AidlBackend backend) {
229 if (type.isString()) {
230 return wrapToString16(payload, backend);
231 } else if (type.isBitField()) {
232 return wrapStaticCast(payload, *static_cast<const BitFieldType&>(type).getElementEnumType(),
233 fqName, backend);
234 } else {
235 return wrapStaticCast(payload, type, fqName, backend);
236 }
237 }
238
containerTranslation(Formatter & out,const FieldWithVersion & field,const CompoundType * parent,AidlBackend backend)239 static void containerTranslation(Formatter& out, const FieldWithVersion& field,
240 const CompoundType* parent, AidlBackend backend) {
241 const Type* elementType;
242 std::string javaSizeAccess;
243 std::string javaElementAccess;
244 std::string cppSize;
245 const std::string inputAccess = "in." + field.fullName +
246 (parent->style() == CompoundType::STYLE_SAFE_UNION ? "()" : "");
247 if (field.field->type().isArray()) {
248 auto fieldArray = static_cast<const ArrayType*>(field.field->get());
249 if (fieldArray->getConstantExpressions()[0]->castSizeT() == 0) {
250 // Nothing to translate for 0 sized arrays!
251 return;
252 }
253 elementType = fieldArray->getElementType();
254 javaSizeAccess = inputAccess + ".length";
255 javaElementAccess = "[i]";
256 cppSize = "sizeof(" + inputAccess + ")/sizeof(" + inputAccess + "[0])";
257 } else if (field.field->type().isVector()) {
258 elementType = static_cast<const VectorType*>(field.field->get())->getElementType();
259 javaSizeAccess = inputAccess + ".size()";
260 javaElementAccess = ".get(i)";
261 cppSize = inputAccess + ".size()";
262 } else {
263 LOG(FATAL) << "Unexpected container type for field: " << field.field->name();
264 return;
265 }
266 if (elementType->isArray() || elementType->isVector()) {
267 out << "#error Nested arrays and vectors are currently not supported. Needs implementation "
268 "for field: "
269 << field.field->name() << "\n";
270 return;
271 }
272 if (elementType->isNamedType() && !elementType->isEnum()) {
273 out << "#error Arrays of NamedTypes are not currently not supported. Needs implementation "
274 "for field: "
275 << field.field->name() << "\n";
276 return;
277 }
278 if (backend == AidlBackend::JAVA) {
279 out << "if (" << inputAccess << " != null) {\n";
280 out.indent([&] {
281 if (parent->style() == CompoundType::STYLE_SAFE_UNION) {
282 out << "out.set" << StringHelper::Capitalize(field.field->name()) << "(new "
283 << elementType->getJavaType(true) << "[" << javaSizeAccess << "]);\n";
284 } else {
285 out << "out." << field.field->name() << " = new " << elementType->getJavaType(true)
286 << "[" << javaSizeAccess << "];\n";
287 }
288 out << "for (int i = 0; i < " << javaSizeAccess << "; i++) {\n";
289 out.indent([&] {
290 h2aScalarChecks(out, *elementType, inputAccess + javaElementAccess, backend);
291 if (parent->style() == CompoundType::STYLE_SAFE_UNION) {
292 out << "out.get" << StringHelper::Capitalize(field.field->name()) << "()";
293 } else {
294 out << "out." << field.field->name();
295 }
296 out << "[i] = " << inputAccess << javaElementAccess << ";\n";
297 });
298 out << "}\n";
299 });
300 out << "}\n";
301 } else {
302 const std::string inputAccessElement = inputAccess + "[i]";
303 out << "{\n";
304 out.indent([&] {
305 if (parent->style() == CompoundType::STYLE_SAFE_UNION) {
306 out << "out->set<" << aidlTypePackage(*parent, backend)
307 << "::" << field.field->name() << ">();\n";
308 }
309 out << "size_t size = " << cppSize << ";\n";
310 out << "for (size_t i = 0; i < size; i++) {\n";
311 out.indent([&] {
312 h2aScalarChecks(out, *elementType, inputAccessElement, backend);
313 out << "out->";
314 if (parent->style() == CompoundType::STYLE_SAFE_UNION) {
315 out << "get<" << aidlTypePackage(*parent, backend)
316 << "::" << field.field->name() << ">()";
317 } else {
318 out << field.field->name();
319 }
320 // Arrays with explicit size use std::array instead of std::vector
321 if (field.field->type().isArray() &&
322 static_cast<const ArrayType*>(field.field->get())
323 ->getConstantExpressions()
324 .size() > 0) {
325 out << "[i] = "
326 << wrapCppSource(inputAccessElement, *elementType, parent->fqName(),
327 backend)
328 << ";\n";
329 } else {
330 out << ".push_back("
331 << wrapCppSource(inputAccessElement, *elementType, parent->fqName(),
332 backend)
333 << ");\n";
334 }
335 });
336 out << "}\n";
337 });
338 out << "}\n";
339 }
340 }
341
simpleTranslation(Formatter & out,const FieldWithVersion & field,const CompoundType * parent,AidlBackend backend)342 static void simpleTranslation(Formatter& out, const FieldWithVersion& field,
343 const CompoundType* parent, AidlBackend backend) {
344 std::string inputAccess = "in." + field.fullName;
345 if (backend == AidlBackend::JAVA) {
346 // HIDL uses short(signed) in the Java backend for uint16_t and int16_t
347 // AIDL uses char which is unsigned. This assignment needs a cast.
348 std::string cast;
349 if (AidlHelper::getAidlType(field.field->type(), parent->fqName()) == "char") {
350 cast = "(char) ";
351 }
352 if (parent->style() == CompoundType::STYLE_STRUCT) {
353 h2aScalarChecks(out, field.field->type(), inputAccess, backend);
354 out << "out." << field.field->name() << " = " << cast << inputAccess << ";\n";
355 } else {
356 inputAccess += "()";
357 h2aScalarChecks(out, field.field->type(), inputAccess, backend);
358 out << "out.set" << StringHelper::Capitalize(field.fullName) << "(" << cast
359 << inputAccess << ");\n";
360 }
361 } else {
362 if (parent->style() == CompoundType::STYLE_STRUCT) {
363 h2aScalarChecks(out, field.field->type(), inputAccess, backend);
364 out << "out->" << field.field->name() << " = "
365 << wrapCppSource("in." + field.fullName, field.field->type(), parent->fqName(),
366 backend)
367 << ";\n";
368 } else {
369 inputAccess += "()";
370 h2aScalarChecks(out, field.field->type(), inputAccess, backend);
371 out << "out->set<" << aidlTypePackage(*parent, backend) << "::" << field.fullName
372 << ">("
373 << wrapCppSource(inputAccess, field.field->type(), parent->fqName(), backend)
374 << ");\n";
375 }
376 }
377 }
378
h2aFieldTranslation(Formatter & out,const std::set<const NamedType * > & namedTypes,const CompoundType * parent,const FieldWithVersion & field,AidlBackend backend)379 static void h2aFieldTranslation(Formatter& out, const std::set<const NamedType*>& namedTypes,
380 const CompoundType* parent, const FieldWithVersion& field,
381 AidlBackend backend) {
382 if (field.field->type().isNamedType() && !field.field->type().isEnum()) {
383 namedTypeTranslation(out, namedTypes, field, parent, backend);
384 } else if (field.field->type().isArray() || field.field->type().isVector()) {
385 containerTranslation(out, field, parent, backend);
386 } else if (field.field->type().isEnum() || field.field->type().isScalar() ||
387 field.field->type().isString() || field.field->type().isBitField()) {
388 simpleTranslation(out, field, parent, backend);
389 } else {
390 AidlHelper::notes() << "An unhandled type was found in translation: "
391 << field.field->type().typeName() << "\n";
392 out << "#error FIXME Unhandled type: " << field.field->type().typeName() << "\n";
393 }
394 }
395
declareAidlFunctionSignature(const NamedType * type,AidlBackend backend)396 static const std::string declareAidlFunctionSignature(const NamedType* type, AidlBackend backend) {
397 if (backend == AidlBackend::JAVA) {
398 return "static public " + aidlTypePackage(*type, backend) + " h2aTranslate(" +
399 type->fullJavaName() + " in)";
400 } else {
401 return "__attribute__((warn_unused_result)) bool translate(const " + type->fullName() +
402 "& in, " + aidlTypePackage(*type, backend) + "* out)";
403 }
404 }
405
getHidlPackagePath(const NamedType * type)406 static const std::string getHidlPackagePath(const NamedType* type) {
407 return base::Join(base::Split(type->fqName().package(), "."), "/");
408 }
409
getParentInterface(const NamedType * type)410 static std::optional<const Interface*> getParentInterface(const NamedType* type) {
411 const Scope* parent = type->parent();
412 while (parent != nullptr) {
413 if (parent->definesInterfaces()) {
414 return parent->getInterface();
415 }
416 parent = parent->parent();
417 }
418 return std::nullopt;
419 }
420
hidlIncludeFile(const NamedType * type)421 static const std::string hidlIncludeFile(const NamedType* type) {
422 std::optional<const Interface*> parent = getParentInterface(type);
423 if (parent) {
424 return "#include \"" + getHidlPackagePath(type) + "/" + type->fqName().version() + "/" +
425 parent.value()->fqName().getInterfaceName() + ".h\"\n";
426 } else {
427 return "#include \"" + getHidlPackagePath(type) + "/" + type->fqName().version() +
428 "/types.h\"\n";
429 }
430 }
431
aidlIncludeFile(const NamedType * type,AidlBackend backend)432 static const std::string aidlIncludeFile(const NamedType* type, AidlBackend backend) {
433 const std::string prefix = (backend == AidlBackend::NDK) ? "aidl/" : std::string();
434 return "#include \"" + prefix + AidlHelper::getAidlPackagePath(type->fqName()) + "/" +
435 AidlHelper::getAidlType(*type, type->fqName()) + ".h\"\n";
436 }
437
emitCppTranslateHeader(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes,AidlBackend backend)438 static void emitCppTranslateHeader(
439 const Coordinator& coordinator, const FQName& fqName,
440 const std::set<const NamedType*>& namedTypes,
441 const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes,
442 AidlBackend backend) {
443 CHECK(backend == AidlBackend::CPP || backend == AidlBackend::NDK);
444 Formatter out =
445 coordinator.getFormatter(fqName, Coordinator::Location::DIRECT,
446 "include/" + AidlHelper::translateHeaderFile(fqName, backend));
447
448 AidlHelper::emitFileHeader(out);
449 out << "// FIXME Remove this file if you don't need to translate types in this backend.\n\n";
450 out << "#pragma once\n\n";
451
452 std::set<std::string> includes = {"#include <limits>"};
453 for (const auto& type : namedTypes) {
454 const auto& it = processedTypes.find(type);
455 if (it == processedTypes.end() && !type->isEnum()) {
456 continue;
457 }
458 includes.insert(aidlIncludeFile(AidlHelper::getTopLevelType(type), backend));
459 includes.insert(hidlIncludeFile(type));
460 }
461 out << base::Join(includes, "") << "\n\n";
462
463 out << "namespace android::h2a {\n\n";
464 for (const auto& type : namedTypes) {
465 const auto& it = processedTypes.find(type);
466 if (it == processedTypes.end()) {
467 continue;
468 }
469 out << declareAidlFunctionSignature(type, backend) << ";\n";
470 }
471 out << "\n} // namespace android::h2a\n";
472 }
473
emitTranslateSource(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes,AidlBackend backend)474 static void emitTranslateSource(
475 const Coordinator& coordinator, const FQName& fqName,
476 const std::set<const NamedType*>& namedTypes,
477 const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes,
478 AidlBackend backend) {
479 Formatter out = coordinator.getFormatter(fqName, Coordinator::Location::DIRECT,
480 AidlHelper::translateSourceFile(fqName, backend));
481 AidlHelper::emitFileHeader(out);
482 out << "// FIXME Remove this file if you don't need to translate types in this backend.\n\n";
483 if (backend == AidlBackend::JAVA) {
484 out << "package " << AidlHelper::getAidlPackage(fqName) + ";\n\n";
485 out << "public class Translate {\n";
486 } else {
487 out << "#include \""
488 << AidlHelper::translateHeaderFile((*namedTypes.begin())->fqName(), backend) + "\"\n\n";
489 out << "namespace android::h2a {\n\n";
490 emitStaticAsserts(out, namedTypes, backend);
491 }
492 for (const auto& type : namedTypes) {
493 const auto& it = processedTypes.find(type);
494 if (it == processedTypes.end()) {
495 continue;
496 }
497 CHECK(type->isCompoundType()) << "Unexpected type: " << type->fqName().string();
498 const CompoundType* compound = static_cast<const CompoundType*>(type);
499
500 if (compound->style() == CompoundType::STYLE_UNION) {
501 // HIDL Java backend doesn't support union so don't add a comment.
502 if (backend != AidlBackend::JAVA) {
503 out << "// FIXME not enough information to safely convert. Remove this function or "
504 "fill it out using the custom discriminators.\n";
505 out << "// " << declareAidlFunctionSignature(type, backend) << "\n\n";
506 }
507 continue;
508 }
509
510 out << declareAidlFunctionSignature(type, backend) << " {\n";
511 if (compound->style() == CompoundType::STYLE_SAFE_UNION) {
512 out.indent([&] {
513 if (backend == AidlBackend::JAVA) {
514 out << aidlTypePackage(*type, backend) << " out = new "
515 << aidlTypePackage(*type, backend) << "();\n";
516 }
517 out << "switch (in.getDiscriminator()) {\n";
518 out.indent([&] {
519 const ProcessedCompoundType& processedType = it->second;
520 for (const auto& field : processedType.fields) {
521 if (backend == AidlBackend::JAVA) {
522 out << "case " << compound->fullJavaName() << ".hidl_discriminator."
523 << field.field->name() << ":\n";
524 } else {
525 out << "case " << compound->fullName()
526 << "::hidl_discriminator::" << field.field->name() << ":\n";
527 }
528 out.indent([&] {
529 h2aFieldTranslation(out, namedTypes, compound, field, backend);
530 out << "break;\n";
531 });
532 }
533 out << "default:\n";
534 if (backend == AidlBackend::JAVA) {
535 out.indent([&] {
536 out << "throw new RuntimeException(\"Unknown discriminator value: \" + "
537 "Integer.toString(in.getDiscriminator()));\n";
538 });
539 } else {
540 out.indent([&] { out << "return false;\n"; });
541 }
542 });
543 out << "}\n";
544 });
545 } else {
546 out.indent([&] {
547 if (backend == AidlBackend::JAVA) {
548 out << aidlTypePackage(*type, backend) << " out = new "
549 << aidlTypePackage(*type, backend) << "();\n";
550 }
551 const ProcessedCompoundType& processedType = it->second;
552 for (const auto& field : processedType.fields) {
553 h2aFieldTranslation(out, namedTypes, compound, field, backend);
554 }
555 });
556 }
557 if (backend == AidlBackend::JAVA) {
558 out.indent([&] { out << "return out;\n"; });
559 } else {
560 out.indent([&] { out << "return true;\n"; });
561 }
562 out << "}\n\n";
563 }
564 if (backend == AidlBackend::JAVA) {
565 out << "}";
566 } else {
567 out << "} // namespace android::h2a";
568 }
569 }
570
emitTranslation(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes)571 void AidlHelper::emitTranslation(
572 const Coordinator& coordinator, const FQName& fqName,
573 const std::set<const NamedType*>& namedTypes,
574 const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes) {
575 if (processedTypes.empty()) return;
576 for (auto backend : {AidlBackend::NDK, AidlBackend::CPP, AidlBackend::JAVA}) {
577 if (backend != AidlBackend::JAVA) {
578 emitCppTranslateHeader(coordinator, fqName, namedTypes, processedTypes, backend);
579 }
580 emitTranslateSource(coordinator, fqName, namedTypes, processedTypes, backend);
581 }
582 }
583
584 } // namespace android
585