• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <memory>
23 #include <sstream>
24 
25 #include <android-base/stringprintf.h>
26 
27 #include "aidl_to_java.h"
28 #include "code_writer.h"
29 #include "type_java.h"
30 
31 using std::unique_ptr;
32 using ::android::aidl::java::Variable;
33 using std::string;
34 
35 namespace android {
36 namespace aidl {
37 namespace java {
38 
generate_java_interface(const string & filename,const AidlInterface * iface,JavaTypeNamespace * types,const IoDelegate & io_delegate,const Options & options)39 bool generate_java_interface(const string& filename, const AidlInterface* iface,
40                              JavaTypeNamespace* types, const IoDelegate& io_delegate,
41                              const Options& options) {
42   Class* cl = generate_binder_interface_class(iface, types, options);
43 
44   Document* document =
45       new Document("" /* no comment */, iface->GetPackage(), unique_ptr<Class>(cl));
46 
47   CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
48   document->Write(code_writer.get());
49 
50   return true;
51 }
52 
generate_java_parcel(const std::string & filename,const AidlStructuredParcelable * parcel,AidlTypenames & typenames,const IoDelegate & io_delegate)53 bool generate_java_parcel(const std::string& filename, const AidlStructuredParcelable* parcel,
54                           AidlTypenames& typenames, const IoDelegate& io_delegate) {
55   Class* cl = generate_parcel_class(parcel, typenames);
56 
57   Document* document =
58       new Document("" /* no comment */, parcel->GetPackage(), unique_ptr<Class>(cl));
59 
60   CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
61   document->Write(code_writer.get());
62 
63   return true;
64 }
65 
generate_java_parcel_declaration(const std::string & filename,const IoDelegate & io_delegate)66 bool generate_java_parcel_declaration(const std::string& filename, const IoDelegate& io_delegate) {
67   CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
68   *code_writer
69       << "// This file is intentionally left blank as placeholder for parcel declaration.\n";
70 
71   return true;
72 }
73 
generate_java(const std::string & filename,const AidlDefinedType * defined_type,JavaTypeNamespace * types,const IoDelegate & io_delegate,const Options & options)74 bool generate_java(const std::string& filename, const AidlDefinedType* defined_type,
75                    JavaTypeNamespace* types, const IoDelegate& io_delegate,
76                    const Options& options) {
77   const AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable();
78   if (parcelable != nullptr) {
79     return generate_java_parcel(filename, parcelable, types->typenames_, io_delegate);
80   }
81 
82   const AidlParcelable* parcelable_decl = defined_type->AsParcelable();
83   if (parcelable_decl != nullptr) {
84     return generate_java_parcel_declaration(filename, io_delegate);
85   }
86 
87   const AidlInterface* interface = defined_type->AsInterface();
88   if (interface != nullptr) {
89     return generate_java_interface(filename, interface, types, io_delegate, options);
90   }
91 
92   CHECK(false) << "Unrecognized type sent for cpp generation.";
93   return false;
94 }
95 
generate_parcel_class(const AidlStructuredParcelable * parcel,AidlTypenames & typenames)96 android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel,
97                                                   AidlTypenames& typenames) {
98   Class* parcel_class = new 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     const Type* type = variable->GetType().GetLanguageType<Type>();
108 
109     std::ostringstream out;
110     out << variable->GetType().GetComments() << "\n";
111     for (const auto& a : generate_java_annotations(variable->GetType())) {
112       out << a << "\n";
113     }
114     out << "public " << type->JavaType() << (variable->GetType().IsArray() ? "[]" : "") << " "
115         << variable->GetName();
116     if (variable->GetDefaultValue()) {
117       out << " = " << variable->ValueString(AidlConstantValueDecorator);
118     }
119     out << ";\n";
120     parcel_class->elements.push_back(new LiteralClassElement(out.str()));
121   }
122 
123   std::ostringstream out;
124   out << "public static final android.os.Parcelable.Creator<" << parcel->GetName() << "> CREATOR = "
125       << "new android.os.Parcelable.Creator<" << parcel->GetName() << ">() {\n";
126   out << "  @Override\n";
127   out << "  public " << parcel->GetName()
128       << " createFromParcel(android.os.Parcel _aidl_source) {\n";
129   out << "    " << parcel->GetName() << " _aidl_out = new " << parcel->GetName() << "();\n";
130   out << "    _aidl_out.readFromParcel(_aidl_source);\n";
131   out << "    return _aidl_out;\n";
132   out << "  }\n";
133   out << "  @Override\n";
134   out << "  public " << parcel->GetName() << "[] newArray(int _aidl_size) {\n";
135   out << "    return new " << parcel->GetName() << "[_aidl_size];\n";
136   out << "  }\n";
137   out << "};\n";
138   parcel_class->elements.push_back(new LiteralClassElement(out.str()));
139 
140   Variable* flag_variable = new Variable("int", "_aidl_flag");
141   Variable* parcel_variable = new Variable("android.os.Parcel", "_aidl_parcel");
142 
143   Method* write_method = new Method;
144   write_method->modifiers = PUBLIC | OVERRIDE | FINAL;
145   write_method->returnType = "void";
146   write_method->name = "writeToParcel";
147   write_method->parameters.push_back(parcel_variable);
148   write_method->parameters.push_back(flag_variable);
149   write_method->statements = new StatementBlock();
150 
151   out.str("");
152   out << "int _aidl_start_pos = _aidl_parcel.dataPosition();\n"
153       << "_aidl_parcel.writeInt(0);\n";
154   write_method->statements->Add(new LiteralStatement(out.str()));
155 
156   for (const auto& field : parcel->GetFields()) {
157     string code;
158     CodeWriterPtr writer = CodeWriter::ForString(&code);
159     CodeGeneratorContext context{
160         .writer = *(writer.get()),
161         .typenames = typenames,
162         .type = field->GetType(),
163         .var = field->GetName(),
164         .parcel = parcel_variable->name,
165         .is_return_value = false,
166     };
167     WriteToParcelFor(context);
168     writer->Close();
169     write_method->statements->Add(new LiteralStatement(code));
170   }
171 
172   out.str("");
173   out << "int _aidl_end_pos = _aidl_parcel.dataPosition();\n"
174       << "_aidl_parcel.setDataPosition(_aidl_start_pos);\n"
175       << "_aidl_parcel.writeInt(_aidl_end_pos - _aidl_start_pos);\n"
176       << "_aidl_parcel.setDataPosition(_aidl_end_pos);\n";
177 
178   write_method->statements->Add(new LiteralStatement(out.str()));
179 
180   parcel_class->elements.push_back(write_method);
181 
182   Method* read_method = new Method;
183   read_method->modifiers = PUBLIC | FINAL;
184   read_method->returnType = "void";
185   read_method->name = "readFromParcel";
186   read_method->parameters.push_back(parcel_variable);
187   read_method->statements = new StatementBlock();
188 
189   out.str("");
190   out << "int _aidl_start_pos = _aidl_parcel.dataPosition();\n"
191       << "int _aidl_parcelable_size = _aidl_parcel.readInt();\n"
192       << "if (_aidl_parcelable_size < 0) return;\n"
193       << "try {\n";
194 
195   read_method->statements->Add(new LiteralStatement(out.str()));
196 
197   out.str("");
198   out << "  if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;\n";
199 
200   LiteralStatement* sizeCheck = nullptr;
201   // keep this across different fields in order to create the classloader
202   // at most once.
203   bool is_classloader_created = false;
204   for (const auto& field : parcel->GetFields()) {
205     string code;
206     CodeWriterPtr writer = CodeWriter::ForString(&code);
207     CodeGeneratorContext context{
208         .writer = *(writer.get()),
209         .typenames = typenames,
210         .type = field->GetType(),
211         .var = field->GetName(),
212         .parcel = parcel_variable->name,
213         .is_classloader_created = &is_classloader_created,
214     };
215     context.writer.Indent();
216     CreateFromParcelFor(context);
217     writer->Close();
218     read_method->statements->Add(new LiteralStatement(code));
219     if (!sizeCheck) sizeCheck = new LiteralStatement(out.str());
220     read_method->statements->Add(sizeCheck);
221   }
222 
223   out.str("");
224   out << "} finally {\n"
225       << "  _aidl_parcel.setDataPosition(_aidl_start_pos + _aidl_parcelable_size);\n"
226       << "}\n";
227 
228   read_method->statements->Add(new LiteralStatement(out.str()));
229 
230   parcel_class->elements.push_back(read_method);
231 
232   Method* describe_contents_method = new Method;
233   describe_contents_method->modifiers = PUBLIC | OVERRIDE;
234   describe_contents_method->returnType = "int";
235   describe_contents_method->name = "describeContents";
236   describe_contents_method->statements = new StatementBlock();
237   describe_contents_method->statements->Add(new LiteralStatement("return 0;\n"));
238   parcel_class->elements.push_back(describe_contents_method);
239 
240   return parcel_class;
241 }
242 
generate_java_annotations(const AidlAnnotatable & a)243 std::vector<std::string> generate_java_annotations(const AidlAnnotatable& a) {
244   std::vector<std::string> result;
245   if (a.IsUnsupportedAppUsage()) {
246     result.emplace_back("@android.annotation.UnsupportedAppUsage");
247   }
248   if (a.IsSystemApi()) {
249     result.emplace_back("@android.annotation.SystemApi");
250   }
251   return result;
252 }
253 
254 }  // namespace java
255 }  // namespace android
256 }  // namespace aidl
257