Christopher Wiley | 3a9da17 | 2016-01-29 11:10:49 -0800 | [diff] [blame] | 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 | |
Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 17 | #include "generate_java.h" |
Christopher Wiley | fdeb0f4 | 2015-09-11 15:38:22 -0700 | [diff] [blame] | 18 | |
Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 19 | #include <stdio.h> |
| 20 | #include <stdlib.h> |
| 21 | #include <string.h> |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 22 | |
| 23 | #include <algorithm> |
Andrei Onea | 9445fc6 | 2019-06-27 18:11:59 +0100 | [diff] [blame] | 24 | #include <map> |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 25 | #include <memory> |
| 26 | #include <sstream> |
Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 27 | |
Christopher Wiley | 3a9da17 | 2016-01-29 11:10:49 -0800 | [diff] [blame] | 28 | #include <android-base/stringprintf.h> |
| 29 | |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 30 | #include "aidl_to_java.h" |
Christopher Wiley | fdeb0f4 | 2015-09-11 15:38:22 -0700 | [diff] [blame] | 31 | #include "code_writer.h" |
Jeongik Cha | a2080bf | 2019-06-18 16:44:29 +0900 | [diff] [blame] | 32 | #include "logging.h" |
Christopher Wiley | fdeb0f4 | 2015-09-11 15:38:22 -0700 | [diff] [blame] | 33 | |
Christopher Wiley | f76b59a | 2016-01-29 11:32:11 -0800 | [diff] [blame] | 34 | using std::unique_ptr; |
Christopher Wiley | db154a5 | 2015-09-28 16:32:25 -0700 | [diff] [blame] | 35 | using ::android::aidl::java::Variable; |
Christopher Wiley | 3a9da17 | 2016-01-29 11:10:49 -0800 | [diff] [blame] | 36 | using std::string; |
Christopher Wiley | db154a5 | 2015-09-28 16:32:25 -0700 | [diff] [blame] | 37 | |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 38 | namespace { |
| 39 | inline string get_setter_name(const string& variablename) { |
| 40 | CHECK(variablename.size() > 0) << "A field name cannot be empty."; |
| 41 | std::ostringstream out; |
| 42 | out << "set" << static_cast<char>(toupper(variablename[0])) << variablename.substr(1); |
| 43 | return out.str(); |
| 44 | } |
| 45 | } // namespace |
| 46 | |
Christopher Wiley | fdeb0f4 | 2015-09-11 15:38:22 -0700 | [diff] [blame] | 47 | namespace android { |
| 48 | namespace aidl { |
Christopher Wiley | db154a5 | 2015-09-28 16:32:25 -0700 | [diff] [blame] | 49 | namespace java { |
| 50 | |
Jiyong Park | 54fa1e0 | 2019-02-08 10:03:20 +0900 | [diff] [blame] | 51 | bool generate_java_interface(const string& filename, const AidlInterface* iface, |
Jeongik Cha | a2080bf | 2019-06-18 16:44:29 +0900 | [diff] [blame] | 52 | const AidlTypenames& typenames, const IoDelegate& io_delegate, |
Jiyong Park | 54fa1e0 | 2019-02-08 10:03:20 +0900 | [diff] [blame] | 53 | const Options& options) { |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 54 | auto cl = generate_binder_interface_class(iface, typenames, options); |
Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 55 | |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 56 | std::unique_ptr<Document> document = |
| 57 | std::make_unique<Document>("" /* no comment */, iface->GetPackage(), std::move(cl)); |
Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 58 | |
Christopher Wiley | 3a9da17 | 2016-01-29 11:10:49 -0800 | [diff] [blame] | 59 | CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename); |
| 60 | document->Write(code_writer.get()); |
Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 61 | |
Jiyong Park | 74595c1 | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 62 | return true; |
Adam Lesinski | ffa1686 | 2014-01-23 18:17:42 -0800 | [diff] [blame] | 63 | } |
| 64 | |
Jiyong Park | 54fa1e0 | 2019-02-08 10:03:20 +0900 | [diff] [blame] | 65 | bool generate_java_parcel(const std::string& filename, const AidlStructuredParcelable* parcel, |
Jeongik Cha | a2080bf | 2019-06-18 16:44:29 +0900 | [diff] [blame] | 66 | const AidlTypenames& typenames, const IoDelegate& io_delegate) { |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 67 | auto cl = generate_parcel_class(parcel, typenames); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 68 | |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 69 | std::unique_ptr<Document> document = |
| 70 | std::make_unique<Document>("" /* no comment */, parcel->GetPackage(), std::move(cl)); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 71 | |
| 72 | CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename); |
| 73 | document->Write(code_writer.get()); |
| 74 | |
Jiyong Park | 74595c1 | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 75 | return true; |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 76 | } |
| 77 | |
Daniel Norman | 716d311 | 2019-09-10 13:11:56 -0700 | [diff] [blame] | 78 | bool generate_java_enum_declaration(const std::string& filename, |
| 79 | const AidlEnumDeclaration* enum_decl, |
| 80 | const AidlTypenames& typenames, const IoDelegate& io_delegate) { |
| 81 | CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename); |
| 82 | generate_enum(code_writer, enum_decl, typenames); |
| 83 | return true; |
| 84 | } |
| 85 | |
Jiyong Park | 54fa1e0 | 2019-02-08 10:03:20 +0900 | [diff] [blame] | 86 | bool generate_java(const std::string& filename, const AidlDefinedType* defined_type, |
Jeongik Cha | a2080bf | 2019-06-18 16:44:29 +0900 | [diff] [blame] | 87 | const AidlTypenames& typenames, const IoDelegate& io_delegate, |
Jiyong Park | 54fa1e0 | 2019-02-08 10:03:20 +0900 | [diff] [blame] | 88 | const Options& options) { |
Daniel Norman | 716d311 | 2019-09-10 13:11:56 -0700 | [diff] [blame] | 89 | if (const AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable(); |
| 90 | parcelable != nullptr) { |
Jeongik Cha | a2080bf | 2019-06-18 16:44:29 +0900 | [diff] [blame] | 91 | return generate_java_parcel(filename, parcelable, typenames, io_delegate); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 92 | } |
| 93 | |
Daniel Norman | 716d311 | 2019-09-10 13:11:56 -0700 | [diff] [blame] | 94 | if (const AidlEnumDeclaration* enum_decl = defined_type->AsEnumDeclaration(); |
| 95 | enum_decl != nullptr) { |
| 96 | return generate_java_enum_declaration(filename, enum_decl, typenames, io_delegate); |
| 97 | } |
| 98 | |
| 99 | if (const AidlInterface* interface = defined_type->AsInterface(); interface != nullptr) { |
Jeongik Cha | a2080bf | 2019-06-18 16:44:29 +0900 | [diff] [blame] | 100 | return generate_java_interface(filename, interface, typenames, io_delegate, options); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 101 | } |
| 102 | |
Daniel Norman | 85aed54 | 2019-08-21 12:01:14 -0700 | [diff] [blame] | 103 | CHECK(false) << "Unrecognized type sent for java generation."; |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 104 | return false; |
| 105 | } |
| 106 | |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 107 | std::unique_ptr<android::aidl::java::Class> generate_parcel_class( |
| 108 | const AidlStructuredParcelable* parcel, const AidlTypenames& typenames) { |
| 109 | auto parcel_class = std::make_unique<Class>(); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 110 | parcel_class->comment = parcel->GetComments(); |
| 111 | parcel_class->modifiers = PUBLIC; |
| 112 | parcel_class->what = Class::CLASS; |
Jeongik Cha | aabc144 | 2019-02-12 17:44:48 +0900 | [diff] [blame] | 113 | parcel_class->type = parcel->GetCanonicalName(); |
| 114 | parcel_class->interfaces.push_back("android.os.Parcelable"); |
Jiyong Park | a6605ab | 2018-11-11 14:30:21 +0900 | [diff] [blame] | 115 | parcel_class->annotations = generate_java_annotations(*parcel); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 116 | |
Devin Moore | 53fc99c | 2020-08-12 08:07:52 -0700 | [diff] [blame] | 117 | if (parcel->IsGeneric()) { |
| 118 | parcel_class->type += "<" + base::Join(parcel->GetTypeParameters(), ",") + ">"; |
| 119 | } |
| 120 | |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 121 | for (const auto& variable : parcel->GetFields()) { |
Steven Moreland | 9ea10e3 | 2018-07-19 15:26:09 -0700 | [diff] [blame] | 122 | std::ostringstream out; |
Jiyong Park | a6605ab | 2018-11-11 14:30:21 +0900 | [diff] [blame] | 123 | out << variable->GetType().GetComments() << "\n"; |
| 124 | for (const auto& a : generate_java_annotations(variable->GetType())) { |
| 125 | out << a << "\n"; |
| 126 | } |
Jeongik Cha | 649e8a7 | 2020-03-27 17:47:40 +0900 | [diff] [blame] | 127 | out << "public "; |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 128 | |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 129 | if (variable->GetType().GetName() == "ParcelableHolder" || parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 649e8a7 | 2020-03-27 17:47:40 +0900 | [diff] [blame] | 130 | out << "final "; |
| 131 | } |
| 132 | out << JavaSignatureOf(variable->GetType(), typenames) << " " << variable->GetName(); |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 133 | if (!parcel->IsJavaOnlyImmutable() && variable->GetDefaultValue()) { |
Daniel Norman | 37d43dd | 2019-09-09 17:22:34 -0700 | [diff] [blame] | 134 | out << " = " << variable->ValueString(ConstantValueDecorator); |
Jeongik Cha | 649e8a7 | 2020-03-27 17:47:40 +0900 | [diff] [blame] | 135 | } else if (variable->GetType().GetName() == "ParcelableHolder") { |
| 136 | out << std::boolalpha; |
Steven Moreland | 4768c96 | 2020-07-23 01:21:16 +0000 | [diff] [blame] | 137 | out << " = new " << JavaSignatureOf(variable->GetType(), typenames) << "("; |
| 138 | if (parcel->IsVintfStability()) { |
| 139 | out << "android.os.Parcelable.PARCELABLE_STABILITY_VINTF"; |
| 140 | } else { |
| 141 | out << "android.os.Parcelable.PARCELABLE_STABILITY_LOCAL"; |
| 142 | } |
| 143 | out << ")"; |
Jeongik Cha | 649e8a7 | 2020-03-27 17:47:40 +0900 | [diff] [blame] | 144 | out << std::noboolalpha; |
Steven Moreland | 9ea10e3 | 2018-07-19 15:26:09 -0700 | [diff] [blame] | 145 | } |
| 146 | out << ";\n"; |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 147 | parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str())); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 148 | } |
| 149 | |
| 150 | std::ostringstream out; |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 151 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 152 | auto builder_class = std::make_shared<Class>(); |
| 153 | builder_class->modifiers = PUBLIC | FINAL | STATIC; |
| 154 | builder_class->what = Class::CLASS; |
| 155 | builder_class->type = "Builder"; |
Jeongik Cha | 92d33d0 | 2020-05-14 00:53:57 +0900 | [diff] [blame] | 156 | |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 157 | out.str(""); |
| 158 | for (const auto& variable : parcel->GetFields()) { |
| 159 | out << "private " << JavaSignatureOf(variable->GetType(), typenames) << " " |
| 160 | << variable->GetName(); |
| 161 | if (variable->GetDefaultValue()) { |
| 162 | out << " = " << variable->ValueString(ConstantValueDecorator); |
| 163 | } |
| 164 | out << ";\n"; |
| 165 | out << "public Builder " << get_setter_name(variable->GetName()) << "(" |
| 166 | << JavaSignatureOf(variable->GetType(), typenames) << " " << variable->GetName() |
| 167 | << ") {\n" |
| 168 | << " " |
| 169 | << "this." << variable->GetName() << " = " << variable->GetName() << ";\n" |
| 170 | << " return this;\n" |
| 171 | << "}\n"; |
| 172 | } |
| 173 | out << "public " << parcel->GetCanonicalName() << " build() {\n" |
| 174 | << " return new " << parcel->GetCanonicalName() << "("; |
| 175 | std::vector<std::string> variables; |
| 176 | std::transform(parcel->GetFields().begin(), parcel->GetFields().end(), |
| 177 | std::back_inserter(variables), [](const auto& f) { return f->GetName(); }); |
| 178 | out << base::Join(variables, ", ") << ");\n" |
| 179 | << "}\n"; |
| 180 | builder_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str())); |
| 181 | parcel_class->elements.push_back(builder_class); |
| 182 | } |
Jeongik Cha | 92d33d0 | 2020-05-14 00:53:57 +0900 | [diff] [blame] | 183 | if (parcel->IsVintfStability()) { |
Steven Moreland | 82466d4 | 2020-08-05 18:05:57 +0000 | [diff] [blame] | 184 | parcel_class->elements.push_back(std::make_shared<LiteralClassElement>( |
| 185 | "@Override\n public final int getStability() { return " |
| 186 | "android.os.Parcelable.PARCELABLE_STABILITY_VINTF; }\n")); |
Jeongik Cha | 92d33d0 | 2020-05-14 00:53:57 +0900 | [diff] [blame] | 187 | } |
| 188 | |
| 189 | out.str(""); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 190 | out << "public static final android.os.Parcelable.Creator<" << parcel->GetName() << "> CREATOR = " |
| 191 | << "new android.os.Parcelable.Creator<" << parcel->GetName() << ">() {\n"; |
Jiyong Park | b77f7a5 | 2018-09-13 21:32:38 +0900 | [diff] [blame] | 192 | out << " @Override\n"; |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 193 | out << " public " << parcel->GetName() |
| 194 | << " createFromParcel(android.os.Parcel _aidl_source) {\n"; |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 195 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 196 | out << " return internalCreateFromParcel(_aidl_source);\n"; |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 197 | } else { |
| 198 | out << " " << parcel->GetName() << " _aidl_out = new " << parcel->GetName() << "();\n"; |
| 199 | out << " _aidl_out.readFromParcel(_aidl_source);\n"; |
| 200 | out << " return _aidl_out;\n"; |
| 201 | } |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 202 | out << " }\n"; |
Jiyong Park | b77f7a5 | 2018-09-13 21:32:38 +0900 | [diff] [blame] | 203 | out << " @Override\n"; |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 204 | out << " public " << parcel->GetName() << "[] newArray(int _aidl_size) {\n"; |
| 205 | out << " return new " << parcel->GetName() << "[_aidl_size];\n"; |
| 206 | out << " }\n"; |
| 207 | out << "};\n"; |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 208 | parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str())); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 209 | |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 210 | auto flag_variable = std::make_shared<Variable>("int", "_aidl_flag"); |
| 211 | auto parcel_variable = std::make_shared<Variable>("android.os.Parcel", "_aidl_parcel"); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 212 | |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 213 | auto write_method = std::make_shared<Method>(); |
Jeongik Cha | a2ada0c | 2018-11-17 15:11:45 +0900 | [diff] [blame] | 214 | write_method->modifiers = PUBLIC | OVERRIDE | FINAL; |
Jeongik Cha | 6cadc21 | 2019-02-12 18:16:03 +0900 | [diff] [blame] | 215 | write_method->returnType = "void"; |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 216 | write_method->name = "writeToParcel"; |
| 217 | write_method->parameters.push_back(parcel_variable); |
| 218 | write_method->parameters.push_back(flag_variable); |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 219 | write_method->statements = std::make_shared<StatementBlock>(); |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 220 | |
| 221 | out.str(""); |
| 222 | out << "int _aidl_start_pos = _aidl_parcel.dataPosition();\n" |
| 223 | << "_aidl_parcel.writeInt(0);\n"; |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 224 | write_method->statements->Add(std::make_shared<LiteralStatement>(out.str())); |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 225 | |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 226 | for (const auto& field : parcel->GetFields()) { |
| 227 | string code; |
| 228 | CodeWriterPtr writer = CodeWriter::ForString(&code); |
| 229 | CodeGeneratorContext context{ |
| 230 | .writer = *(writer.get()), |
Jeongik Cha | 6cadc21 | 2019-02-12 18:16:03 +0900 | [diff] [blame] | 231 | .typenames = typenames, |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 232 | .type = field->GetType(), |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 233 | .parcel = parcel_variable->name, |
Nick Desaulniers | 27e1ff6 | 2019-10-07 23:13:10 -0700 | [diff] [blame] | 234 | .var = field->GetName(), |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 235 | .is_return_value = false, |
| 236 | }; |
| 237 | WriteToParcelFor(context); |
| 238 | writer->Close(); |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 239 | write_method->statements->Add(std::make_shared<LiteralStatement>(code)); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 240 | } |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 241 | |
| 242 | out.str(""); |
| 243 | out << "int _aidl_end_pos = _aidl_parcel.dataPosition();\n" |
| 244 | << "_aidl_parcel.setDataPosition(_aidl_start_pos);\n" |
| 245 | << "_aidl_parcel.writeInt(_aidl_end_pos - _aidl_start_pos);\n" |
| 246 | << "_aidl_parcel.setDataPosition(_aidl_end_pos);\n"; |
| 247 | |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 248 | write_method->statements->Add(std::make_shared<LiteralStatement>(out.str())); |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 249 | |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 250 | parcel_class->elements.push_back(write_method); |
| 251 | |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 252 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 253 | auto constructor = std::make_shared<Method>(); |
| 254 | constructor->modifiers = PUBLIC; |
| 255 | constructor->name = parcel->GetName(); |
| 256 | constructor->statements = std::make_shared<StatementBlock>(); |
| 257 | for (const auto& field : parcel->GetFields()) { |
| 258 | constructor->parameters.push_back(std::make_shared<Variable>( |
| 259 | JavaSignatureOf(field->GetType(), typenames), field->GetName())); |
| 260 | out.str(""); |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 261 | |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 262 | out << "this." << field->GetName() << " = "; |
| 263 | if (field->GetType().GetName() == "List") { |
Jeongik Cha | 02c2c1e | 2020-07-31 15:11:49 +0900 | [diff] [blame] | 264 | out << field->GetName() << " == null ? null : java.util.Collections.unmodifiableList(" |
| 265 | << field->GetName() << ");\n"; |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 266 | } else if (field->GetType().GetName() == "Map") { |
Jeongik Cha | 02c2c1e | 2020-07-31 15:11:49 +0900 | [diff] [blame] | 267 | out << field->GetName() << " == null ? null : java.util.Collections.unmodifiableMap(" |
| 268 | << field->GetName() << ");\n"; |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 269 | } else { |
| 270 | out << field->GetName() << ";\n"; |
| 271 | } |
| 272 | constructor->statements->Add(std::make_shared<LiteralStatement>(out.str())); |
| 273 | } |
| 274 | parcel_class->elements.push_back(constructor); |
| 275 | } |
| 276 | |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 277 | // For an immutable parcelable, generate internalCreateFromParcel method. |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 278 | // Otherwise, generate readFromParcel method. |
| 279 | auto read_or_create_method = std::make_shared<Method>(); |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 280 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 281 | auto constructor = std::make_shared<Method>(); |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 282 | read_or_create_method->modifiers = PRIVATE | STATIC; |
| 283 | read_or_create_method->returnType = parcel->GetName(); |
| 284 | read_or_create_method->name = "internalCreateFromParcel"; |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 285 | read_or_create_method->parameters.push_back(parcel_variable); |
| 286 | read_or_create_method->statements = std::make_shared<StatementBlock>(); |
| 287 | } else { |
| 288 | read_or_create_method->modifiers = PUBLIC | FINAL; |
| 289 | read_or_create_method->returnType = "void"; |
| 290 | read_or_create_method->name = "readFromParcel"; |
| 291 | read_or_create_method->parameters.push_back(parcel_variable); |
| 292 | read_or_create_method->statements = std::make_shared<StatementBlock>(); |
| 293 | } |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 294 | out.str(""); |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 295 | const string builder_variable = "_aidl_parcelable_builder"; |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 296 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 297 | out << "Builder " << builder_variable << " = new Builder();\n"; |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 298 | } |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 299 | out << "int _aidl_start_pos = _aidl_parcel.dataPosition();\n" |
| 300 | << "int _aidl_parcelable_size = _aidl_parcel.readInt();\n" |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 301 | << "try {\n" |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 302 | << " if (_aidl_parcelable_size < 0) return"; |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 303 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 304 | out << " " << builder_variable << ".build()"; |
| 305 | } |
| 306 | out << ";\n"; |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 307 | |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 308 | read_or_create_method->statements->Add(std::make_shared<LiteralStatement>(out.str())); |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 309 | |
| 310 | out.str(""); |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 311 | out << " if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return"; |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 312 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 313 | out << " " << builder_variable << ".build()"; |
| 314 | } |
| 315 | out << ";\n"; |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 316 | |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 317 | std::shared_ptr<LiteralStatement> sizeCheck = nullptr; |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 318 | // keep this across different fields in order to create the classloader |
| 319 | // at most once. |
| 320 | bool is_classloader_created = false; |
| 321 | for (const auto& field : parcel->GetFields()) { |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 322 | const auto field_variable_name = |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 323 | (parcel->IsJavaOnlyImmutable() ? "_aidl_temp_" : "") + field->GetName(); |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 324 | string code; |
| 325 | CodeWriterPtr writer = CodeWriter::ForString(&code); |
| 326 | CodeGeneratorContext context{ |
| 327 | .writer = *(writer.get()), |
Jeongik Cha | 6cadc21 | 2019-02-12 18:16:03 +0900 | [diff] [blame] | 328 | .typenames = typenames, |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 329 | .type = field->GetType(), |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 330 | .parcel = parcel_variable->name, |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 331 | .var = field_variable_name, |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 332 | .is_classloader_created = &is_classloader_created, |
| 333 | }; |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 334 | context.writer.Indent(); |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 335 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 336 | context.writer.Write("%s %s;\n", JavaSignatureOf(field->GetType(), typenames).c_str(), |
| 337 | field_variable_name.c_str()); |
| 338 | } |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 339 | CreateFromParcelFor(context); |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 340 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 341 | context.writer.Write("%s.%s(%s);\n", builder_variable.c_str(), |
| 342 | get_setter_name(field->GetName()).c_str(), field_variable_name.c_str()); |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 343 | } |
Jiyong Park | 1d2df7d | 2018-07-23 15:22:50 +0900 | [diff] [blame] | 344 | writer->Close(); |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 345 | read_or_create_method->statements->Add(std::make_shared<LiteralStatement>(code)); |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 346 | if (!sizeCheck) sizeCheck = std::make_shared<LiteralStatement>(out.str()); |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 347 | read_or_create_method->statements->Add(sizeCheck); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 348 | } |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 349 | |
| 350 | out.str(""); |
| 351 | out << "} finally {\n" |
Jeongik Cha | 8b32998 | 2020-09-01 20:59:36 +0900 | [diff] [blame] | 352 | << " if (_aidl_start_pos > (Integer.MAX_VALUE - _aidl_parcelable_size)) {\n" |
| 353 | << " throw new android.os.BadParcelableException(\"Overflow in the size of " |
| 354 | "parcelable\");\n" |
| 355 | << " }\n" |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 356 | << " _aidl_parcel.setDataPosition(_aidl_start_pos + _aidl_parcelable_size);\n"; |
Jeongik Cha | d0a1027 | 2020-08-06 16:33:36 +0900 | [diff] [blame] | 357 | if (parcel->IsJavaOnlyImmutable()) { |
Jeongik Cha | 9118025 | 2020-07-31 15:43:11 +0900 | [diff] [blame] | 358 | out << " return " << builder_variable << ".build();\n"; |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 359 | } |
| 360 | out << "}\n"; |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 361 | |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 362 | read_or_create_method->statements->Add(std::make_shared<LiteralStatement>(out.str())); |
Jeongik Cha | 95eba57 | 2018-11-22 09:14:52 +0900 | [diff] [blame] | 363 | |
Jeongik Cha | 36f76c3 | 2020-07-28 00:25:52 +0900 | [diff] [blame] | 364 | parcel_class->elements.push_back(read_or_create_method); |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 365 | |
Jiyong Park | 43113fb | 2020-07-20 16:26:19 +0900 | [diff] [blame] | 366 | if (parcel->IsJavaDebug()) { |
| 367 | out.str(""); |
| 368 | out << "@Override\n"; |
| 369 | out << "public String toString() {\n"; |
| 370 | out << " java.util.StringJoiner _aidl_sj = new java.util.StringJoiner("; |
| 371 | out << "\", \", \"{\", \"}\");\n"; |
| 372 | for (const auto& field : parcel->GetFields()) { |
| 373 | std::string code; |
| 374 | CodeWriterPtr writer = CodeWriter::ForString(&code); |
| 375 | CodeGeneratorContext context{ |
| 376 | .writer = *(writer.get()), |
| 377 | .typenames = typenames, |
| 378 | .type = field->GetType(), |
| 379 | .parcel = parcel_variable->name, |
| 380 | .var = field->GetName(), |
| 381 | .is_classloader_created = &is_classloader_created, |
| 382 | }; |
| 383 | ToStringFor(context); |
| 384 | writer->Close(); |
| 385 | out << " _aidl_sj.add(\"" << field->GetName() << ": \" + (" << code << "));\n"; |
| 386 | } |
| 387 | out << " return \"" << parcel->GetCanonicalName() << "\" + _aidl_sj.toString() ;\n"; |
| 388 | out << "}\n"; |
| 389 | parcel_class->elements.push_back(std::make_shared<LiteralClassElement>(out.str())); |
| 390 | } |
| 391 | |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 392 | auto describe_contents_method = std::make_shared<Method>(); |
Jiyong Park | b77f7a5 | 2018-09-13 21:32:38 +0900 | [diff] [blame] | 393 | describe_contents_method->modifiers = PUBLIC | OVERRIDE; |
Jeongik Cha | 6cadc21 | 2019-02-12 18:16:03 +0900 | [diff] [blame] | 394 | describe_contents_method->returnType = "int"; |
Jiyong Park | b77f7a5 | 2018-09-13 21:32:38 +0900 | [diff] [blame] | 395 | describe_contents_method->name = "describeContents"; |
Steven Moreland | 48548e0 | 2019-09-18 15:10:22 -0700 | [diff] [blame] | 396 | describe_contents_method->statements = std::make_shared<StatementBlock>(); |
| 397 | describe_contents_method->statements->Add(std::make_shared<LiteralStatement>("return 0;\n")); |
Jiyong Park | b77f7a5 | 2018-09-13 21:32:38 +0900 | [diff] [blame] | 398 | parcel_class->elements.push_back(describe_contents_method); |
| 399 | |
Steven Moreland | 5557f1c | 2018-07-02 13:50:23 -0700 | [diff] [blame] | 400 | return parcel_class; |
| 401 | } |
| 402 | |
Daniel Norman | 716d311 | 2019-09-10 13:11:56 -0700 | [diff] [blame] | 403 | void generate_enum(const CodeWriterPtr& code_writer, const AidlEnumDeclaration* enum_decl, |
| 404 | const AidlTypenames& typenames) { |
| 405 | code_writer->Write( |
| 406 | "/*\n" |
| 407 | " * This file is auto-generated. DO NOT MODIFY.\n" |
| 408 | " */\n"); |
| 409 | |
| 410 | code_writer->Write("package %s;\n", enum_decl->GetPackage().c_str()); |
Daniel Norman | 2e4112d | 2019-10-03 10:22:35 -0700 | [diff] [blame] | 411 | code_writer->Write("%s\n", enum_decl->GetComments().c_str()); |
Daniel Norman | 716d311 | 2019-09-10 13:11:56 -0700 | [diff] [blame] | 412 | for (const std::string& annotation : generate_java_annotations(*enum_decl)) { |
Steven Moreland | d3721d6 | 2019-12-09 13:04:16 -0800 | [diff] [blame] | 413 | code_writer->Write("%s", annotation.c_str()); |
Daniel Norman | 716d311 | 2019-09-10 13:11:56 -0700 | [diff] [blame] | 414 | } |
| 415 | code_writer->Write("public @interface %s {\n", enum_decl->GetName().c_str()); |
| 416 | code_writer->Indent(); |
| 417 | for (const auto& enumerator : enum_decl->GetEnumerators()) { |
Steven Moreland | d3721d6 | 2019-12-09 13:04:16 -0800 | [diff] [blame] | 418 | code_writer->Write("%s", enumerator->GetComments().c_str()); |
Daniel Norman | 716d311 | 2019-09-10 13:11:56 -0700 | [diff] [blame] | 419 | code_writer->Write( |
| 420 | "public static final %s %s = %s;\n", |
| 421 | JavaSignatureOf(enum_decl->GetBackingType(), typenames).c_str(), |
| 422 | enumerator->GetName().c_str(), |
Daniel Norman | 37d43dd | 2019-09-09 17:22:34 -0700 | [diff] [blame] | 423 | enumerator->ValueString(enum_decl->GetBackingType(), ConstantValueDecorator).c_str()); |
Daniel Norman | 716d311 | 2019-09-10 13:11:56 -0700 | [diff] [blame] | 424 | } |
| 425 | code_writer->Dedent(); |
| 426 | code_writer->Write("}\n"); |
| 427 | } |
| 428 | |
Mathew Inwood | adb7467 | 2019-11-29 14:01:53 +0000 | [diff] [blame] | 429 | std::string dump_location(const AidlNode& method) { |
| 430 | return method.PrintLocation(); |
| 431 | } |
| 432 | |
| 433 | std::string generate_java_unsupportedappusage_parameters(const AidlAnnotation& a) { |
Daniel Norman | 37d43dd | 2019-09-09 17:22:34 -0700 | [diff] [blame] | 434 | const std::map<std::string, std::string> params = a.AnnotationParams(ConstantValueDecorator); |
Andrei Onea | 9445fc6 | 2019-06-27 18:11:59 +0100 | [diff] [blame] | 435 | std::vector<string> parameters_decl; |
| 436 | for (const auto& name_and_param : params) { |
| 437 | const std::string& param_name = name_and_param.first; |
| 438 | const std::string& param_value = name_and_param.second; |
| 439 | parameters_decl.push_back(param_name + " = " + param_value); |
| 440 | } |
Mathew Inwood | adb7467 | 2019-11-29 14:01:53 +0000 | [diff] [blame] | 441 | parameters_decl.push_back("overrideSourcePosition=\"" + dump_location(a) + "\""); |
Andrei Onea | 9445fc6 | 2019-06-27 18:11:59 +0100 | [diff] [blame] | 442 | return "(" + base::Join(parameters_decl, ", ") + ")"; |
| 443 | } |
| 444 | |
Jiyong Park | a6605ab | 2018-11-11 14:30:21 +0900 | [diff] [blame] | 445 | std::vector<std::string> generate_java_annotations(const AidlAnnotatable& a) { |
| 446 | std::vector<std::string> result; |
Makoto Onuki | 78a1c1c | 2020-03-04 16:57:23 -0800 | [diff] [blame] | 447 | if (a.IsHide()) { |
| 448 | result.emplace_back("@android.annotation.Hide"); |
| 449 | } |
Jiyong Park | bf5fd5c | 2020-06-05 19:48:05 +0900 | [diff] [blame] | 450 | |
| 451 | const AidlAnnotation* unsupported_app_usage = a.UnsupportedAppUsage(); |
Andrei Onea | 9445fc6 | 2019-06-27 18:11:59 +0100 | [diff] [blame] | 452 | if (unsupported_app_usage != nullptr) { |
Artur Satayev | 55120a7 | 2019-12-09 12:19:11 +0000 | [diff] [blame] | 453 | result.emplace_back("@android.compat.annotation.UnsupportedAppUsage" + |
Mathew Inwood | adb7467 | 2019-11-29 14:01:53 +0000 | [diff] [blame] | 454 | generate_java_unsupportedappusage_parameters(*unsupported_app_usage)); |
Jiyong Park | a6605ab | 2018-11-11 14:30:21 +0900 | [diff] [blame] | 455 | } |
Jiyong Park | bf5fd5c | 2020-06-05 19:48:05 +0900 | [diff] [blame] | 456 | |
| 457 | auto strip_double_quote = [](const AidlTypeSpecifier& type, const std::string& raw_value) -> std::string { |
| 458 | if (!android::base::StartsWith(raw_value, "\"") || |
| 459 | !android::base::EndsWith(raw_value, "\"")) { |
| 460 | AIDL_FATAL(type) << "Java passthrough annotation " << raw_value << " is not properly quoted"; |
| 461 | return ""; |
| 462 | } |
| 463 | return raw_value.substr(1, raw_value.size() - 2); |
| 464 | }; |
| 465 | |
| 466 | const AidlAnnotation* java_passthrough = a.JavaPassthrough(); |
| 467 | if (java_passthrough != nullptr) { |
| 468 | for (const auto& name_and_param : java_passthrough->AnnotationParams(strip_double_quote)) { |
| 469 | if (name_and_param.first == "annotation") { |
| 470 | result.emplace_back(name_and_param.second); |
| 471 | break; |
| 472 | } |
| 473 | } |
| 474 | } |
| 475 | |
Jiyong Park | a6605ab | 2018-11-11 14:30:21 +0900 | [diff] [blame] | 476 | return result; |
| 477 | } |
| 478 | |
Christopher Wiley | db154a5 | 2015-09-28 16:32:25 -0700 | [diff] [blame] | 479 | } // namespace java |
Christopher Wiley | fdeb0f4 | 2015-09-11 15:38:22 -0700 | [diff] [blame] | 480 | } // namespace aidl |
Steven Moreland | f4c64df | 2019-07-29 19:54:04 -0700 | [diff] [blame] | 481 | } // namespace android |