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