blob: d7eaffe9fb2b0e196e2c939f22d1e7eed9e82155 [file] [log] [blame]
Jiyong Park1d2df7d2018-07-23 15:22:50 +09001/*
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 "aidl_to_java.h"
18#include "aidl_language.h"
19#include "aidl_typenames.h"
20#include "logging.h"
21
22#include <android-base/strings.h>
23
Jiyong Park1d2df7d2018-07-23 15:22:50 +090024#include <functional>
25#include <iostream>
26#include <map>
27#include <string>
28#include <vector>
29
30namespace android {
31namespace aidl {
32namespace java {
33
34using android::base::Join;
35
Jiyong Park1d2df7d2018-07-23 15:22:50 +090036using std::endl;
37using std::function;
38using std::map;
39using std::string;
40using std::vector;
41
Daniel Norman37d43dd2019-09-09 17:22:34 -070042std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value) {
Will McVickerd7d18df2019-09-12 13:40:50 -070043 if (type.GetName() == "long" && !type.IsArray()) {
Daniel Norman37d43dd2019-09-09 17:22:34 -070044 return raw_value + "L";
45 }
46
Steven Moreland860b1942018-08-16 14:59:28 -070047 return raw_value;
48};
49
Daniel Norman716d3112019-09-10 13:11:56 -070050const string& JavaNameOf(const AidlTypeSpecifier& aidl, const AidlTypenames& typenames,
Jeongik Chae74c86d2019-12-12 16:54:03 +090051 bool instantiable = false, bool boxing = false) {
Steven Moreland8219c472018-08-17 11:41:13 -070052 CHECK(aidl.IsResolved()) << aidl.ToString();
53
Jeongik Chaa2080bf2019-06-18 16:44:29 +090054 if (instantiable) {
55 // An instantiable type is used in only out type(not even inout type),
56 // And instantiable type has to be either the type in List, Map, ParcelFileDescriptor or
57 // user-defined type.
58
59 static map<string, string> instantiable_m = {
60 {"List", "java.util.ArrayList"},
61 {"Map", "java.util.HashMap"},
62 {"ParcelFileDescriptor", "android.os.ParcelFileDescriptor"},
63 };
64 const string& aidl_name = aidl.GetName();
65
66 if (instantiable_m.find(aidl_name) != instantiable_m.end()) {
67 return instantiable_m[aidl_name];
68 }
Jeongik Chaa2080bf2019-06-18 16:44:29 +090069 }
70
Jiyong Park1d2df7d2018-07-23 15:22:50 +090071 // map from AIDL built-in type name to the corresponding Java type name
72 static map<string, string> m = {
73 {"void", "void"},
74 {"boolean", "boolean"},
75 {"byte", "byte"},
76 {"char", "char"},
77 {"int", "int"},
78 {"long", "long"},
79 {"float", "float"},
80 {"double", "double"},
81 {"String", "java.lang.String"},
82 {"List", "java.util.List"},
83 {"Map", "java.util.Map"},
84 {"IBinder", "android.os.IBinder"},
85 {"FileDescriptor", "java.io.FileDescriptor"},
86 {"CharSequence", "java.lang.CharSequence"},
Jiyong Parke05195e2018-10-08 18:24:23 +090087 {"ParcelFileDescriptor", "android.os.ParcelFileDescriptor"},
Jeongik Cha649e8a72020-03-27 17:47:40 +090088 {"ParcelableHolder", "android.os.ParcelableHolder"},
Jiyong Park1d2df7d2018-07-23 15:22:50 +090089 };
Daniel Norman716d3112019-09-10 13:11:56 -070090
Jeongik Chae74c86d2019-12-12 16:54:03 +090091 // map from primitive types to the corresponding boxing types
92 static map<string, string> boxing_types = {
93 {"void", "Void"}, {"boolean", "Boolean"}, {"byte", "Byte"}, {"char", "Character"},
94 {"int", "Integer"}, {"long", "Long"}, {"float", "Float"}, {"double", "Double"},
95 };
96
Daniel Norman716d3112019-09-10 13:11:56 -070097 // Enums in Java are represented by their backing type when
98 // referenced in parcelables, methods, etc.
99 if (const AidlEnumDeclaration* enum_decl = typenames.GetEnumDeclaration(aidl);
100 enum_decl != nullptr) {
101 const string& backing_type_name = enum_decl->GetBackingType().GetName();
102 CHECK(m.find(backing_type_name) != m.end());
103 CHECK(AidlTypenames::IsBuiltinTypename(backing_type_name));
Devin Moore7b68f0b2020-08-28 16:47:40 -0700104 if (boxing) {
105 return boxing_types[backing_type_name];
106 } else {
107 return m[backing_type_name];
108 }
Daniel Norman716d3112019-09-10 13:11:56 -0700109 }
110
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900111 const string& aidl_name = aidl.GetName();
Jeongik Chae74c86d2019-12-12 16:54:03 +0900112 if (boxing && AidlTypenames::IsPrimitiveTypename(aidl_name)) {
113 // Every primitive type must have the corresponding boxing type
114 CHECK(boxing_types.find(aidl_name) != m.end());
115 return boxing_types[aidl_name];
116 }
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900117 if (m.find(aidl_name) != m.end()) {
118 CHECK(AidlTypenames::IsBuiltinTypename(aidl_name));
119 return m[aidl_name];
120 } else {
121 // 'foo.bar.IFoo' in AIDL maps to 'foo.bar.IFoo' in Java
122 return aidl_name;
123 }
124}
125
Jeongik Chaa2080bf2019-06-18 16:44:29 +0900126namespace {
Jeongik Chae74c86d2019-12-12 16:54:03 +0900127string JavaSignatureOfInternal(
128 const AidlTypeSpecifier& aidl, const AidlTypenames& typenames, bool instantiable,
129 bool omit_array, bool boxing = false /* boxing can be true only if it is a type parameter */) {
130 string ret = JavaNameOf(aidl, typenames, instantiable, boxing && !aidl.IsArray());
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900131 if (aidl.IsGeneric()) {
132 vector<string> arg_names;
133 for (const auto& ta : aidl.GetTypeParameters()) {
Jeongik Chae74c86d2019-12-12 16:54:03 +0900134 arg_names.emplace_back(
135 JavaSignatureOfInternal(*ta, typenames, false, false, true /* boxing */));
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900136 }
137 ret += "<" + Join(arg_names, ",") + ">";
138 }
Jeongik Chaa2080bf2019-06-18 16:44:29 +0900139 if (aidl.IsArray() && !omit_array) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900140 ret += "[]";
141 }
142 return ret;
143}
Daniel Norman716d3112019-09-10 13:11:56 -0700144
145// Returns the name of the backing type for the specified type. Note: this
146// returns type names as used in AIDL, not a Java signature.
147// For enums, this is the enum's backing type.
148// For all other types, this is the type itself.
149string AidlBackingTypeName(const AidlTypeSpecifier& type, const AidlTypenames& typenames) {
150 string type_name;
151 if (const AidlEnumDeclaration* enum_decl = typenames.GetEnumDeclaration(type);
152 enum_decl != nullptr) {
153 type_name = enum_decl->GetBackingType().GetName();
154 } else {
155 type_name = type.GetName();
156 }
157 if (type.IsArray()) {
158 type_name += "[]";
159 }
160 return type_name;
161}
162
Jeongik Chaa2080bf2019-06-18 16:44:29 +0900163} // namespace
164
Daniel Norman716d3112019-09-10 13:11:56 -0700165string JavaSignatureOf(const AidlTypeSpecifier& aidl, const AidlTypenames& typenames) {
166 return JavaSignatureOfInternal(aidl, typenames, false, false);
Jeongik Chaa2080bf2019-06-18 16:44:29 +0900167}
168
Daniel Norman716d3112019-09-10 13:11:56 -0700169string InstantiableJavaSignatureOf(const AidlTypeSpecifier& aidl, const AidlTypenames& typenames) {
170 return JavaSignatureOfInternal(aidl, typenames, true, true);
Jeongik Chaa2080bf2019-06-18 16:44:29 +0900171}
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900172
Daniel Norman716d3112019-09-10 13:11:56 -0700173string DefaultJavaValueOf(const AidlTypeSpecifier& aidl, const AidlTypenames& typenames) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900174 static map<string, string> m = {
175 {"boolean", "false"}, {"byte", "0"}, {"char", R"('\u0000')"}, {"int", "0"},
176 {"long", "0L"}, {"float", "0.0f"}, {"double", "0.0d"},
177 };
Daniel Norman716d3112019-09-10 13:11:56 -0700178
179 const string name = AidlBackingTypeName(aidl, typenames);
Steven Moreland9731c632019-08-13 10:21:08 -0700180 CHECK(name != "void");
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900181
182 if (!aidl.IsArray() && m.find(name) != m.end()) {
183 CHECK(AidlTypenames::IsBuiltinTypename(name));
184 return m[name];
185 } else {
186 return "null";
187 }
188}
189
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900190static string GetFlagFor(const CodeGeneratorContext& c) {
191 if (c.is_return_value) {
192 return "android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE";
193 } else {
194 return "0";
195 }
196}
197
198bool WriteToParcelFor(const CodeGeneratorContext& c) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900199 static map<string, function<void(const CodeGeneratorContext&)>> method_map{
200 {"boolean",
201 [](const CodeGeneratorContext& c) {
202 c.writer << c.parcel << ".writeInt(((" << c.var << ")?(1):(0)));\n";
203 }},
204 {"boolean[]",
205 [](const CodeGeneratorContext& c) {
206 c.writer << c.parcel << ".writeBooleanArray(" << c.var << ");\n";
207 }},
208 {"byte",
209 [](const CodeGeneratorContext& c) {
210 c.writer << c.parcel << ".writeByte(" << c.var << ");\n";
211 }},
212 {"byte[]",
213 [](const CodeGeneratorContext& c) {
214 c.writer << c.parcel << ".writeByteArray(" << c.var << ");\n";
215 }},
216 {"char",
217 [](const CodeGeneratorContext& c) {
218 c.writer << c.parcel << ".writeInt(((int)" << c.var << "));\n";
219 }},
220 {"char[]",
221 [](const CodeGeneratorContext& c) {
222 c.writer << c.parcel << ".writeCharArray(" << c.var << ");\n";
223 }},
224 {"int",
225 [](const CodeGeneratorContext& c) {
226 c.writer << c.parcel << ".writeInt(" << c.var << ");\n";
227 }},
228 {"int[]",
229 [](const CodeGeneratorContext& c) {
230 c.writer << c.parcel << ".writeIntArray(" << c.var << ");\n";
231 }},
232 {"long",
233 [](const CodeGeneratorContext& c) {
234 c.writer << c.parcel << ".writeLong(" << c.var << ");\n";
235 }},
236 {"long[]",
237 [](const CodeGeneratorContext& c) {
238 c.writer << c.parcel << ".writeLongArray(" << c.var << ");\n";
239 }},
240 {"float",
241 [](const CodeGeneratorContext& c) {
242 c.writer << c.parcel << ".writeFloat(" << c.var << ");\n";
243 }},
244 {"float[]",
245 [](const CodeGeneratorContext& c) {
246 c.writer << c.parcel << ".writeFloatArray(" << c.var << ");\n";
247 }},
248 {"double",
249 [](const CodeGeneratorContext& c) {
250 c.writer << c.parcel << ".writeDouble(" << c.var << ");\n";
251 }},
252 {"double[]",
253 [](const CodeGeneratorContext& c) {
254 c.writer << c.parcel << ".writeDoubleArray(" << c.var << ");\n";
255 }},
256 {"String",
257 [](const CodeGeneratorContext& c) {
258 c.writer << c.parcel << ".writeString(" << c.var << ");\n";
259 }},
260 {"String[]",
261 [](const CodeGeneratorContext& c) {
262 c.writer << c.parcel << ".writeStringArray(" << c.var << ");\n";
263 }},
264 {"List",
265 [](const CodeGeneratorContext& c) {
266 if (c.type.IsGeneric()) {
267 const string& contained_type = c.type.GetTypeParameters().at(0)->GetName();
268 if (AidlTypenames::IsBuiltinTypename(contained_type)) {
269 if (contained_type == "String") {
270 c.writer << c.parcel << ".writeStringList(" << c.var << ");\n";
271 } else if (contained_type == "IBinder") {
272 c.writer << c.parcel << ".writeBinderList(" << c.var << ");\n";
273 }
274 } else {
275 const AidlDefinedType* t = c.typenames.TryGetDefinedType(contained_type);
276 CHECK(t != nullptr) << "Unknown type: " << contained_type << endl;
277 if (t->AsParcelable() != nullptr) {
278 c.writer << c.parcel << ".writeTypedList(" << c.var << ");\n";
279 }
280 }
281 } else {
282 c.writer << c.parcel << ".writeList(" << c.var << ");\n";
283 }
284 }},
285 {"Map",
286 [](const CodeGeneratorContext& c) {
Jeongik Chae48d9942020-01-02 17:39:00 +0900287 if (c.type.IsGeneric()) {
288 c.writer << "if (" << c.var << " == null) {\n";
289 c.writer.Indent();
290 c.writer << c.parcel << ".writeInt(-1);\n";
291 c.writer.Dedent();
292 c.writer << "} else {\n";
293 c.writer.Indent();
294 c.writer << c.parcel << ".writeInt(" << c.var << ".size());\n";
295 c.writer << c.var << ".forEach((k, v) -> {\n";
296 c.writer.Indent();
297 c.writer << c.parcel << ".writeString(k);\n";
298
299 CodeGeneratorContext value_context{
300 c.writer,
301 c.typenames,
302 *c.type.GetTypeParameters()[1].get(),
303 c.parcel,
304 "v",
305 c.is_return_value,
306 c.is_classloader_created,
307 c.filename,
308 };
309 WriteToParcelFor(value_context);
310 c.writer.Dedent();
311 c.writer << "});\n";
312
313 c.writer.Dedent();
314 c.writer << "}\n";
315 } else {
316 c.writer << c.parcel << ".writeMap(" << c.var << ");\n";
317 }
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900318 }},
319 {"IBinder",
320 [](const CodeGeneratorContext& c) {
321 c.writer << c.parcel << ".writeStrongBinder(" << c.var << ");\n";
322 }},
323 {"IBinder[]",
324 [](const CodeGeneratorContext& c) {
325 c.writer << c.parcel << ".writeBinderArray(" << c.var << ");\n";
326 }},
327 {"FileDescriptor",
328 [](const CodeGeneratorContext& c) {
329 c.writer << c.parcel << ".writeRawFileDescriptor(" << c.var << ");\n";
330 }},
331 {"FileDescriptor[]",
332 [](const CodeGeneratorContext& c) {
333 c.writer << c.parcel << ".writeRawFileDescriptorArray(" << c.var << ");\n";
334 }},
Jiyong Parke05195e2018-10-08 18:24:23 +0900335 {"ParcelFileDescriptor",
336 [](const CodeGeneratorContext& c) {
Jiyong Parkd53fdbe2018-11-14 15:53:32 +0900337 // This is same as writeTypedObject which was introduced with SDK 23.
338 // Keeping below code so that the generated code is buildable with older SDK.
339 c.writer << "if ((" << c.var << "!=null)) {\n";
340 c.writer.Indent();
341 c.writer << c.parcel << ".writeInt(1);\n";
342 c.writer << c.var << ".writeToParcel(" << c.parcel << ", " << GetFlagFor(c) << ");\n";
343 c.writer.Dedent();
344 c.writer << "}\n";
345 c.writer << "else {\n";
346 c.writer.Indent();
347 c.writer << c.parcel << ".writeInt(0);\n";
348 c.writer.Dedent();
349 c.writer << "}\n";
Jiyong Parke05195e2018-10-08 18:24:23 +0900350 }},
351 {"ParcelFileDescriptor[]",
352 [](const CodeGeneratorContext& c) {
353 c.writer << c.parcel << ".writeTypedArray(" << c.var << ", " << GetFlagFor(c) << ");\n";
354 }},
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900355 {"CharSequence",
356 [](const CodeGeneratorContext& c) {
357 // TextUtils.writeToParcel does not accept null. So, we need to handle
358 // the case here.
359 c.writer << "if (" << c.var << "!=null) {\n";
360 c.writer.Indent();
361 c.writer << c.parcel << ".writeInt(1);\n";
362 c.writer << "android.text.TextUtils.writeToParcel(" << c.var << ", " << c.parcel << ", "
363 << GetFlagFor(c) << ");\n";
364 c.writer.Dedent();
365 c.writer << "}\n";
366 c.writer << "else {\n";
367 c.writer.Indent();
368 c.writer << c.parcel << ".writeInt(0);\n";
369 c.writer.Dedent();
370 c.writer << "}\n";
371 }},
Jeongik Cha649e8a72020-03-27 17:47:40 +0900372 {"ParcelableHolder",
373 [](const CodeGeneratorContext& c) {
374 c.writer << c.parcel << ".writeTypedObject(" << c.var << ", 0);\n";
375 }},
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900376 };
Daniel Norman716d3112019-09-10 13:11:56 -0700377 const string type_name = AidlBackingTypeName(c.type, c.typenames);
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900378 const auto found = method_map.find(type_name);
379 if (found != method_map.end()) {
380 found->second(c);
381 } else {
382 const AidlDefinedType* t = c.typenames.TryGetDefinedType(c.type.GetName());
383 CHECK(t != nullptr) << "Unknown type: " << c.type.GetName() << endl;
384 if (t->AsInterface() != nullptr) {
385 if (!c.type.IsArray()) {
386 // Why don't we use writeStrongInterface which does the exact same thing?
387 // Keeping below code just not to break unit tests.
388 c.writer << c.parcel << ".writeStrongBinder((((" << c.var << "!=null))?"
389 << "(" << c.var << ".asBinder()):(null)));\n";
390 }
391 } else if (t->AsParcelable() != nullptr) {
392 if (c.type.IsArray()) {
393 c.writer << c.parcel << ".writeTypedArray(" << c.var << ", " << GetFlagFor(c) << ");\n";
394 } else {
395 // This is same as writeTypedObject.
396 // Keeping below code just not to break tests.
397 c.writer << "if ((" << c.var << "!=null)) {\n";
398 c.writer.Indent();
399 c.writer << c.parcel << ".writeInt(1);\n";
400 c.writer << c.var << ".writeToParcel(" << c.parcel << ", " << GetFlagFor(c) << ");\n";
401 c.writer.Dedent();
402 c.writer << "}\n";
403 c.writer << "else {\n";
404 c.writer.Indent();
405 c.writer << c.parcel << ".writeInt(0);\n";
406 c.writer.Dedent();
407 c.writer << "}\n";
408 }
409 }
410 }
411 return true;
412}
413
414// Ensures that a variable is initialized to refer to the classloader
415// of the current object and returns the name of the variable.
416static string EnsureAndGetClassloader(CodeGeneratorContext& c) {
417 CHECK(c.is_classloader_created != nullptr);
418 if (!*(c.is_classloader_created)) {
419 c.writer << "java.lang.ClassLoader cl = "
420 << "(java.lang.ClassLoader)this.getClass().getClassLoader();\n";
421 *(c.is_classloader_created) = true;
422 }
423 return "cl";
424}
425
426bool CreateFromParcelFor(const CodeGeneratorContext& c) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900427 static map<string, function<void(const CodeGeneratorContext&)>> method_map{
428 {"boolean",
429 [](const CodeGeneratorContext& c) {
430 c.writer << c.var << " = (0!=" << c.parcel << ".readInt());\n";
431 }},
432 {"boolean[]",
433 [](const CodeGeneratorContext& c) {
434 c.writer << c.var << " = " << c.parcel << ".createBooleanArray();\n";
435 }},
436 {"byte",
437 [](const CodeGeneratorContext& c) {
438 c.writer << c.var << " = " << c.parcel << ".readByte();\n";
439 }},
440 {"byte[]",
441 [](const CodeGeneratorContext& c) {
442 c.writer << c.var << " = " << c.parcel << ".createByteArray();\n";
443 }},
444 {"char",
445 [](const CodeGeneratorContext& c) {
446 c.writer << c.var << " = (char)" << c.parcel << ".readInt();\n";
447 }},
448 {"char[]",
449 [](const CodeGeneratorContext& c) {
450 c.writer << c.var << " = " << c.parcel << ".createCharArray();\n";
451 }},
452 {"int",
453 [](const CodeGeneratorContext& c) {
454 c.writer << c.var << " = " << c.parcel << ".readInt();\n";
455 }},
456 {"int[]",
457 [](const CodeGeneratorContext& c) {
458 c.writer << c.var << " = " << c.parcel << ".createIntArray();\n";
459 }},
460 {"long",
461 [](const CodeGeneratorContext& c) {
462 c.writer << c.var << " = " << c.parcel << ".readLong();\n";
463 }},
464 {"long[]",
465 [](const CodeGeneratorContext& c) {
466 c.writer << c.var << " = " << c.parcel << ".createLongArray();\n";
467 }},
468 {"float",
469 [](const CodeGeneratorContext& c) {
470 c.writer << c.var << " = " << c.parcel << ".readFloat();\n";
471 }},
472 {"float[]",
473 [](const CodeGeneratorContext& c) {
474 c.writer << c.var << " = " << c.parcel << ".createFloatArray();\n";
475 }},
476 {"double",
477 [](const CodeGeneratorContext& c) {
478 c.writer << c.var << " = " << c.parcel << ".readDouble();\n";
479 }},
480 {"double[]",
481 [](const CodeGeneratorContext& c) {
482 c.writer << c.var << " = " << c.parcel << ".createDoubleArray();\n";
483 }},
484 {"String",
485 [](const CodeGeneratorContext& c) {
486 c.writer << c.var << " = " << c.parcel << ".readString();\n";
487 }},
488 {"String[]",
489 [](const CodeGeneratorContext& c) {
490 c.writer << c.var << " = " << c.parcel << ".createStringArray();\n";
491 }},
492 {"List",
493 [](const CodeGeneratorContext& c) {
494 if (c.type.IsGeneric()) {
495 const string& contained_type = c.type.GetTypeParameters().at(0)->GetName();
496 if (AidlTypenames::IsBuiltinTypename(contained_type)) {
497 if (contained_type == "String") {
498 c.writer << c.var << " = " << c.parcel << ".createStringArrayList();\n";
499 } else if (contained_type == "IBinder") {
500 c.writer << c.var << " = " << c.parcel << ".createBinderArrayList();\n";
501 }
502 } else {
503 const AidlDefinedType* t = c.typenames.TryGetDefinedType(contained_type);
504 CHECK(t != nullptr) << "Unknown type: " << contained_type << endl;
505 if (t->AsParcelable() != nullptr) {
506 c.writer << c.var << " = " << c.parcel << ".createTypedArrayList("
Daniel Norman716d3112019-09-10 13:11:56 -0700507 << JavaNameOf(*(c.type.GetTypeParameters().at(0)), c.typenames)
508 << ".CREATOR);\n";
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900509 }
510 }
511 } else {
512 const string classloader = EnsureAndGetClassloader(const_cast<CodeGeneratorContext&>(c));
513 c.writer << c.var << " = " << c.parcel << ".readArrayList(" << classloader << ");\n";
514 }
515 }},
516 {"Map",
517 [](const CodeGeneratorContext& c) {
Jeongik Chae48d9942020-01-02 17:39:00 +0900518 if (c.type.IsGeneric()) {
519 c.writer << "{\n";
520 c.writer.Indent();
521 c.writer << "int N = " << c.parcel << ".readInt();\n";
522 c.writer << c.var << " = N < 0 ? null : new java.util.HashMap<>();\n";
523
524 auto creator = JavaNameOf(*(c.type.GetTypeParameters().at(1)), c.typenames) + ".CREATOR";
525 c.writer << "java.util.stream.IntStream.range(0, N).forEach(i -> {\n";
526 c.writer.Indent();
527 c.writer << "String k = " << c.parcel << ".readString();\n";
528 c.writer << JavaNameOf(*(c.type.GetTypeParameters().at(1)), c.typenames) << " v;\n";
529 CodeGeneratorContext value_context{
530 c.writer,
531 c.typenames,
532 *c.type.GetTypeParameters()[1].get(),
533 c.parcel,
534 "v",
535 c.is_return_value,
536 c.is_classloader_created,
537 c.filename,
538 };
539 CreateFromParcelFor(value_context);
540 c.writer << c.var << ".put(k, v);\n";
541
542 c.writer.Dedent();
543 c.writer << "});\n";
544
545 c.writer.Dedent();
546 c.writer << "}\n";
547 } else {
548 const string classloader = EnsureAndGetClassloader(const_cast<CodeGeneratorContext&>(c));
549 c.writer << c.var << " = " << c.parcel << ".readHashMap(" << classloader << ");\n";
550 }
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900551 }},
552 {"IBinder",
553 [](const CodeGeneratorContext& c) {
554 c.writer << c.var << " = " << c.parcel << ".readStrongBinder();\n";
555 }},
556 {"IBinder[]",
557 [](const CodeGeneratorContext& c) {
558 c.writer << c.var << " = " << c.parcel << ".createBinderArray();\n";
559 }},
560 {"FileDescriptor",
561 [](const CodeGeneratorContext& c) {
562 c.writer << c.var << " = " << c.parcel << ".readRawFileDescriptor();\n";
563 }},
564 {"FileDescriptor[]",
565 [](const CodeGeneratorContext& c) {
566 c.writer << c.var << " = " << c.parcel << ".createRawFileDescriptorArray();\n";
567 }},
Jiyong Parke05195e2018-10-08 18:24:23 +0900568 {"ParcelFileDescriptor",
569 [](const CodeGeneratorContext& c) {
Jiyong Parkd53fdbe2018-11-14 15:53:32 +0900570 // This is same as readTypedObject which was introduced with SDK 23.
571 // Keeping below code so that the generated code is buildable with older SDK.
572 c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n";
573 c.writer.Indent();
574 c.writer << c.var << " = " << "android.os.ParcelFileDescriptor.CREATOR.createFromParcel(" << c.parcel
575 << ");\n";
576 c.writer.Dedent();
577 c.writer << "}\n";
578 c.writer << "else {\n";
579 c.writer.Indent();
580 c.writer << c.var << " = null;\n";
581 c.writer.Dedent();
582 c.writer << "}\n";
Jiyong Parke05195e2018-10-08 18:24:23 +0900583 }},
584 {"ParcelFileDescriptor[]",
585 [](const CodeGeneratorContext& c) {
586 c.writer << c.var << " = " << c.parcel
587 << ".createTypedArray(android.os.ParcelFileDescriptor.CREATOR);\n";
588 }},
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900589 {"CharSequence",
590 [](const CodeGeneratorContext& c) {
591 // We have written 0 for null CharSequence.
592 c.writer << "if (0!=" << c.parcel << ".readInt()) {\n";
593 c.writer.Indent();
594 c.writer << c.var << " = android.text.TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel("
595 << c.parcel << ");\n";
596 c.writer.Dedent();
597 c.writer << "}\n";
598 c.writer << "else {\n";
599 c.writer.Indent();
600 c.writer << c.var << " = null;\n";
601 c.writer.Dedent();
602 c.writer << "}\n";
603 }},
Jeongik Cha649e8a72020-03-27 17:47:40 +0900604 {"ParcelableHolder",
605 [](const CodeGeneratorContext& c) {
606 c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n";
607 c.writer.Indent();
608 c.writer << c.var << ".readFromParcel(" << c.parcel << ");\n";
609 c.writer.Dedent();
610 c.writer << "}\n";
611 }},
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900612 };
Daniel Norman716d3112019-09-10 13:11:56 -0700613 const auto found = method_map.find(AidlBackingTypeName(c.type, c.typenames));
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900614 if (found != method_map.end()) {
615 found->second(c);
616 } else {
617 const AidlDefinedType* t = c.typenames.TryGetDefinedType(c.type.GetName());
618 CHECK(t != nullptr) << "Unknown type: " << c.type.GetName() << endl;
619 if (t->AsInterface() != nullptr) {
620 if (!c.type.IsArray()) {
621 c.writer << c.var << " = " << c.type.GetName() << ".Stub.asInterface(" << c.parcel
622 << ".readStrongBinder());\n";
623 }
624 } else if (t->AsParcelable() != nullptr || t->AsStructuredParcelable() != nullptr) {
625 if (c.type.IsArray()) {
Daniel Norman716d3112019-09-10 13:11:56 -0700626 c.writer << c.var << " = " << c.parcel << ".createTypedArray("
627 << JavaNameOf(c.type, c.typenames) << ".CREATOR);\n";
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900628 } else {
629 // This is same as readTypedObject.
630 // Keeping below code just not to break unit tests.
631 c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n";
632 c.writer.Indent();
633 c.writer << c.var << " = " << c.type.GetName() << ".CREATOR.createFromParcel(" << c.parcel
634 << ");\n";
635 c.writer.Dedent();
636 c.writer << "}\n";
637 c.writer << "else {\n";
638 c.writer.Indent();
639 c.writer << c.var << " = null;\n";
640 c.writer.Dedent();
641 c.writer << "}\n";
642 }
643 }
644 }
645 return true;
646}
647
648bool ReadFromParcelFor(const CodeGeneratorContext& c) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900649 static map<string, function<void(const CodeGeneratorContext&)>> method_map{
650 {"boolean[]",
651 [](const CodeGeneratorContext& c) {
652 c.writer << c.parcel << ".readBooleanArray(" << c.var << ");\n";
653 }},
654 {"byte[]",
655 [](const CodeGeneratorContext& c) {
656 c.writer << c.parcel << ".readByteArray(" << c.var << ");\n";
657 }},
658 {"char[]",
659 [](const CodeGeneratorContext& c) {
660 c.writer << c.parcel << ".readCharArray(" << c.var << ");\n";
661 }},
662 {"int[]",
663 [](const CodeGeneratorContext& c) {
664 c.writer << c.parcel << ".readIntArray(" << c.var << ");\n";
665 }},
666 {"long[]",
667 [](const CodeGeneratorContext& c) {
668 c.writer << c.parcel << ".readLongArray(" << c.var << ");\n";
669 }},
670 {"float[]",
671 [](const CodeGeneratorContext& c) {
672 c.writer << c.parcel << ".readFloatArray(" << c.var << ");\n";
673 }},
674 {"double[]",
675 [](const CodeGeneratorContext& c) {
676 c.writer << c.parcel << ".readDoubleArray(" << c.var << ");\n";
677 }},
678 {"String[]",
679 [](const CodeGeneratorContext& c) {
680 c.writer << c.parcel << ".readStringArray(" << c.var << ");\n";
681 }},
682 {"List",
683 [](const CodeGeneratorContext& c) {
684 if (c.type.IsGeneric()) {
685 const string& contained_type = c.type.GetTypeParameters().at(0)->GetName();
686 if (AidlTypenames::IsBuiltinTypename(contained_type)) {
687 if (contained_type == "String") {
688 c.writer << c.parcel << ".readStringList(" << c.var << ");\n";
689 } else if (contained_type == "IBinder") {
690 c.writer << c.parcel << ".readBinderList(" << c.var << ");\n";
691 }
692 } else {
693 const AidlDefinedType* t = c.typenames.TryGetDefinedType(contained_type);
694 CHECK(t != nullptr) << "Unknown type: " << contained_type << endl;
695 if (t->AsParcelable() != nullptr) {
696 c.writer << c.parcel << ".readTypedList(" << c.var << ", "
Daniel Norman716d3112019-09-10 13:11:56 -0700697 << JavaNameOf(*(c.type.GetTypeParameters().at(0)), c.typenames)
698 << ".CREATOR);\n";
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900699 }
700 }
701 } else {
702 const string classloader = EnsureAndGetClassloader(const_cast<CodeGeneratorContext&>(c));
703 c.writer << c.parcel << ".readList(" << c.var << ", " << classloader << ");\n";
704 }
705 }},
706 {"Map",
707 [](const CodeGeneratorContext& c) {
Jeongik Chae48d9942020-01-02 17:39:00 +0900708 if (c.type.IsGeneric()) {
709 c.writer << "if (" << c.var << " != null) " << c.var << ".clear();\n";
710 c.writer << "java.util.stream.IntStream.range(0, " << c.parcel
711 << ".readInt()).forEach(i -> {\n";
712 c.writer.Indent();
713 c.writer << "String k = " << c.parcel << ".readString();\n";
714 c.writer << JavaNameOf(*(c.type.GetTypeParameters().at(1)), c.typenames) << " v;\n";
715 CodeGeneratorContext value_context{
716 c.writer,
717 c.typenames,
718 *c.type.GetTypeParameters()[1].get(),
719 c.parcel,
720 "v",
721 c.is_return_value,
722 c.is_classloader_created,
723 c.filename,
724 };
725 CreateFromParcelFor(value_context);
726 c.writer << c.var << ".put(k, v);\n";
727
728 c.writer.Dedent();
729 c.writer << "});\n";
730
731 c.writer.Dedent();
732 c.writer << "}\n";
733 } else {
734 const string classloader = EnsureAndGetClassloader(const_cast<CodeGeneratorContext&>(c));
735 c.writer << c.var << " = " << c.parcel << ".readHashMap(" << classloader << ");\n";
736 }
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900737 }},
738 {"IBinder[]",
739 [](const CodeGeneratorContext& c) {
740 c.writer << c.var << " = " << c.parcel << ".createBinderArray();\n";
741 }},
742 {"FileDescriptor[]",
743 [](const CodeGeneratorContext& c) {
744 c.writer << c.var << " = " << c.parcel << ".createRawFileDescriptorArray();\n";
745 }},
Jiyong Parke05195e2018-10-08 18:24:23 +0900746 {"ParcelFileDescriptor",
747 [](const CodeGeneratorContext& c) {
Jiyong Parkd53fdbe2018-11-14 15:53:32 +0900748 c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n";
749 c.writer.Indent();
750 c.writer << c.var << " = " << "android.os.ParcelFileDescriptor.CREATOR.createFromParcel(" << c.parcel << ");\n";
751 c.writer.Dedent();
752 c.writer << "}\n";
Jiyong Parke05195e2018-10-08 18:24:23 +0900753 }},
754 {"ParcelFileDescriptor[]",
755 [](const CodeGeneratorContext& c) {
756 c.writer << c.parcel << ".readTypedArray(" << c.var
757 << ", android.os.ParcelFileDescriptor.CREATOR);\n";
758 }},
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900759 };
Daniel Norman716d3112019-09-10 13:11:56 -0700760 const auto& found = method_map.find(AidlBackingTypeName(c.type, c.typenames));
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900761 if (found != method_map.end()) {
762 found->second(c);
763 } else {
764 const AidlDefinedType* t = c.typenames.TryGetDefinedType(c.type.GetName());
765 CHECK(t != nullptr) << "Unknown type: " << c.type.GetName() << endl;
766 if (t->AsParcelable() != nullptr) {
767 if (c.type.IsArray()) {
768 c.writer << c.parcel << ".readTypedArray(" << c.var << ", " << c.type.GetName()
769 << ".CREATOR);\n";
770 } else {
771 c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n";
772 c.writer.Indent();
773 c.writer << c.var << ".readFromParcel(" << c.parcel << ");\n";
774 c.writer.Dedent();
775 c.writer << "}\n";
776 }
777 }
778 }
779 return true;
780}
781
Jiyong Park43113fb2020-07-20 16:26:19 +0900782void ToStringFor(const CodeGeneratorContext& c) {
783 if (c.type.IsArray()) {
784 // Arrays can be null
785 c.writer << c.var << " == null ? \"null\" : ";
786 c.writer << "java.util.Arrays.toString(" << c.var << ")";
787 return;
788 }
789
790 const std::string name = c.type.GetName();
791
792 if (AidlTypenames::IsPrimitiveTypename(name)) {
793 c.writer << c.var;
794 return;
795 }
796
797 const AidlDefinedType* t = c.typenames.TryGetDefinedType(name);
798 if (t != nullptr && t->AsEnumDeclaration()) {
799 c.writer << c.var;
800 return;
801 }
802
803 // FileDescriptor doesn't have a good toString() impl.
804 if (name == "FileDescriptor") {
805 c.writer << c.var << " == null ? \"null\" : ";
806 c.writer << c.var << ".getInt$()";
807 return;
808 }
809
810 // Rest of the built-in types have reasonable toString() impls.
811 if (AidlTypenames::IsBuiltinTypename(name)) {
812 c.writer << "java.util.Objects.toString(" << c.var << ")";
813 return;
814 }
815
816 // For user-defined types, we also use toString() that we are generating here, but just make sure
817 // that they are actually user-defined types.
818 AIDL_FATAL_IF(t == nullptr, c.type) << "Unknown type";
819 if (t->AsInterface() != nullptr || t->AsParcelable() != nullptr) {
820 c.writer << c.var << ".toString()";
821 return;
822 }
823 CHECK(true) << "Unhandled typename: " << name << endl;
824}
825
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900826} // namespace java
827} // namespace aidl
828} // namespace android