1 /*
2 * Copyright (C) 2016, 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_java.h"
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <map>
23 #include <memory>
24 #include <sstream>
25
26 #include <android-base/stringprintf.h>
27
28 #include "aidl_to_java.h"
29 #include "code_writer.h"
30 #include "logging.h"
31
32 using std::unique_ptr;
33 using ::android::aidl::java::Variable;
34 using std::string;
35
36 namespace android {
37 namespace aidl {
38 namespace java {
39
generate_java_interface(const string & filename,const AidlInterface * iface,const AidlTypenames & typenames,const IoDelegate & io_delegate,const Options & options)40 bool generate_java_interface(const string& filename, const AidlInterface* iface,
41 const AidlTypenames& typenames, const IoDelegate& io_delegate,
42 const Options& options) {
43 auto cl = generate_binder_interface_class(iface, typenames, options);
44
45 std::unique_ptr<Document> document =
46 std::make_unique<Document>("" /* no comment */, iface->GetPackage(), std::move(cl));
47
48 CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
49 document->Write(code_writer.get());
50
51 return true;
52 }
53
generate_java_parcel(const std::string & filename,const AidlStructuredParcelable * parcel,const AidlTypenames & typenames,const IoDelegate & io_delegate)54 bool generate_java_parcel(const std::string& filename, const AidlStructuredParcelable* parcel,
55 const AidlTypenames& typenames, const IoDelegate& io_delegate) {
56 auto cl = generate_parcel_class(parcel, typenames);
57
58 std::unique_ptr<Document> document =
59 std::make_unique<Document>("" /* no comment */, parcel->GetPackage(), std::move(cl));
60
61 CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
62 document->Write(code_writer.get());
63
64 return true;
65 }
66
generate_java_enum_declaration(const std::string & filename,const AidlEnumDeclaration * enum_decl,const AidlTypenames & typenames,const IoDelegate & io_delegate)67 bool generate_java_enum_declaration(const std::string& filename,
68 const AidlEnumDeclaration* enum_decl,
69 const AidlTypenames& typenames, const IoDelegate& io_delegate) {
70 CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
71 generate_enum(code_writer, enum_decl, typenames);
72 return true;
73 }
74
generate_java(const std::string & filename,const AidlDefinedType * defined_type,const AidlTypenames & typenames,const IoDelegate & io_delegate,const Options & options)75 bool generate_java(const std::string& filename, const AidlDefinedType* defined_type,
76 const AidlTypenames& typenames, const IoDelegate& io_delegate,
77 const Options& options) {
78 if (const AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable();
79 parcelable != nullptr) {
80 return generate_java_parcel(filename, parcelable, typenames, io_delegate);
81 }
82
83 if (const AidlEnumDeclaration* enum_decl = defined_type->AsEnumDeclaration();
84 enum_decl != nullptr) {
85 return generate_java_enum_declaration(filename, enum_decl, typenames, io_delegate);
86 }
87
88 if (const AidlInterface* interface = defined_type->AsInterface(); interface != nullptr) {
89 return generate_java_interface(filename, interface, typenames, io_delegate, options);
90 }
91
92 CHECK(false) << "Unrecognized type sent for java generation.";
93 return false;
94 }
95
generate_parcel_class(const AidlStructuredParcelable * parcel,const AidlTypenames & typenames)96 std::unique_ptr<android::aidl::java::Class> generate_parcel_class(
97 const AidlStructuredParcelable* parcel, const AidlTypenames& typenames) {
98 auto parcel_class = std::make_unique<Class>();
99 parcel_class->comment = parcel->GetComments();
100 parcel_class->modifiers = PUBLIC;
101 parcel_class->what = Class::CLASS;
102 parcel_class->type = parcel->GetCanonicalName();
103 parcel_class->interfaces.push_back("android.os.Parcelable");
104 parcel_class->annotations = generate_java_annotations(*parcel);
105
106 for (const auto& variable : parcel->GetFields()) {
107 std::ostringstream out;
108 out << variable->GetType().GetComments() << "\n";
109 for (const auto& a : generate_java_annotations(variable->GetType())) {
110 out << a << "\n";
111 }
112 out << "public ";
113
114 if (variable->GetType().GetName() == "ParcelableHolder" || parcel->IsImmutable()) {
115 out << "final ";
116 }
117 out << JavaSignatureOf(variable->GetType(), typenames) << " " << variable->GetName();
118 if (!parcel->IsImmutable() && variable->GetDefaultValue()) {
119 out << " = " << variable->ValueString(ConstantValueDecorator);
120 } else if (variable->GetType().GetName() == "ParcelableHolder") {
121 out << std::boolalpha;
122 out << " = new " << JavaSignatureOf(variable->GetType(), typenames) << "(";
123 if (parcel->IsVintfStability()) {
124 out << "android.os.Parcelable.PARCELABLE_STABILITY_VINTF";
125 } else {
126 out << "android.os.Parcelable.PARCELABLE_STABILITY_LOCAL";
127 }
128 out << ")";
129 out << std::noboolalpha;
130 }
131 out << ";\n";
132 parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str()));
133 }
134
135 std::ostringstream out;
136
137 if (parcel->IsVintfStability()) {
138 out << "public final int getStability() { return "
139 "android.os.Parcelable.PARCELABLE_STABILITY_VINTF; }\n";
140 parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str()));
141 }
142
143 out.str("");
144 out << "public static final android.os.Parcelable.Creator<" << parcel->GetName() << "> CREATOR = "
145 << "new android.os.Parcelable.Creator<" << parcel->GetName() << ">() {\n";
146 out << " @Override\n";
147 out << " public " << parcel->GetName()
148 << " createFromParcel(android.os.Parcel _aidl_source) {\n";
149 if (parcel->IsImmutable()) {
150 out << " return new " << parcel->GetName() << "(_aidl_source);\n";
151 } else {
152 out << " " << parcel->GetName() << " _aidl_out = new " << parcel->GetName() << "();\n";
153 out << " _aidl_out.readFromParcel(_aidl_source);\n";
154 out << " return _aidl_out;\n";
155 }
156 out << " }\n";
157 out << " @Override\n";
158 out << " public " << parcel->GetName() << "[] newArray(int _aidl_size) {\n";
159 out << " return new " << parcel->GetName() << "[_aidl_size];\n";
160 out << " }\n";
161 out << "};\n";
162 parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str()));
163
164 auto flag_variable = std::make_shared<Variable>("int", "_aidl_flag");
165 auto parcel_variable = std::make_shared<Variable>("android.os.Parcel", "_aidl_parcel");
166
167 auto write_method = std::make_shared<Method>();
168 write_method->modifiers = PUBLIC | OVERRIDE | FINAL;
169 write_method->returnType = "void";
170 write_method->name = "writeToParcel";
171 write_method->parameters.push_back(parcel_variable);
172 write_method->parameters.push_back(flag_variable);
173 write_method->statements = std::make_shared<StatementBlock>();
174
175 out.str("");
176 out << "int _aidl_start_pos = _aidl_parcel.dataPosition();\n"
177 << "_aidl_parcel.writeInt(0);\n";
178 write_method->statements->Add(std::make_shared<LiteralStatement>(out.str()));
179
180 for (const auto& field : parcel->GetFields()) {
181 string code;
182 CodeWriterPtr writer = CodeWriter::ForString(&code);
183 CodeGeneratorContext context{
184 .writer = *(writer.get()),
185 .typenames = typenames,
186 .type = field->GetType(),
187 .parcel = parcel_variable->name,
188 .var = field->GetName(),
189 .is_return_value = false,
190 };
191 WriteToParcelFor(context);
192 writer->Close();
193 write_method->statements->Add(std::make_shared<LiteralStatement>(code));
194 }
195
196 out.str("");
197 out << "int _aidl_end_pos = _aidl_parcel.dataPosition();\n"
198 << "_aidl_parcel.setDataPosition(_aidl_start_pos);\n"
199 << "_aidl_parcel.writeInt(_aidl_end_pos - _aidl_start_pos);\n"
200 << "_aidl_parcel.setDataPosition(_aidl_end_pos);\n";
201
202 write_method->statements->Add(std::make_shared<LiteralStatement>(out.str()));
203
204 parcel_class->elements.push_back(write_method);
205
206 if (parcel->IsImmutable()) {
207 auto constructor = std::make_shared<Method>();
208 constructor->modifiers = PUBLIC;
209 constructor->name = parcel->GetName();
210 constructor->statements = std::make_shared<StatementBlock>();
211 for (const auto& field : parcel->GetFields()) {
212 constructor->parameters.push_back(std::make_shared<Variable>(
213 JavaSignatureOf(field->GetType(), typenames), field->GetName()));
214 out.str("");
215
216 out << "this." << field->GetName() << " = ";
217 if (field->GetType().GetName() == "List") {
218 out << field->GetName() << " == null ? null : java.util.Collections.unmodifiableList("
219 << field->GetName() << ");\n";
220 } else if (field->GetType().GetName() == "Map") {
221 out << field->GetName() << " == null ? null : java.util.Collections.unmodifiableMap("
222 << field->GetName() << ");\n";
223 } else {
224 out << field->GetName() << ";\n";
225 }
226 constructor->statements->Add(std::make_shared<LiteralStatement>(out.str()));
227 }
228 parcel_class->elements.push_back(constructor);
229 }
230
231 // For an immutable parcelable, generate a constructor with a parcel object,
232 // Otherwise, generate readFromParcel method.
233 auto read_or_create_method = std::make_shared<Method>();
234 if (parcel->IsImmutable()) {
235 auto constructor = std::make_shared<Method>();
236 read_or_create_method->modifiers = PUBLIC;
237 read_or_create_method->name = parcel->GetName();
238 read_or_create_method->parameters.push_back(parcel_variable);
239 read_or_create_method->statements = std::make_shared<StatementBlock>();
240 } else {
241 read_or_create_method->modifiers = PUBLIC | FINAL;
242 read_or_create_method->returnType = "void";
243 read_or_create_method->name = "readFromParcel";
244 read_or_create_method->parameters.push_back(parcel_variable);
245 read_or_create_method->statements = std::make_shared<StatementBlock>();
246 }
247 out.str("");
248 if (parcel->IsImmutable()) {
249 for (const auto& field : parcel->GetFields()) {
250 out << JavaSignatureOf(field->GetType(), typenames) << " " << field->GetName();
251 if (field->GetDefaultValue()) {
252 out << " = " << field->ValueString(ConstantValueDecorator);
253 } else {
254 out << " = null";
255 }
256 out << ";\n";
257 }
258 }
259 out << "int _aidl_start_pos = _aidl_parcel.dataPosition();\n"
260 << "int _aidl_parcelable_size = _aidl_parcel.readInt();\n"
261 << "try {\n"
262 << " if (_aidl_parcelable_size < 0) return;\n";
263
264 read_or_create_method->statements->Add(std::make_shared<LiteralStatement>(out.str()));
265
266 out.str("");
267 out << " if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;\n";
268
269 std::shared_ptr<LiteralStatement> sizeCheck = nullptr;
270 // keep this across different fields in order to create the classloader
271 // at most once.
272 bool is_classloader_created = false;
273 for (const auto& field : parcel->GetFields()) {
274 const auto field_variable_name =
275 (parcel->IsImmutable() ? "_aidl_temp_" : "") + field->GetName();
276 string code;
277 CodeWriterPtr writer = CodeWriter::ForString(&code);
278 CodeGeneratorContext context{
279 .writer = *(writer.get()),
280 .typenames = typenames,
281 .type = field->GetType(),
282 .parcel = parcel_variable->name,
283 .var = field_variable_name,
284 .is_classloader_created = &is_classloader_created,
285 };
286 context.writer.Indent();
287 if (parcel->IsImmutable()) {
288 context.writer.Write("%s %s;\n", JavaSignatureOf(field->GetType(), typenames).c_str(),
289 field_variable_name.c_str());
290 }
291 CreateFromParcelFor(context);
292 if (parcel->IsImmutable()) {
293 context.writer.Write("%s = %s;\n", field->GetName().c_str(), field_variable_name.c_str());
294 }
295 writer->Close();
296 read_or_create_method->statements->Add(std::make_shared<LiteralStatement>(code));
297 if (!sizeCheck) sizeCheck = std::make_shared<LiteralStatement>(out.str());
298 read_or_create_method->statements->Add(sizeCheck);
299 }
300
301 out.str("");
302 out << "} finally {\n"
303 << " _aidl_parcel.setDataPosition(_aidl_start_pos + _aidl_parcelable_size);\n";
304 if (parcel->IsImmutable()) {
305 for (const auto& field : parcel->GetFields()) {
306 out << " this." << field->GetName() << " = ";
307 if (field->GetType().GetName() == "List") {
308 out << "java.util.Collections.unmodifiableList(" << field->GetName() << ");\n";
309 } else if (field->GetType().GetName() == "Map") {
310 out << "java.util.Collections.unmodifiableMap(" << field->GetName() << ");\n";
311 } else {
312 out << field->GetName() << ";\n";
313 }
314 }
315 }
316 out << "}\n";
317
318 read_or_create_method->statements->Add(std::make_shared<LiteralStatement>(out.str()));
319
320 parcel_class->elements.push_back(read_or_create_method);
321
322 if (parcel->IsJavaDebug()) {
323 out.str("");
324 out << "@Override\n";
325 out << "public String toString() {\n";
326 out << " java.util.StringJoiner _aidl_sj = new java.util.StringJoiner(";
327 out << "\", \", \"{\", \"}\");\n";
328 for (const auto& field : parcel->GetFields()) {
329 std::string code;
330 CodeWriterPtr writer = CodeWriter::ForString(&code);
331 CodeGeneratorContext context{
332 .writer = *(writer.get()),
333 .typenames = typenames,
334 .type = field->GetType(),
335 .parcel = parcel_variable->name,
336 .var = field->GetName(),
337 .is_classloader_created = &is_classloader_created,
338 };
339 ToStringFor(context);
340 writer->Close();
341 out << " _aidl_sj.add(\"" << field->GetName() << ": \" + (" << code << "));\n";
342 }
343 out << " return \"" << parcel->GetCanonicalName() << "\" + _aidl_sj.toString() ;\n";
344 out << "}\n";
345 parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str()));
346 }
347
348 auto describe_contents_method = std::make_shared<Method>();
349 describe_contents_method->modifiers = PUBLIC | OVERRIDE;
350 describe_contents_method->returnType = "int";
351 describe_contents_method->name = "describeContents";
352 describe_contents_method->statements = std::make_shared<StatementBlock>();
353 describe_contents_method->statements->Add(std::make_shared<LiteralStatement>("return 0;\n"));
354 parcel_class->elements.push_back(describe_contents_method);
355
356 return parcel_class;
357 }
358
generate_enum(const CodeWriterPtr & code_writer,const AidlEnumDeclaration * enum_decl,const AidlTypenames & typenames)359 void generate_enum(const CodeWriterPtr& code_writer, const AidlEnumDeclaration* enum_decl,
360 const AidlTypenames& typenames) {
361 code_writer->Write(
362 "/*\n"
363 " * This file is auto-generated. DO NOT MODIFY.\n"
364 " */\n");
365
366 code_writer->Write("package %s;\n", enum_decl->GetPackage().c_str());
367 code_writer->Write("%s\n", enum_decl->GetComments().c_str());
368 for (const std::string& annotation : generate_java_annotations(*enum_decl)) {
369 code_writer->Write("%s", annotation.c_str());
370 }
371 code_writer->Write("public @interface %s {\n", enum_decl->GetName().c_str());
372 code_writer->Indent();
373 for (const auto& enumerator : enum_decl->GetEnumerators()) {
374 code_writer->Write("%s", enumerator->GetComments().c_str());
375 code_writer->Write(
376 "public static final %s %s = %s;\n",
377 JavaSignatureOf(enum_decl->GetBackingType(), typenames).c_str(),
378 enumerator->GetName().c_str(),
379 enumerator->ValueString(enum_decl->GetBackingType(), ConstantValueDecorator).c_str());
380 }
381 code_writer->Dedent();
382 code_writer->Write("}\n");
383 }
384
dump_location(const AidlNode & method)385 std::string dump_location(const AidlNode& method) {
386 return method.PrintLocation();
387 }
388
generate_java_unsupportedappusage_parameters(const AidlAnnotation & a)389 std::string generate_java_unsupportedappusage_parameters(const AidlAnnotation& a) {
390 const std::map<std::string, std::string> params = a.AnnotationParams(ConstantValueDecorator);
391 std::vector<string> parameters_decl;
392 for (const auto& name_and_param : params) {
393 const std::string& param_name = name_and_param.first;
394 const std::string& param_value = name_and_param.second;
395 parameters_decl.push_back(param_name + " = " + param_value);
396 }
397 parameters_decl.push_back("overrideSourcePosition=\"" + dump_location(a) + "\"");
398 return "(" + base::Join(parameters_decl, ", ") + ")";
399 }
400
generate_java_annotations(const AidlAnnotatable & a)401 std::vector<std::string> generate_java_annotations(const AidlAnnotatable& a) {
402 std::vector<std::string> result;
403 if (a.IsHide()) {
404 result.emplace_back("@android.annotation.Hide");
405 }
406
407 const AidlAnnotation* unsupported_app_usage = a.UnsupportedAppUsage();
408 if (unsupported_app_usage != nullptr) {
409 result.emplace_back("@android.compat.annotation.UnsupportedAppUsage" +
410 generate_java_unsupportedappusage_parameters(*unsupported_app_usage));
411 }
412
413 auto strip_double_quote = [](const AidlTypeSpecifier& type, const std::string& raw_value) -> std::string {
414 if (!android::base::StartsWith(raw_value, "\"") ||
415 !android::base::EndsWith(raw_value, "\"")) {
416 AIDL_FATAL(type) << "Java passthrough annotation " << raw_value << " is not properly quoted";
417 return "";
418 }
419 return raw_value.substr(1, raw_value.size() - 2);
420 };
421
422 const AidlAnnotation* java_passthrough = a.JavaPassthrough();
423 if (java_passthrough != nullptr) {
424 for (const auto& name_and_param : java_passthrough->AnnotationParams(strip_double_quote)) {
425 if (name_and_param.first == "annotation") {
426 result.emplace_back(name_and_param.second);
427 break;
428 }
429 }
430 }
431
432 return result;
433 }
434
435 } // namespace java
436 } // namespace aidl
437 } // namespace android
438