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 AidlHelper::getAidlPackagePath(fqName) + "/translate-ndk.cpp";
57         case AidlBackend::CPP:
58             return AidlHelper::getAidlPackagePath(fqName) + "/translate-cpp.cpp";
59         case AidlBackend::JAVA:
60             return 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());
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     if (field.field->type().isArray()) {
246         elementType = static_cast<const ArrayType*>(field.field->get())->getElementType();
247         javaSizeAccess = ".length";
248         javaElementAccess = "[i]";
249         cppSize = "sizeof(in." + field.fullName + ")/sizeof(in." + field.fullName + "[0])";
250     } else if (field.field->type().isVector()) {
251         elementType = static_cast<const VectorType*>(field.field->get())->getElementType();
252         javaSizeAccess = ".size()";
253         javaElementAccess = ".get(i)";
254         cppSize = "in." + field.fullName + ".size()";
255     } else {
256         LOG(FATAL) << "Unexpected container type for field: " << field.field->name();
257         return;
258     }
259     if (elementType->isArray() || elementType->isVector()) {
260         out << "#error Nested arrays and vectors are currently not supported. Needs implementation "
261                "for field: "
262             << field.field->name() << "\n";
263         return;
264     }
265     if (elementType->isNamedType() && !elementType->isEnum()) {
266         out << "#error Arrays of NamedTypes are not currently not supported. Needs implementation "
267                "for field: "
268             << field.field->name() << "\n";
269         return;
270     }
271     if (backend == AidlBackend::JAVA) {
272         const std::string inputAccess = "in." + field.fullName;
273         out << "if (" << inputAccess << " != null) {\n";
274         out.indent([&] {
275             out << "out." << field.field->name() << " = new " << elementType->getJavaType(true)
276                 << "[" << inputAccess << javaSizeAccess << "];\n";
277             out << "for (int i = 0; i < " << inputAccess << javaSizeAccess << "; i++) {\n";
278             out.indent([&] {
279                 h2aScalarChecks(out, *elementType, inputAccess + javaElementAccess, backend);
280                 out << "out." << field.field->name() << "[i] = " << inputAccess << javaElementAccess
281                     << ";\n";
282             });
283             out << "}\n";
284         });
285         out << "}\n";
286     } else {
287         const std::string inputAccessElement = "in." + field.fullName + "[i]";
288         out << "{\n";
289         out.indent([&] {
290             out << "size_t size = " << cppSize << ";\n";
291             out << "for (size_t i = 0; i < size; i++) {\n";
292             out.indent([&] {
293                 h2aScalarChecks(out, *elementType, inputAccessElement, backend);
294                 out << "out->" << field.field->name() << ".push_back("
295                     << wrapCppSource(inputAccessElement, *elementType, parent->fqName(), backend)
296                     << ");\n";
297             });
298             out << "}\n";
299         });
300         out << "}\n";
301     }
302 }
303 
simpleTranslation(Formatter & out,const FieldWithVersion & field,const CompoundType * parent,AidlBackend backend)304 static void simpleTranslation(Formatter& out, const FieldWithVersion& field,
305                               const CompoundType* parent, AidlBackend backend) {
306     std::string inputAccess = "in." + field.fullName;
307     if (backend == AidlBackend::JAVA) {
308         // HIDL uses short(signed) in the Java backend for uint16_t and int16_t
309         // AIDL uses char which is unsigned. This assignment needs a cast.
310         std::string cast;
311         if (AidlHelper::getAidlType(field.field->type(), parent->fqName()) == "char") {
312             cast = "(char) ";
313         }
314         if (parent->style() == CompoundType::STYLE_STRUCT) {
315             h2aScalarChecks(out, field.field->type(), inputAccess, backend);
316             out << "out." << field.field->name() << " = " << cast << inputAccess << ";\n";
317         } else {
318             inputAccess += "()";
319             h2aScalarChecks(out, field.field->type(), inputAccess, backend);
320             out << "out.set" << StringHelper::Capitalize(field.fullName) << "(" << cast
321                 << inputAccess << ");\n";
322         }
323     } else {
324         if (parent->style() == CompoundType::STYLE_STRUCT) {
325             h2aScalarChecks(out, field.field->type(), inputAccess, backend);
326             out << "out->" << field.field->name() << " = "
327                 << wrapCppSource("in." + field.fullName, field.field->type(), parent->fqName(),
328                                  backend)
329                 << ";\n";
330         } else {
331             inputAccess += "()";
332             h2aScalarChecks(out, field.field->type(), inputAccess, backend);
333             out << "*out = "
334                 << wrapCppSource(inputAccess, field.field->type(), parent->fqName(), backend)
335                 << ";\n";
336         }
337     }
338 }
339 
h2aFieldTranslation(Formatter & out,const std::set<const NamedType * > & namedTypes,const CompoundType * parent,const FieldWithVersion & field,AidlBackend backend)340 static void h2aFieldTranslation(Formatter& out, const std::set<const NamedType*>& namedTypes,
341                                 const CompoundType* parent, const FieldWithVersion& field,
342                                 AidlBackend backend) {
343     if (field.field->type().isNamedType() && !field.field->type().isEnum()) {
344         namedTypeTranslation(out, namedTypes, field, parent, backend);
345     } else if (field.field->type().isArray() || field.field->type().isVector()) {
346         containerTranslation(out, field, parent, backend);
347     } else if (field.field->type().isEnum() || field.field->type().isScalar() ||
348                field.field->type().isString() || field.field->type().isBitField()) {
349         simpleTranslation(out, field, parent, backend);
350     } else {
351         AidlHelper::notes() << "An unhandled type was found in translation: "
352                             << field.field->type().typeName() << "\n";
353         out << "#error FIXME Unhandled type: " << field.field->type().typeName() << "\n";
354     }
355 }
356 
declareAidlFunctionSignature(const NamedType * type,AidlBackend backend)357 static const std::string declareAidlFunctionSignature(const NamedType* type, AidlBackend backend) {
358     if (backend == AidlBackend::JAVA) {
359         return "static public " + aidlTypePackage(*type, backend) + " h2aTranslate(" +
360                type->fullJavaName() + " in)";
361     } else {
362         return "__attribute__((warn_unused_result)) bool translate(const " + type->fullName() +
363                "& in, " + aidlTypePackage(*type, backend) + "* out)";
364     }
365 }
366 
getHidlPackagePath(const NamedType * type)367 static const std::string getHidlPackagePath(const NamedType* type) {
368     return base::Join(base::Split(type->fqName().package(), "."), "/");
369 }
370 
getParentInterface(const NamedType * type)371 static std::optional<const Interface*> getParentInterface(const NamedType* type) {
372     const Scope* parent = type->parent();
373     while (parent != nullptr) {
374         if (parent->definesInterfaces()) {
375             return parent->getInterface();
376         }
377         parent = parent->parent();
378     }
379     return std::nullopt;
380 }
381 
hidlIncludeFile(const NamedType * type)382 static const std::string hidlIncludeFile(const NamedType* type) {
383     std::optional<const Interface*> parent = getParentInterface(type);
384     if (parent) {
385         return "#include \"" + getHidlPackagePath(type) + "/" + type->fqName().version() + "/" +
386                parent.value()->fqName().getInterfaceName() + ".h\"\n";
387     } else {
388         return "#include \"" + getHidlPackagePath(type) + "/" + type->fqName().version() +
389                "/types.h\"\n";
390     }
391 }
392 
aidlIncludeFile(const NamedType * type,AidlBackend backend)393 static const std::string aidlIncludeFile(const NamedType* type, AidlBackend backend) {
394     const std::string prefix = (backend == AidlBackend::NDK) ? "aidl/" : std::string();
395     return "#include \"" + prefix + AidlHelper::getAidlPackagePath(type->fqName()) + "/" +
396            AidlHelper::getAidlType(*type, type->fqName()) + ".h\"\n";
397 }
398 
emitCppTranslateHeader(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes,AidlBackend backend)399 static void emitCppTranslateHeader(
400         const Coordinator& coordinator, const FQName& fqName,
401         const std::set<const NamedType*>& namedTypes,
402         const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes,
403         AidlBackend backend) {
404     CHECK(backend == AidlBackend::CPP || backend == AidlBackend::NDK);
405     Formatter out =
406             coordinator.getFormatter(fqName, Coordinator::Location::DIRECT,
407                                      "include/" + AidlHelper::translateHeaderFile(fqName, backend));
408 
409     AidlHelper::emitFileHeader(out);
410     out << "// FIXME Remove this file if you don't need to translate types in this backend.\n\n";
411     out << "#pragma once\n\n";
412 
413     std::set<std::string> includes = {"#include <limits>"};
414     for (const auto& type : namedTypes) {
415         const auto& it = processedTypes.find(type);
416         if (it == processedTypes.end() && !type->isEnum()) {
417             continue;
418         }
419         includes.insert(aidlIncludeFile(type, backend));
420         includes.insert(hidlIncludeFile(type));
421     }
422     out << base::Join(includes, "") << "\n\n";
423 
424     out << "namespace android::h2a {\n\n";
425     for (const auto& type : namedTypes) {
426         const auto& it = processedTypes.find(type);
427         if (it == processedTypes.end()) {
428             continue;
429         }
430         out << declareAidlFunctionSignature(type, backend) << ";\n";
431     }
432     out << "\n}  // namespace android::h2a\n";
433 }
434 
emitTranslateSource(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes,AidlBackend backend)435 static void emitTranslateSource(
436         const Coordinator& coordinator, const FQName& fqName,
437         const std::set<const NamedType*>& namedTypes,
438         const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes,
439         AidlBackend backend) {
440     Formatter out = coordinator.getFormatter(fqName, Coordinator::Location::DIRECT,
441                                              AidlHelper::translateSourceFile(fqName, backend));
442     AidlHelper::emitFileHeader(out);
443     out << "// FIXME Remove this file if you don't need to translate types in this backend.\n\n";
444     if (backend == AidlBackend::JAVA) {
445         out << "package " << AidlHelper::getAidlPackage(fqName) + ";\n\n";
446         out << "public class Translate {\n";
447     } else {
448         out << "#include \""
449             << AidlHelper::translateHeaderFile((*namedTypes.begin())->fqName(), backend) + "\"\n\n";
450         out << "namespace android::h2a {\n\n";
451         emitStaticAsserts(out, namedTypes, backend);
452     }
453     for (const auto& type : namedTypes) {
454         const auto& it = processedTypes.find(type);
455         if (it == processedTypes.end()) {
456             continue;
457         }
458         CHECK(type->isCompoundType()) << "Unexpected type: " << type->fqName().string();
459         const CompoundType* compound = static_cast<const CompoundType*>(type);
460 
461         if (compound->style() == CompoundType::STYLE_UNION) {
462             // HIDL Java backend doesn't support union so don't add a comment.
463             if (backend != AidlBackend::JAVA) {
464                 out << "// FIXME not enough information to safely convert. Remove this function or "
465                        "fill it out using the custom discriminators.\n";
466                 out << "// " << declareAidlFunctionSignature(type, backend) << "\n\n";
467             }
468             continue;
469         }
470 
471         out << declareAidlFunctionSignature(type, backend) << " {\n";
472         if (compound->style() == CompoundType::STYLE_SAFE_UNION) {
473             out.indent([&] {
474                 if (backend == AidlBackend::JAVA) {
475                     out << aidlTypePackage(*type, backend) << " out = new "
476                         << aidlTypePackage(*type, backend) << "();\n";
477                 }
478                 out << "switch (in.getDiscriminator()) {\n";
479                 out.indent([&] {
480                     const ProcessedCompoundType& processedType = it->second;
481                     for (const auto& field : processedType.fields) {
482                         if (backend == AidlBackend::JAVA) {
483                             out << "case " << compound->fullJavaName() << ".hidl_discriminator."
484                                 << field.field->name() << ":\n";
485                         } else {
486                             out << "case " << compound->fullName()
487                                 << "::hidl_discriminator::" << field.field->name() << ":\n";
488                         }
489                         out.indent([&] {
490                             h2aFieldTranslation(out, namedTypes, compound, field, backend);
491                             out << "break;\n";
492                         });
493                     }
494                     out << "default:\n";
495                     if (backend == AidlBackend::JAVA) {
496                         out.indent([&] {
497                             out << "throw new RuntimeException(\"Unknown discriminator value: \" + "
498                                    "Integer.toString(in.getDiscriminator()));\n";
499                         });
500                     } else {
501                         out.indent([&] { out << "return false;\n"; });
502                     }
503                 });
504                 out << "}\n";
505             });
506         } else {
507             out.indent([&] {
508                 if (backend == AidlBackend::JAVA) {
509                     out << aidlTypePackage(*type, backend) << " out = new "
510                         << aidlTypePackage(*type, backend) << "();\n";
511                 }
512                 const ProcessedCompoundType& processedType = it->second;
513                 for (const auto& field : processedType.fields) {
514                     h2aFieldTranslation(out, namedTypes, compound, field, backend);
515                 }
516             });
517         }
518         if (backend == AidlBackend::JAVA) {
519             out.indent([&] { out << "return out;\n"; });
520         } else {
521             out.indent([&] { out << "return true;\n"; });
522         }
523         out << "}\n\n";
524     }
525     if (backend == AidlBackend::JAVA) {
526         out << "}";
527     } else {
528         out << "}  // namespace android::h2a";
529     }
530 }
531 
emitTranslation(const Coordinator & coordinator,const FQName & fqName,const std::set<const NamedType * > & namedTypes,const std::map<const NamedType *,const ProcessedCompoundType> & processedTypes)532 void AidlHelper::emitTranslation(
533         const Coordinator& coordinator, const FQName& fqName,
534         const std::set<const NamedType*>& namedTypes,
535         const std::map<const NamedType*, const ProcessedCompoundType>& processedTypes) {
536     if (processedTypes.empty()) return;
537     for (auto backend : {AidlBackend::NDK, AidlBackend::CPP, AidlBackend::JAVA}) {
538         if (backend != AidlBackend::JAVA) {
539             emitCppTranslateHeader(coordinator, fqName, namedTypes, processedTypes, backend);
540         }
541         emitTranslateSource(coordinator, fqName, namedTypes, processedTypes, backend);
542     }
543 }
544 
545 }  // namespace android
546