1 /*
2  * Copyright (C) 2018, 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 "generate_ndk.h"
18 
19 #include "aidl.h"
20 #include "aidl_language.h"
21 #include "aidl_to_cpp_common.h"
22 #include "aidl_to_ndk.h"
23 #include "logging.h"
24 
25 namespace android {
26 namespace aidl {
27 namespace ndk {
28 
29 static constexpr const char* kClazz = "_g_aidl_clazz";
30 static constexpr const char* kDescriptor = "descriptor";
31 static constexpr const char* kVersion = "version";
32 static constexpr const char* kHash = "hash";
33 static constexpr const char* kCachedVersion = "_aidl_cached_version";
34 static constexpr const char* kCachedHash = "_aidl_cached_hash";
35 static constexpr const char* kCachedHashMutex = "_aidl_cached_hash_mutex";
36 
37 using namespace internals;
38 using cpp::ClassNames;
39 
GenerateNdkInterface(const string & output_file,const Options & options,const AidlTypenames & types,const AidlInterface & defined_type,const IoDelegate & io_delegate)40 void GenerateNdkInterface(const string& output_file, const Options& options,
41                           const AidlTypenames& types, const AidlInterface& defined_type,
42                           const IoDelegate& io_delegate) {
43   const string i_header = options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::RAW);
44   unique_ptr<CodeWriter> i_writer(io_delegate.GetCodeWriter(i_header));
45   GenerateInterfaceHeader(*i_writer, types, defined_type, options);
46   CHECK(i_writer->Close());
47 
48   const string bp_header =
49       options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::CLIENT);
50   unique_ptr<CodeWriter> bp_writer(io_delegate.GetCodeWriter(bp_header));
51   GenerateClientHeader(*bp_writer, types, defined_type, options);
52   CHECK(bp_writer->Close());
53 
54   const string bn_header =
55       options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::SERVER);
56   unique_ptr<CodeWriter> bn_writer(io_delegate.GetCodeWriter(bn_header));
57   GenerateServerHeader(*bn_writer, types, defined_type, options);
58   CHECK(bn_writer->Close());
59 
60   unique_ptr<CodeWriter> source_writer = io_delegate.GetCodeWriter(output_file);
61   GenerateSource(*source_writer, types, defined_type, options);
62   CHECK(source_writer->Close());
63 }
64 
GenerateNdkParcel(const string & output_file,const Options & options,const AidlTypenames & types,const AidlStructuredParcelable & defined_type,const IoDelegate & io_delegate)65 void GenerateNdkParcel(const string& output_file, const Options& options,
66                        const AidlTypenames& types, const AidlStructuredParcelable& defined_type,
67                        const IoDelegate& io_delegate) {
68   const string header_path =
69       options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::RAW);
70   unique_ptr<CodeWriter> header_writer(io_delegate.GetCodeWriter(header_path));
71   GenerateParcelHeader(*header_writer, types, defined_type, options);
72   CHECK(header_writer->Close());
73 
74   const string bp_header =
75       options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::CLIENT);
76   unique_ptr<CodeWriter> bp_writer(io_delegate.GetCodeWriter(bp_header));
77   *bp_writer << "#error TODO(b/111362593) defined_types do not have bp classes\n";
78   CHECK(bp_writer->Close());
79 
80   const string bn_header =
81       options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::SERVER);
82   unique_ptr<CodeWriter> bn_writer(io_delegate.GetCodeWriter(bn_header));
83   *bn_writer << "#error TODO(b/111362593) defined_types do not have bn classes\n";
84   CHECK(bn_writer->Close());
85 
86   unique_ptr<CodeWriter> source_writer = io_delegate.GetCodeWriter(output_file);
87   GenerateParcelSource(*source_writer, types, defined_type, options);
88   CHECK(source_writer->Close());
89 }
90 
GenerateNdkParcelDeclaration(const std::string & filename,const IoDelegate & io_delegate)91 void GenerateNdkParcelDeclaration(const std::string& filename, const IoDelegate& io_delegate) {
92   CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
93   *code_writer
94       << "// This file is intentionally left blank as placeholder for parcel declaration.\n";
95   CHECK(code_writer->Close());
96 }
97 
GenerateNdkEnumDeclaration(const string & output_file,const Options & options,const AidlTypenames & types,const AidlEnumDeclaration & defined_type,const IoDelegate & io_delegate)98 void GenerateNdkEnumDeclaration(const string& output_file, const Options& options,
99                                 const AidlTypenames& types, const AidlEnumDeclaration& defined_type,
100                                 const IoDelegate& io_delegate) {
101   const string header_path =
102       options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::RAW);
103   unique_ptr<CodeWriter> header_writer(io_delegate.GetCodeWriter(header_path));
104   GenerateEnumHeader(*header_writer, types, defined_type, options);
105   CHECK(header_writer->Close());
106 
107   const string bp_header =
108       options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::CLIENT);
109   unique_ptr<CodeWriter> bp_writer(io_delegate.GetCodeWriter(bp_header));
110   *bp_writer << "#error TODO(b/111362593) enums do not have bp classes\n";
111   CHECK(bp_writer->Close());
112 
113   const string bn_header =
114       options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::SERVER);
115   unique_ptr<CodeWriter> bn_writer(io_delegate.GetCodeWriter(bn_header));
116   *bn_writer << "#error TODO(b/111362593) enums do not have bn classes\n";
117   CHECK(bn_writer->Close());
118 
119   unique_ptr<CodeWriter> source_writer = io_delegate.GetCodeWriter(output_file);
120   *source_writer
121       << "// This file is intentionally left blank as placeholder for enum declaration.\n";
122   CHECK(source_writer->Close());
123 }
124 
GenerateNdk(const string & output_file,const Options & options,const AidlTypenames & types,const AidlDefinedType & defined_type,const IoDelegate & io_delegate)125 void GenerateNdk(const string& output_file, const Options& options, const AidlTypenames& types,
126                  const AidlDefinedType& defined_type, const IoDelegate& io_delegate) {
127   if (const AidlStructuredParcelable* parcelable = defined_type.AsStructuredParcelable();
128       parcelable != nullptr) {
129     GenerateNdkParcel(output_file, options, types, *parcelable, io_delegate);
130     return;
131   }
132 
133   if (const AidlParcelable* parcelable_decl = defined_type.AsParcelable();
134       parcelable_decl != nullptr) {
135     GenerateNdkParcelDeclaration(output_file, io_delegate);
136     return;
137   }
138 
139   if (const AidlEnumDeclaration* enum_decl = defined_type.AsEnumDeclaration();
140       enum_decl != nullptr) {
141     GenerateNdkEnumDeclaration(output_file, options, types, *enum_decl, io_delegate);
142     return;
143   }
144 
145   if (const AidlInterface* interface = defined_type.AsInterface(); interface != nullptr) {
146     GenerateNdkInterface(output_file, options, types, *interface, io_delegate);
147     return;
148   }
149 
150   CHECK(false) << "Unrecognized type sent for NDK cpp generation.";
151 }
152 namespace internals {
153 
EnterNdkNamespace(CodeWriter & out,const AidlDefinedType & defined_type)154 void EnterNdkNamespace(CodeWriter& out, const AidlDefinedType& defined_type) {
155   out << "namespace aidl {\n";
156   cpp::EnterNamespace(out, defined_type);
157 }
LeaveNdkNamespace(CodeWriter & out,const AidlDefinedType & defined_type)158 void LeaveNdkNamespace(CodeWriter& out, const AidlDefinedType& defined_type) {
159   cpp::LeaveNamespace(out, defined_type);
160   out << "}  // namespace aidl\n";
161 }
162 
StatusCheckGoto(CodeWriter & out)163 static void StatusCheckGoto(CodeWriter& out) {
164   out << "if (_aidl_ret_status != STATUS_OK) goto _aidl_error;\n\n";
165 }
StatusCheckBreak(CodeWriter & out)166 static void StatusCheckBreak(CodeWriter& out) {
167   out << "if (_aidl_ret_status != STATUS_OK) break;\n\n";
168 }
StatusCheckReturn(CodeWriter & out)169 static void StatusCheckReturn(CodeWriter& out) {
170   out << "if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;\n\n";
171 }
172 
GenerateHeaderIncludes(CodeWriter & out,const AidlTypenames & types,const AidlDefinedType & defined_type)173 static void GenerateHeaderIncludes(CodeWriter& out, const AidlTypenames& types,
174                                    const AidlDefinedType& defined_type) {
175   out << "#include <cstdint>\n";
176   out << "#include <memory>\n";
177   out << "#include <optional>\n";
178   out << "#include <string>\n";
179   out << "#include <vector>\n";
180   out << "#ifdef BINDER_STABILITY_SUPPORT\n";
181   out << "#include <android/binder_stability.h>\n";
182   out << "#endif  // BINDER_STABILITY_SUPPORT\n";
183 
184   auto headerFilePath = [&types](const AidlTypeSpecifier& typespec) -> std::string {
185     const AidlDefinedType* type = types.TryGetDefinedType(typespec.GetName());
186     if (type == nullptr) {
187       // could be a primitive type.
188       return "";
189     }
190 
191     if (type->AsInterface() != nullptr) {
192       return NdkHeaderFile(*type, ClassNames::RAW, false /*use_os_sep*/);
193     } else if (type->AsStructuredParcelable() != nullptr) {
194       return NdkHeaderFile(*type, ClassNames::RAW, false /*use_os_sep*/);
195     } else if (type->AsParcelable() != nullptr) {
196       return type->AsParcelable()->GetCppHeader();
197     } else if (type->AsEnumDeclaration() != nullptr) {
198       return NdkHeaderFile(*type, ClassNames::RAW, false /*use_os_sep*/);
199     } else {
200       AIDL_FATAL(*type) << "Unrecognized type.";
201       return "";
202     }
203   };
204 
205   std::set<std::string> includes;
206 
207   const AidlInterface* interface = defined_type.AsInterface();
208   if (interface != nullptr) {
209     for (const auto& method : interface->GetMethods()) {
210       includes.insert(headerFilePath(method->GetType()));
211       for (const auto& argument : method->GetArguments()) {
212         includes.insert(headerFilePath(argument->GetType()));
213       }
214     }
215   }
216 
217   const AidlStructuredParcelable* parcelable = defined_type.AsStructuredParcelable();
218   if (parcelable != nullptr) {
219     for (const auto& field : parcelable->GetFields()) {
220       includes.insert(headerFilePath(field->GetType()));
221     }
222   }
223 
224   const AidlEnumDeclaration* enum_decl = defined_type.AsEnumDeclaration();
225   if (enum_decl != nullptr) {
226     includes.insert(headerFilePath(enum_decl->GetBackingType()));
227   }
228 
229   for (const auto& path : includes) {
230     if (path == "") {
231       continue;
232     }
233     out << "#include <" << path << ">\n";
234   }
235 }
236 
GenerateSourceIncludes(CodeWriter & out,const AidlTypenames & types,const AidlDefinedType &)237 static void GenerateSourceIncludes(CodeWriter& out, const AidlTypenames& types,
238                                    const AidlDefinedType& /*defined_type*/) {
239   out << "#include <android/binder_parcel_utils.h>\n";
240 
241   types.IterateTypes([&](const AidlDefinedType& a_defined_type) {
242     if (a_defined_type.AsInterface() != nullptr) {
243       out << "#include <" << NdkHeaderFile(a_defined_type, ClassNames::CLIENT, false /*use_os_sep*/)
244           << ">\n";
245       out << "#include <" << NdkHeaderFile(a_defined_type, ClassNames::SERVER, false /*use_os_sep*/)
246           << ">\n";
247       out << "#include <" << NdkHeaderFile(a_defined_type, ClassNames::RAW, false /*use_os_sep*/)
248           << ">\n";
249     }
250   });
251 }
252 
GenerateConstantDeclarations(CodeWriter & out,const AidlInterface & interface)253 static void GenerateConstantDeclarations(CodeWriter& out, const AidlInterface& interface) {
254   for (const auto& constant : interface.GetConstantDeclarations()) {
255     const AidlConstantValue& value = constant->GetValue();
256     CHECK(value.GetType() != AidlConstantValue::Type::UNARY &&
257           value.GetType() != AidlConstantValue::Type::BINARY);
258     if (value.GetType() == AidlConstantValue::Type::STRING) {
259       out << "static const char* " << constant->GetName() << ";\n";
260     }
261   }
262   out << "\n";
263 
264   bool hasIntegralConstant = false;
265   for (const auto& constant : interface.GetConstantDeclarations()) {
266     const AidlConstantValue& value = constant->GetValue();
267     CHECK(value.GetType() != AidlConstantValue::Type::UNARY &&
268           value.GetType() != AidlConstantValue::Type::BINARY);
269     if (value.GetType() == AidlConstantValue::Type::BOOLEAN ||
270         value.GetType() == AidlConstantValue::Type::INT8 ||
271         value.GetType() == AidlConstantValue::Type::INT32) {
272       hasIntegralConstant = true;
273       break;
274     }
275   }
276 
277   if (hasIntegralConstant) {
278     out << "enum : int32_t {\n";
279     out.Indent();
280     for (const auto& constant : interface.GetConstantDeclarations()) {
281       const AidlConstantValue& value = constant->GetValue();
282       if (value.GetType() == AidlConstantValue::Type::BOOLEAN ||
283           value.GetType() == AidlConstantValue::Type::INT8 ||
284           value.GetType() == AidlConstantValue::Type::INT32) {
285         out << constant->GetName() << " = " << constant->ValueString(ConstantValueDecorator)
286             << ",\n";
287       }
288     }
289     out.Dedent();
290     out << "};\n";
291   }
292 }
GenerateConstantDefinitions(CodeWriter & out,const AidlInterface & interface)293 static void GenerateConstantDefinitions(CodeWriter& out, const AidlInterface& interface) {
294   const std::string clazz = ClassName(interface, ClassNames::INTERFACE);
295 
296   for (const auto& constant : interface.GetConstantDeclarations()) {
297     const AidlConstantValue& value = constant->GetValue();
298     CHECK(value.GetType() != AidlConstantValue::Type::UNARY &&
299           value.GetType() != AidlConstantValue::Type::BINARY);
300     if (value.GetType() == AidlConstantValue::Type::STRING) {
301       out << "const char* " << clazz << "::" << constant->GetName() << " = "
302           << constant->ValueString(ConstantValueDecorator) << ";\n";
303     }
304   }
305 }
306 
GenerateSource(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const Options & options)307 void GenerateSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type,
308                     const Options& options) {
309   GenerateSourceIncludes(out, types, defined_type);
310   out << "\n";
311 
312   EnterNdkNamespace(out, defined_type);
313   GenerateClassSource(out, types, defined_type, options);
314   GenerateClientSource(out, types, defined_type, options);
315   GenerateServerSource(out, types, defined_type, options);
316   GenerateInterfaceSource(out, types, defined_type, options);
317   LeaveNdkNamespace(out, defined_type);
318 }
319 
MethodId(const AidlMethod & m)320 static std::string MethodId(const AidlMethod& m) {
321   return "(FIRST_CALL_TRANSACTION + " + std::to_string(m.GetId()) + " /*" + m.GetName() + "*/)";
322 }
323 
GenerateClientMethodDefinition(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const AidlMethod & method,const Options & options)324 static void GenerateClientMethodDefinition(CodeWriter& out, const AidlTypenames& types,
325                                            const AidlInterface& defined_type,
326                                            const AidlMethod& method,
327                                            const Options& options) {
328   const std::string clazz = ClassName(defined_type, ClassNames::CLIENT);
329 
330   out << NdkMethodDecl(types, method, clazz) << " {\n";
331   out.Indent();
332   out << "binder_status_t _aidl_ret_status = STATUS_OK;\n";
333   out << "::ndk::ScopedAStatus _aidl_status;\n";
334 
335   if (method.GetName() == kGetInterfaceHash && !options.Hash().empty()) {
336     out << "const std::lock_guard<std::mutex> lock(" << kCachedHashMutex << ");\n";
337     out << "if (" << kCachedHash << " != \"-1\") {\n";
338     out.Indent();
339     out << "*_aidl_return = " << kCachedHash << ";\n"
340         << "_aidl_status.set(AStatus_fromStatus(_aidl_ret_status));\n"
341         << "return _aidl_status;\n";
342     out.Dedent();
343     out << "}\n";
344   } else if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
345     out << "if (" << kCachedVersion << " != -1) {\n";
346     out.Indent();
347     out << "*_aidl_return = " << kCachedVersion << ";\n"
348         << "_aidl_status.set(AStatus_fromStatus(_aidl_ret_status));\n"
349         << "return _aidl_status;\n";
350     out.Dedent();
351     out << "}\n";
352   }
353   out << "::ndk::ScopedAParcel _aidl_in;\n";
354   out << "::ndk::ScopedAParcel _aidl_out;\n";
355   out << "\n";
356 
357   if (options.GenLog()) {
358     out << cpp::GenLogBeforeExecute(ClassName(defined_type, ClassNames::CLIENT), method,
359                                     false /* isServer */, true /* isNdk */);
360   }
361   if (options.GenTraces()) {
362     out << "ScopedTrace _aidl_trace(\"AIDL::" << Options::LanguageToString(options.TargetLanguage())
363         << "::" << ClassName(defined_type, ClassNames::INTERFACE) << "::" << method.GetName()
364         << "::client\");\n";
365   }
366 
367   out << "_aidl_ret_status = AIBinder_prepareTransaction(asBinder().get(), _aidl_in.getR());\n";
368   StatusCheckGoto(out);
369 
370   for (const auto& arg : method.GetArguments()) {
371     const std::string var_name = cpp::BuildVarName(*arg);
372 
373     if (arg->IsIn()) {
374       out << "_aidl_ret_status = ";
375       const std::string prefix = (arg->IsOut() ? "*" : "");
376       WriteToParcelFor({out, types, arg->GetType(), "_aidl_in.get()", prefix + var_name});
377       out << ";\n";
378       StatusCheckGoto(out);
379     } else if (arg->IsOut() && arg->GetType().IsArray()) {
380       out << "_aidl_ret_status = ::ndk::AParcel_writeVectorSize(_aidl_in.get(), *" << var_name
381           << ");\n";
382     }
383   }
384   out << "_aidl_ret_status = AIBinder_transact(\n";
385   out.Indent();
386   out << "asBinder().get(),\n";
387   out << MethodId(method) << ",\n";
388   out << "_aidl_in.getR(),\n";
389   out << "_aidl_out.getR(),\n";
390   out << (method.IsOneway() ? "FLAG_ONEWAY" : "0") << "\n";
391   out << "#ifdef BINDER_STABILITY_SUPPORT\n";
392   out << "| FLAG_PRIVATE_LOCAL\n";
393   out << "#endif  // BINDER_STABILITY_SUPPORT\n";
394   out << ");\n";
395   out.Dedent();
396 
397   // If the method is not implmented in the server side but the client has
398   // provided the default implementation, call it instead of failing hard.
399   const std::string iface = ClassName(defined_type, ClassNames::INTERFACE);
400   out << "if (_aidl_ret_status == STATUS_UNKNOWN_TRANSACTION && ";
401   out << iface << "::getDefaultImpl()) {\n";
402   out.Indent();
403   out << "_aidl_status = " << iface << "::getDefaultImpl()->" << method.GetName() << "(";
404   out << NdkArgList(types, method, FormatArgNameOnly) << ");\n";
405   out << "goto _aidl_status_return;\n";
406   out.Dedent();
407   out << "}\n";
408 
409   StatusCheckGoto(out);
410 
411   if (!method.IsOneway()) {
412     out << "_aidl_ret_status = AParcel_readStatusHeader(_aidl_out.get(), _aidl_status.getR());\n";
413     StatusCheckGoto(out);
414 
415     out << "if (!AStatus_isOk(_aidl_status.get())) goto _aidl_status_return;\n";
416   }
417 
418   if (method.GetType().GetName() != "void") {
419     out << "_aidl_ret_status = ";
420     ReadFromParcelFor({out, types, method.GetType(), "_aidl_out.get()", "_aidl_return"});
421     out << ";\n";
422     StatusCheckGoto(out);
423     if (method.GetName() == kGetInterfaceHash && !options.Hash().empty()) {
424       out << kCachedHash << " = *_aidl_return;\n";
425     } else if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
426       out << kCachedVersion << " = *_aidl_return;\n";
427     }
428   }
429   for (const AidlArgument* arg : method.GetOutArguments()) {
430     out << "_aidl_ret_status = ";
431     ReadFromParcelFor({out, types, arg->GetType(), "_aidl_out.get()", cpp::BuildVarName(*arg)});
432     out << ";\n";
433     StatusCheckGoto(out);
434   }
435 
436   out << "_aidl_error:\n";
437   out << "_aidl_status.set(AStatus_fromStatus(_aidl_ret_status));\n";
438   out << "_aidl_status_return:\n";
439   if (options.GenLog()) {
440     out << cpp::GenLogAfterExecute(ClassName(defined_type, ClassNames::CLIENT), defined_type,
441                                    method, "_aidl_status", "_aidl_return", false /* isServer */,
442                                    true /* isNdk */);
443   }
444 
445   out << "return _aidl_status;\n";
446   out.Dedent();
447   out << "}\n";
448 }
449 
GenerateServerCaseDefinition(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const AidlMethod & method,const Options & options)450 static void GenerateServerCaseDefinition(CodeWriter& out, const AidlTypenames& types,
451                                          const AidlInterface& defined_type,
452                                          const AidlMethod& method, const Options& options) {
453   out << "case " << MethodId(method) << ": {\n";
454   out.Indent();
455   for (const auto& arg : method.GetArguments()) {
456     out << NdkNameOf(types, arg->GetType(), StorageMode::STACK) << " " << cpp::BuildVarName(*arg)
457         << ";\n";
458   }
459   if (method.GetType().GetName() != "void") {
460     out << NdkNameOf(types, method.GetType(), StorageMode::STACK) << " _aidl_return;\n";
461   }
462   out << "\n";
463   if (options.GenTraces()) {
464     out << "ScopedTrace _aidl_trace(\"AIDL::" << Options::LanguageToString(options.TargetLanguage())
465         << "::" << ClassName(defined_type, ClassNames::INTERFACE) << "::" << method.GetName()
466         << "::server\");\n";
467   }
468 
469   for (const auto& arg : method.GetArguments()) {
470     const std::string var_name = cpp::BuildVarName(*arg);
471 
472     if (arg->IsIn()) {
473       out << "_aidl_ret_status = ";
474       ReadFromParcelFor({out, types, arg->GetType(), "_aidl_in", "&" + var_name});
475       out << ";\n";
476       StatusCheckBreak(out);
477     } else if (arg->IsOut() && arg->GetType().IsArray()) {
478       out << "_aidl_ret_status = ::ndk::AParcel_resizeVector(_aidl_in, &" << var_name << ");\n";
479     }
480   }
481   if (options.GenLog()) {
482     out << cpp::GenLogBeforeExecute(ClassName(defined_type, ClassNames::SERVER), method,
483                                     true /* isServer */, true /* isNdk */);
484   }
485   out << "::ndk::ScopedAStatus _aidl_status = _aidl_impl->" << method.GetName() << "("
486       << NdkArgList(types, method, FormatArgForCall) << ");\n";
487 
488   if (options.GenLog()) {
489     out << cpp::GenLogAfterExecute(ClassName(defined_type, ClassNames::SERVER), defined_type,
490                                    method, "_aidl_status", "_aidl_return", true /* isServer */,
491                                    true /* isNdk */);
492   }
493   if (method.IsOneway()) {
494     // For a oneway transaction, the kernel will have already returned a result. This is for the
495     // in-process case when a oneway transaction is parceled/unparceled in the same process.
496     out << "_aidl_ret_status = STATUS_OK;\n";
497   } else {
498     out << "_aidl_ret_status = AParcel_writeStatusHeader(_aidl_out, _aidl_status.get());\n";
499     StatusCheckBreak(out);
500 
501     out << "if (!AStatus_isOk(_aidl_status.get())) break;\n\n";
502 
503     if (method.GetType().GetName() != "void") {
504       out << "_aidl_ret_status = ";
505       WriteToParcelFor({out, types, method.GetType(), "_aidl_out", "_aidl_return"});
506       out << ";\n";
507       StatusCheckBreak(out);
508     }
509     for (const AidlArgument* arg : method.GetOutArguments()) {
510       out << "_aidl_ret_status = ";
511       WriteToParcelFor({out, types, arg->GetType(), "_aidl_out", cpp::BuildVarName(*arg)});
512       out << ";\n";
513       StatusCheckBreak(out);
514     }
515   }
516   out << "break;\n";
517   out.Dedent();
518   out << "}\n";
519 }
520 
GenerateClassSource(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const Options & options)521 void GenerateClassSource(CodeWriter& out, const AidlTypenames& types,
522                          const AidlInterface& defined_type, const Options& options) {
523   const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE);
524   const std::string bn_clazz = ClassName(defined_type, ClassNames::SERVER);
525   if (options.GenTraces()) {
526     out << "class ScopedTrace {\n";
527     out.Indent();
528     out << "public:\n"
529         << "inline ScopedTrace(const char* name) {\n"
530         << "ATrace_beginSection(name);\n"
531         << "}\n"
532         << "inline ~ScopedTrace() {\n"
533         << "ATrace_endSection();\n"
534         << "}\n";
535     out.Dedent();
536     out << "};\n";
537   }
538   out << "static binder_status_t "
539       << "_aidl_onTransact"
540       << "(AIBinder* _aidl_binder, transaction_code_t _aidl_code, const AParcel* _aidl_in, "
541          "AParcel* _aidl_out) {\n";
542   out.Indent();
543   out << "(void)_aidl_in;\n";
544   out << "(void)_aidl_out;\n";
545   out << "binder_status_t _aidl_ret_status = STATUS_UNKNOWN_TRANSACTION;\n";
546   if (!defined_type.GetMethods().empty()) {
547     // we know this cast is valid because this method is only called by the ICInterface
548     // AIBinder_Class object which is associated with this class.
549     out << "std::shared_ptr<" << bn_clazz << "> _aidl_impl = std::static_pointer_cast<" << bn_clazz
550         << ">(::ndk::ICInterface::asInterface(_aidl_binder));\n";
551     out << "switch (_aidl_code) {\n";
552     out.Indent();
553     for (const auto& method : defined_type.GetMethods()) {
554       GenerateServerCaseDefinition(out, types, defined_type, *method, options);
555     }
556     out.Dedent();
557     out << "}\n";
558   } else {
559     out << "(void)_aidl_binder;\n";
560     out << "(void)_aidl_code;\n";
561   }
562   out << "return _aidl_ret_status;\n";
563   out.Dedent();
564   out << "}\n\n";
565 
566   out << "static AIBinder_Class* " << kClazz << " = ::ndk::ICInterface::defineClass(" << clazz
567       << "::" << kDescriptor << ", _aidl_onTransact);\n\n";
568 }
GenerateClientSource(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const Options & options)569 void GenerateClientSource(CodeWriter& out, const AidlTypenames& types,
570                           const AidlInterface& defined_type, const Options& options) {
571   const std::string clazz = ClassName(defined_type, ClassNames::CLIENT);
572 
573   out << clazz << "::" << clazz << "(const ::ndk::SpAIBinder& binder) : BpCInterface(binder) {}\n";
574   out << clazz << "::~" << clazz << "() {}\n";
575   if (options.GenLog()) {
576     out << "std::function<void(const Json::Value&)> " << clazz << "::logFunc;\n";
577   }
578   out << "\n";
579   for (const auto& method : defined_type.GetMethods()) {
580     GenerateClientMethodDefinition(out, types, defined_type, *method, options);
581   }
582 }
GenerateServerSource(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const Options & options)583 void GenerateServerSource(CodeWriter& out, const AidlTypenames& types,
584                           const AidlInterface& defined_type, const Options& options) {
585   const std::string clazz = ClassName(defined_type, ClassNames::SERVER);
586   const std::string iface = ClassName(defined_type, ClassNames::INTERFACE);
587 
588   out << "// Source for " << clazz << "\n";
589   out << clazz << "::" << clazz << "() {}\n";
590   out << clazz << "::~" << clazz << "() {}\n";
591   if (options.GenLog()) {
592     out << "std::function<void(const Json::Value&)> " << clazz << "::logFunc;\n";
593   }
594   out << "::ndk::SpAIBinder " << clazz << "::createBinder() {\n";
595   out.Indent();
596   out << "AIBinder* binder = AIBinder_new(" << kClazz << ", static_cast<void*>(this));\n";
597 
598   out << "#ifdef BINDER_STABILITY_SUPPORT\n";
599   if (defined_type.IsVintfStability()) {
600     out << "AIBinder_markVintfStability(binder);\n";
601   } else {
602     out << "AIBinder_markCompilationUnitStability(binder);\n";
603   }
604   out << "#endif  // BINDER_STABILITY_SUPPORT\n";
605 
606   out << "return ::ndk::SpAIBinder(binder);\n";
607   out.Dedent();
608   out << "}\n";
609 
610   // Implement the meta methods
611   for (const auto& method : defined_type.GetMethods()) {
612     if (method->IsUserDefined()) {
613       continue;
614     }
615     if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
616       out << NdkMethodDecl(types, *method, clazz) << " {\n";
617       out.Indent();
618       out << "*_aidl_return = " << iface << "::" << kVersion << ";\n";
619       out << "return ::ndk::ScopedAStatus(AStatus_newOk());\n";
620       out.Dedent();
621       out << "}\n";
622     }
623     if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) {
624       out << NdkMethodDecl(types, *method, clazz) << " {\n";
625       out.Indent();
626       out << "*_aidl_return = " << iface << "::" << kHash << ";\n";
627       out << "return ::ndk::ScopedAStatus(AStatus_newOk());\n";
628       out.Dedent();
629       out << "}\n";
630     }
631   }
632 }
GenerateInterfaceSource(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const Options & options)633 void GenerateInterfaceSource(CodeWriter& out, const AidlTypenames& types,
634                              const AidlInterface& defined_type, const Options& options) {
635   const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE);
636   const std::string bp_clazz = ClassName(defined_type, ClassNames::CLIENT);
637 
638   out << "// Source for " << clazz << "\n";
639   out << "const char* " << clazz << "::" << kDescriptor << " = \""
640       << defined_type.GetCanonicalName() << "\";\n";
641   out << clazz << "::" << clazz << "() {}\n";
642   out << clazz << "::~" << clazz << "() {}\n";
643   out << "\n";
644   GenerateConstantDefinitions(out, defined_type);
645   out << "\n";
646 
647   out << "std::shared_ptr<" << clazz << "> " << clazz
648       << "::fromBinder(const ::ndk::SpAIBinder& binder) {\n";
649   out.Indent();
650   out << "if (!AIBinder_associateClass(binder.get(), " << kClazz << ")) { return nullptr; }\n";
651   out << "std::shared_ptr<::ndk::ICInterface> interface = "
652          "::ndk::ICInterface::asInterface(binder.get());\n";
653   out << "if (interface) {\n";
654   out.Indent();
655   out << "return std::static_pointer_cast<" << clazz << ">(interface);\n";
656   out.Dedent();
657   out << "}\n";
658   out << "return ::ndk::SharedRefBase::make<" << bp_clazz << ">(binder);\n";
659   out.Dedent();
660   out << "}\n\n";
661 
662   out << "binder_status_t " << clazz << "::writeToParcel(AParcel* parcel, const std::shared_ptr<"
663       << clazz << ">& instance) {\n";
664   out.Indent();
665   out << "return AParcel_writeStrongBinder(parcel, instance ? instance->asBinder().get() : "
666          "nullptr);\n";
667   out.Dedent();
668   out << "}\n";
669 
670   out << "binder_status_t " << clazz << "::readFromParcel(const AParcel* parcel, std::shared_ptr<"
671       << clazz << ">* instance) {\n";
672   out.Indent();
673   out << "::ndk::SpAIBinder binder;\n";
674   out << "binder_status_t status = AParcel_readStrongBinder(parcel, binder.getR());\n";
675   out << "if (status != STATUS_OK) return status;\n";
676   out << "*instance = " << clazz << "::fromBinder(binder);\n";
677   out << "return STATUS_OK;\n";
678   out.Dedent();
679   out << "}\n";
680 
681   // defintion for static member setDefaultImpl
682   out << "bool " << clazz << "::setDefaultImpl(std::shared_ptr<" << clazz << "> impl) {\n";
683   out.Indent();
684   out << "// Only one user of this interface can use this function\n";
685   out << "// at a time. This is a heuristic to detect if two different\n";
686   out << "// users in the same process use this function.\n";
687   out << "assert(!" << clazz << "::default_impl);\n";
688   out << "if (impl) {\n";
689   out.Indent();
690   out << clazz << "::default_impl = impl;\n";
691   out << "return true;\n";
692   out.Dedent();
693   out << "}\n";
694   out << "return false;\n";
695   out.Dedent();
696   out << "}\n";
697 
698   // definition for static member getDefaultImpl
699   out << "const std::shared_ptr<" << clazz << ">& " << clazz << "::getDefaultImpl() {\n";
700   out.Indent();
701   out << "return " << clazz << "::default_impl;\n";
702   out.Dedent();
703   out << "}\n";
704 
705   // definition for the static field default_impl
706   out << "std::shared_ptr<" << clazz << "> " << clazz << "::default_impl = nullptr;\n";
707 
708   // default implementation for the <Name>Default class members
709   const std::string defaultClazz = clazz + "Default";
710   for (const auto& method : defined_type.GetMethods()) {
711     if (method->IsUserDefined()) {
712       out << "::ndk::ScopedAStatus " << defaultClazz << "::" << method->GetName() << "("
713           << NdkArgList(types, *method, FormatArgNameUnused) << ") {\n";
714       out.Indent();
715       out << "::ndk::ScopedAStatus _aidl_status;\n";
716       out << "_aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));\n";
717       out << "return _aidl_status;\n";
718       out.Dedent();
719       out << "}\n";
720     } else {
721       if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
722         out << "::ndk::ScopedAStatus " << defaultClazz << "::" << method->GetName() << "("
723             << "int32_t* _aidl_return) {\n";
724         out.Indent();
725         out << "*_aidl_return = 0;\n";
726         out << "return ::ndk::ScopedAStatus(AStatus_newOk());\n";
727         out.Dedent();
728         out << "}\n";
729       }
730       if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) {
731         out << "::ndk::ScopedAStatus " << defaultClazz << "::" << method->GetName() << "("
732             << "std::string* _aidl_return) {\n";
733         out.Indent();
734         out << "*_aidl_return = \"\";\n";
735         out << "return ::ndk::ScopedAStatus(AStatus_newOk());\n";
736         out.Dedent();
737         out << "}\n";
738       }
739     }
740   }
741 
742   out << "::ndk::SpAIBinder " << defaultClazz << "::asBinder() {\n";
743   out.Indent();
744   out << "return ::ndk::SpAIBinder();\n";
745   out.Dedent();
746   out << "}\n";
747 
748   out << "bool " << defaultClazz << "::isRemote() {\n";
749   out.Indent();
750   out << "return false;\n";
751   out.Dedent();
752   out << "}\n";
753 }
754 
GenerateClientHeader(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const Options & options)755 void GenerateClientHeader(CodeWriter& out, const AidlTypenames& types,
756                           const AidlInterface& defined_type, const Options& options) {
757   const std::string clazz = ClassName(defined_type, ClassNames::CLIENT);
758 
759   out << "#pragma once\n\n";
760   out << "#include \"" << NdkHeaderFile(defined_type, ClassNames::RAW, false /*use_os_sep*/)
761       << "\"\n";
762   out << "\n";
763   out << "#include <android/binder_ibinder.h>\n";
764   if (options.GenLog()) {
765     out << "#include <json/value.h>\n";
766     out << "#include <functional>\n";
767     out << "#include <chrono>\n";
768     out << "#include <sstream>\n";
769   }
770   if (options.GenTraces()) {
771     out << "#include <android/trace.h>\n";
772   }
773   out << "\n";
774   EnterNdkNamespace(out, defined_type);
775   out << "class " << clazz << " : public ::ndk::BpCInterface<"
776       << ClassName(defined_type, ClassNames::INTERFACE) << "> {\n";
777   out << "public:\n";
778   out.Indent();
779   out << clazz << "(const ::ndk::SpAIBinder& binder);\n";
780   out << "virtual ~" << clazz << "();\n";
781   out << "\n";
782   for (const auto& method : defined_type.GetMethods()) {
783     out << NdkMethodDecl(types, *method) << " override;\n";
784   }
785 
786   if (options.Version() > 0) {
787     out << "int32_t " << kCachedVersion << " = -1;\n";
788   }
789 
790   if (!options.Hash().empty()) {
791     out << "std::string " << kCachedHash << " = \"-1\";\n";
792     out << "std::mutex " << kCachedHashMutex << ";\n";
793   }
794   if (options.GenLog()) {
795     out << "static std::function<void(const Json::Value&)> logFunc;\n";
796   }
797   out.Dedent();
798   out << "};\n";
799   LeaveNdkNamespace(out, defined_type);
800 }
GenerateServerHeader(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const Options & options)801 void GenerateServerHeader(CodeWriter& out, const AidlTypenames& types,
802                           const AidlInterface& defined_type, const Options& options) {
803   const std::string clazz = ClassName(defined_type, ClassNames::SERVER);
804   const std::string iface = ClassName(defined_type, ClassNames::INTERFACE);
805 
806   out << "#pragma once\n\n";
807   out << "#include \"" << NdkHeaderFile(defined_type, ClassNames::RAW, false /*use_os_sep*/)
808       << "\"\n";
809   out << "\n";
810   out << "#include <android/binder_ibinder.h>\n";
811   out << "\n";
812   EnterNdkNamespace(out, defined_type);
813   out << "class " << clazz << " : public ::ndk::BnCInterface<" << iface << "> {\n";
814   out << "public:\n";
815   out.Indent();
816   out << clazz << "();\n";
817   out << "virtual ~" << clazz << "();\n";
818 
819   // Declare the meta methods
820   for (const auto& method : defined_type.GetMethods()) {
821     if (method->IsUserDefined()) {
822       continue;
823     }
824     if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
825       out << NdkMethodDecl(types, *method) << " final override;\n";
826     } else if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) {
827       out << NdkMethodDecl(types, *method) << " final override;\n";
828     } else {
829       AIDL_FATAL(defined_type) << "Meta method '" << method->GetName() << "' is unimplemented.";
830     }
831   }
832   if (options.GenLog()) {
833     out << "static std::function<void(const Json::Value&)> logFunc;\n";
834   }
835   out.Dedent();
836   out << "protected:\n";
837   out.Indent();
838   out << "::ndk::SpAIBinder createBinder() override;\n";
839   out.Dedent();
840   out << "private:\n";
841   out.Indent();
842   out.Dedent();
843   out << "};\n";
844   LeaveNdkNamespace(out, defined_type);
845 }
GenerateInterfaceHeader(CodeWriter & out,const AidlTypenames & types,const AidlInterface & defined_type,const Options & options)846 void GenerateInterfaceHeader(CodeWriter& out, const AidlTypenames& types,
847                              const AidlInterface& defined_type, const Options& options) {
848   const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE);
849 
850   out << "#pragma once\n\n";
851   out << "#include <android/binder_interface_utils.h>\n";
852   if (options.GenLog()) {
853     out << "#include <json/value.h>\n";
854     out << "#include <functional>\n";
855     out << "#include <chrono>\n";
856     out << "#include <sstream>\n";
857   }
858   out << "\n";
859 
860   GenerateHeaderIncludes(out, types, defined_type);
861   out << "\n";
862 
863   EnterNdkNamespace(out, defined_type);
864   out << "class " << clazz << " : public ::ndk::ICInterface {\n";
865   out << "public:\n";
866   out.Indent();
867   out << "static const char* " << kDescriptor << ";\n";
868   out << clazz << "();\n";
869   out << "virtual ~" << clazz << "();\n";
870   out << "\n";
871   GenerateConstantDeclarations(out, defined_type);
872   if (options.Version() > 0) {
873     out << "static const int32_t " << kVersion << " = " << std::to_string(options.Version())
874         << ";\n";
875   }
876   if (!options.Hash().empty()) {
877     out << "static inline const std::string " << kHash << " = \"" << options.Hash() << "\";\n";
878   }
879   out << "\n";
880   out << "static std::shared_ptr<" << clazz << "> fromBinder(const ::ndk::SpAIBinder& binder);\n";
881   out << "static binder_status_t writeToParcel(AParcel* parcel, const std::shared_ptr<" << clazz
882       << ">& instance);";
883   out << "\n";
884   out << "static binder_status_t readFromParcel(const AParcel* parcel, std::shared_ptr<" << clazz
885       << ">* instance);";
886   out << "\n";
887   out << "static bool setDefaultImpl(std::shared_ptr<" << clazz << "> impl);";
888   out << "\n";
889   out << "static const std::shared_ptr<" << clazz << ">& getDefaultImpl();";
890   out << "\n";
891   for (const auto& method : defined_type.GetMethods()) {
892     out << "virtual " << NdkMethodDecl(types, *method) << " = 0;\n";
893   }
894   out.Dedent();
895   out << "private:\n";
896   out.Indent();
897   out << "static std::shared_ptr<" << clazz << "> default_impl;\n";
898   out.Dedent();
899   out << "};\n";
900 
901   const std::string defaultClazz = clazz + "Default";
902 
903   out << "class " << defaultClazz << " : public " << clazz << " {\n";
904   out << "public:\n";
905   out.Indent();
906   for (const auto& method : defined_type.GetMethods()) {
907     if (method->IsUserDefined()) {
908       out << NdkMethodDecl(types, *method) << " override;\n";
909     } else if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) {
910       out << NdkMethodDecl(types, *method) << " override;\n";
911     } else if (method->GetName() == kGetInterfaceHash && !options.Hash().empty()) {
912       out << NdkMethodDecl(types, *method) << " override;\n";
913     }
914   }
915   out << "::ndk::SpAIBinder asBinder() override;\n";
916   out << "bool isRemote() override;\n";
917   out.Dedent();
918   out << "};\n";
919 
920   LeaveNdkNamespace(out, defined_type);
921 }
GenerateParcelHeader(CodeWriter & out,const AidlTypenames & types,const AidlStructuredParcelable & defined_type,const Options &)922 void GenerateParcelHeader(CodeWriter& out, const AidlTypenames& types,
923                           const AidlStructuredParcelable& defined_type,
924                           const Options& /*options*/) {
925   const std::string clazz = ClassName(defined_type, ClassNames::RAW);
926 
927   out << "#pragma once\n";
928   out << "#include <android/binder_interface_utils.h>\n";
929   out << "\n";
930 
931   GenerateHeaderIncludes(out, types, defined_type);
932 
933   EnterNdkNamespace(out, defined_type);
934   out << "class " << clazz << " {\n";
935   out << "public:\n";
936   out.Indent();
937   out << "static const char* descriptor;\n";
938   out << "\n";
939   for (const auto& variable : defined_type.GetFields()) {
940     out << NdkNameOf(types, variable->GetType(), StorageMode::STACK) << " " << variable->GetName();
941     if (variable->GetDefaultValue()) {
942       out << " = " << variable->ValueString(ConstantValueDecorator);
943     }
944     out << ";\n";
945   }
946   out << "\n";
947   out << "binder_status_t readFromParcel(const AParcel* parcel);\n";
948   out << "binder_status_t writeToParcel(AParcel* parcel) const;\n";
949 
950   out << "static const bool _aidl_is_stable = "
951       << (defined_type.IsVintfStability() ? "true" : "false") << ";\n";
952   out.Dedent();
953   out << "};\n";
954   LeaveNdkNamespace(out, defined_type);
955 }
GenerateParcelSource(CodeWriter & out,const AidlTypenames & types,const AidlStructuredParcelable & defined_type,const Options &)956 void GenerateParcelSource(CodeWriter& out, const AidlTypenames& types,
957                           const AidlStructuredParcelable& defined_type,
958                           const Options& /*options*/) {
959   const std::string clazz = ClassName(defined_type, ClassNames::RAW);
960 
961   out << "#include \"" << NdkHeaderFile(defined_type, ClassNames::RAW, false /*use_os_sep*/)
962       << "\"\n";
963   out << "\n";
964   GenerateSourceIncludes(out, types, defined_type);
965   out << "\n";
966   EnterNdkNamespace(out, defined_type);
967   out << "const char* " << clazz << "::" << kDescriptor << " = \""
968       << defined_type.GetCanonicalName() << "\";\n";
969   out << "\n";
970 
971   out << "binder_status_t " << clazz << "::readFromParcel(const AParcel* parcel) {\n";
972   out.Indent();
973   out << "int32_t _aidl_parcelable_size;\n";
974   out << "int32_t _aidl_start_pos = AParcel_getDataPosition(parcel);\n";
975   out << "binder_status_t _aidl_ret_status = AParcel_readInt32(parcel, &_aidl_parcelable_size);\n";
976   out << "if (_aidl_parcelable_size < 0) return STATUS_BAD_VALUE;\n";
977   StatusCheckReturn(out);
978 
979   for (const auto& variable : defined_type.GetFields()) {
980     out << "_aidl_ret_status = ";
981     ReadFromParcelFor({out, types, variable->GetType(), "parcel", "&" + variable->GetName()});
982     out << ";\n";
983     StatusCheckReturn(out);
984     out << "if (AParcel_getDataPosition(parcel) - _aidl_start_pos >= _aidl_parcelable_size) {\n"
985         << "  AParcel_setDataPosition(parcel, _aidl_start_pos + _aidl_parcelable_size);\n"
986         << "  return _aidl_ret_status;\n"
987         << "}\n";
988   }
989   out << "AParcel_setDataPosition(parcel, _aidl_start_pos + _aidl_parcelable_size);\n"
990       << "return _aidl_ret_status;\n";
991   out.Dedent();
992   out << "}\n";
993 
994   out << "binder_status_t " << clazz << "::writeToParcel(AParcel* parcel) const {\n";
995   out.Indent();
996   out << "binder_status_t _aidl_ret_status;\n";
997 
998   out << "size_t _aidl_start_pos = AParcel_getDataPosition(parcel);\n";
999   out << "_aidl_ret_status = AParcel_writeInt32(parcel, 0);\n";
1000   StatusCheckReturn(out);
1001 
1002   for (const auto& variable : defined_type.GetFields()) {
1003     out << "_aidl_ret_status = ";
1004     WriteToParcelFor({out, types, variable->GetType(), "parcel", variable->GetName()});
1005     out << ";\n";
1006     StatusCheckReturn(out);
1007   }
1008   out << "size_t _aidl_end_pos = AParcel_getDataPosition(parcel);\n";
1009   out << "AParcel_setDataPosition(parcel, _aidl_start_pos);\n";
1010   out << "AParcel_writeInt32(parcel, _aidl_end_pos - _aidl_start_pos);\n";
1011   out << "AParcel_setDataPosition(parcel, _aidl_end_pos);\n";
1012 
1013   out << "return _aidl_ret_status;\n";
1014   out.Dedent();
1015   out << "}\n";
1016   out << "\n";
1017   LeaveNdkNamespace(out, defined_type);
1018 }
1019 
GenerateEnumToString(const AidlTypenames & typenames,const AidlEnumDeclaration & enum_decl)1020 std::string GenerateEnumToString(const AidlTypenames& typenames,
1021                                  const AidlEnumDeclaration& enum_decl) {
1022   std::ostringstream code;
1023   code << "static inline std::string toString(" << enum_decl.GetName() << " val) {\n";
1024   code << "  switch(val) {\n";
1025   std::set<std::string> unique_cases;
1026   for (const auto& enumerator : enum_decl.GetEnumerators()) {
1027     std::string c = enumerator->ValueString(enum_decl.GetBackingType(), ConstantValueDecorator);
1028     // Only add a case if its value has not yet been used in the switch
1029     // statement. C++ does not allow multiple cases with the same value, but
1030     // enums does allow this. In this scenario, the first declared
1031     // enumerator with the given value is printed.
1032     if (unique_cases.count(c) == 0) {
1033       unique_cases.insert(c);
1034       code << "  case " << enum_decl.GetName() << "::" << enumerator->GetName() << ":\n";
1035       code << "    return \"" << enumerator->GetName() << "\";\n";
1036     }
1037   }
1038   code << "  default:\n";
1039   code << "    return std::to_string(static_cast<"
1040        << NdkNameOf(typenames, enum_decl.GetBackingType(), StorageMode::STACK) << ">(val));\n";
1041   code << "  }\n";
1042   code << "}\n";
1043   return code.str();
1044 }
1045 
GenerateEnumHeader(CodeWriter & out,const AidlTypenames & types,const AidlEnumDeclaration & enum_decl,const Options &)1046 void GenerateEnumHeader(CodeWriter& out, const AidlTypenames& types,
1047                         const AidlEnumDeclaration& enum_decl, const Options& /*options*/) {
1048   out << "#pragma once\n";
1049   out << "\n";
1050 
1051   GenerateHeaderIncludes(out, types, enum_decl);
1052   // enum specific headers
1053   out << "#include <array>\n";
1054   out << "#include <android/binder_enums.h>\n";
1055 
1056   EnterNdkNamespace(out, enum_decl);
1057   out << "enum class " << enum_decl.GetName() << " : "
1058       << NdkNameOf(types, enum_decl.GetBackingType(), StorageMode::STACK) << " {\n";
1059   out.Indent();
1060   for (const auto& enumerator : enum_decl.GetEnumerators()) {
1061     out << enumerator->GetName() << " = "
1062         << enumerator->ValueString(enum_decl.GetBackingType(), ConstantValueDecorator) << ",\n";
1063   }
1064   out.Dedent();
1065   out << "};\n";
1066   out << "\n";
1067   out << GenerateEnumToString(types, enum_decl);
1068   LeaveNdkNamespace(out, enum_decl);
1069 
1070   out << "namespace ndk {\n";
1071   out << "namespace internal {\n";
1072   out << cpp::GenerateEnumValues(enum_decl, {"aidl"});
1073   out << "}  // namespace internal\n";
1074   out << "}  // namespace android\n";
1075 }
1076 
1077 }  // namespace internals
1078 }  // namespace ndk
1079 }  // namespace aidl
1080 }  // namespace android
1081