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