blob: 198b8c1c0c2a979df0f32fd7835784b6fa3c72a3 [file] [log] [blame]
Christopher Wiley3a9da172016-01-29 11:10:49 -08001/*
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
Jiyong Park309668e2018-07-28 16:55:44 +090017#include "aidl.h"
Jiyong Park1d2df7d2018-07-23 15:22:50 +090018#include "aidl_to_java.h"
Adam Lesinskiffa16862014-01-23 18:17:42 -080019#include "generate_java.h"
Jiyong Park1d2df7d2018-07-23 15:22:50 +090020#include "options.h"
21#include "type_java.h"
Christopher Wileyf690be52015-09-14 15:19:10 -070022
Adam Lesinskiffa16862014-01-23 18:17:42 -080023#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
Andreas Gampee9c816e2018-03-14 09:05:48 -070027#include <algorithm>
28#include <unordered_set>
Jiyong Park1d2df7d2018-07-23 15:22:50 +090029#include <utility>
30#include <vector>
Andreas Gampee9c816e2018-03-14 09:05:48 -070031
Elliott Hughes0a620672015-12-04 13:53:18 -080032#include <android-base/macros.h>
Andreas Gampe7d7fa602017-11-22 10:50:03 -080033#include <android-base/stringprintf.h>
Christopher Wiley8b2d3ee2015-09-23 15:43:01 -070034
Jiyong Park75e1a742018-07-04 12:31:23 +090035using android::base::Join;
Andreas Gampe7d7fa602017-11-22 10:50:03 -080036using android::base::StringPrintf;
Jiyong Park1d2df7d2018-07-23 15:22:50 +090037
38using std::pair;
Jiyong Park75e1a742018-07-04 12:31:23 +090039using std::string;
40using std::unique_ptr;
41using std::vector;
Andreas Gampe7d7fa602017-11-22 10:50:03 -080042
Christopher Wileyfdeb0f42015-09-11 15:38:22 -070043namespace android {
44namespace aidl {
Christopher Wileydb154a52015-09-28 16:32:25 -070045namespace java {
Christopher Wileyfdeb0f42015-09-11 15:38:22 -070046
Adam Lesinskiffa16862014-01-23 18:17:42 -080047// =================================================
Jiyong Park2c44f072018-07-30 21:52:21 +090048class VariableFactory {
49 public:
50 using Variable = ::android::aidl::java::Variable;
51 using Type = ::android::aidl::java::Type;
52
53 explicit VariableFactory(const std::string& base) : base_(base), index_(0) {}
54 Variable* Get(const Type* type) {
55 Variable* v = new Variable(type, StringPrintf("%s%d", base_.c_str(), index_));
56 vars_.push_back(v);
57 index_++;
58 return v;
59 }
60
61 Variable* Get(int index) { return vars_[index]; }
62
63 private:
64 std::vector<Variable*> vars_;
65 std::string base_;
66 int index_;
67
68 DISALLOW_COPY_AND_ASSIGN(VariableFactory);
69};
70
71// =================================================
Christopher Wiley67502f12016-01-29 10:57:00 -080072class StubClass : public Class {
73 public:
Jiyong Park74595c12018-07-23 15:22:50 +090074 StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types,
75 const Options& options);
Christopher Wiley3a9da172016-01-29 11:10:49 -080076 virtual ~StubClass() = default;
Adam Lesinskiffa16862014-01-23 18:17:42 -080077
Christopher Wiley67502f12016-01-29 10:57:00 -080078 Variable* transact_code;
79 Variable* transact_data;
80 Variable* transact_reply;
81 Variable* transact_flags;
82 SwitchStatement* transact_switch;
Andreas Gampe7fab0d12017-11-22 17:50:17 -080083 StatementBlock* transact_statements;
Olivier Gaillard11401402018-07-05 15:01:34 +010084 SwitchStatement* code_to_method_name_switch;
Christopher Wiley8b2d3ee2015-09-23 15:43:01 -070085
Andreas Gampe1b865af2017-11-22 11:31:47 -080086 // Where onTransact cases should be generated as separate methods.
87 bool transact_outline;
Andreas Gampee9c816e2018-03-14 09:05:48 -070088 // Specific methods that should be outlined when transact_outline is true.
89 std::unordered_set<const AidlMethod*> outline_methods;
90 // Number of all methods.
91 size_t all_method_count;
Andreas Gampe1b865af2017-11-22 11:31:47 -080092
Andreas Gampea8a66fe2017-11-22 12:17:00 -080093 // Finish generation. This will add a default case to the switch.
94 void finish();
95
Andreas Gampee9c816e2018-03-14 09:05:48 -070096 Expression* get_transact_descriptor(const JavaTypeNamespace* types,
97 const AidlMethod* method);
Andreas Gampe7fab0d12017-11-22 17:50:17 -080098
Christopher Wiley67502f12016-01-29 10:57:00 -080099 private:
100 void make_as_interface(const InterfaceType* interfaceType,
101 JavaTypeNamespace* types);
102
Andreas Gampe7fab0d12017-11-22 17:50:17 -0800103 Variable* transact_descriptor;
Jiyong Park74595c12018-07-23 15:22:50 +0900104 const Options& options_;
Andreas Gampe7fab0d12017-11-22 17:50:17 -0800105
Christopher Wiley67502f12016-01-29 10:57:00 -0800106 DISALLOW_COPY_AND_ASSIGN(StubClass);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800107};
108
Jiyong Park74595c12018-07-23 15:22:50 +0900109StubClass::StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types,
110 const Options& options)
Olivier Gaillard11401402018-07-05 15:01:34 +0100111 : Class(), options_(options) {
Andreas Gampe7fab0d12017-11-22 17:50:17 -0800112 transact_descriptor = nullptr;
Andreas Gampe1b865af2017-11-22 11:31:47 -0800113 transact_outline = false;
Andreas Gampee9c816e2018-03-14 09:05:48 -0700114 all_method_count = 0; // Will be set when outlining may be enabled.
Andreas Gampe7fab0d12017-11-22 17:50:17 -0800115
Christopher Wiley67502f12016-01-29 10:57:00 -0800116 this->comment = "/** Local-side IPC implementation stub class. */";
117 this->modifiers = PUBLIC | ABSTRACT | STATIC;
118 this->what = Class::CLASS;
119 this->type = type;
120 this->extends = types->BinderNativeType();
121 this->interfaces.push_back(interfaceType);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800122
Christopher Wiley67502f12016-01-29 10:57:00 -0800123 // descriptor
124 Field* descriptor =
125 new Field(STATIC | FINAL | PRIVATE,
126 new Variable(types->StringType(), "DESCRIPTOR"));
Christopher Wileyd21bfee2016-01-29 15:11:38 -0800127 descriptor->value = "\"" + interfaceType->JavaType() + "\"";
Christopher Wiley67502f12016-01-29 10:57:00 -0800128 this->elements.push_back(descriptor);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800129
Christopher Wiley67502f12016-01-29 10:57:00 -0800130 // ctor
131 Method* ctor = new Method;
132 ctor->modifiers = PUBLIC;
133 ctor->comment =
134 "/** Construct the stub at attach it to the "
135 "interface. */";
136 ctor->name = "Stub";
137 ctor->statements = new StatementBlock;
138 MethodCall* attach =
139 new MethodCall(THIS_VALUE, "attachInterface", 2, THIS_VALUE,
140 new LiteralExpression("DESCRIPTOR"));
141 ctor->statements->Add(attach);
142 this->elements.push_back(ctor);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800143
Christopher Wiley67502f12016-01-29 10:57:00 -0800144 // asInterface
145 make_as_interface(interfaceType, types);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800146
Christopher Wiley67502f12016-01-29 10:57:00 -0800147 // asBinder
148 Method* asBinder = new Method;
149 asBinder->modifiers = PUBLIC | OVERRIDE;
150 asBinder->returnType = types->IBinderType();
151 asBinder->name = "asBinder";
152 asBinder->statements = new StatementBlock;
153 asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
154 this->elements.push_back(asBinder);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800155
Jiyong Park74595c12018-07-23 15:22:50 +0900156 if (options_.GenTransactionNames()) {
Olivier Gaillard83d7cd32018-07-30 16:20:57 +0100157 // getDefaultTransactionName
158 Method* getDefaultTransactionName = new Method;
159 getDefaultTransactionName->modifiers = PUBLIC | STATIC;
160 getDefaultTransactionName->returnType = types->StringType();
161 getDefaultTransactionName->name = "getDefaultTransactionName";
162 Variable* code = new Variable(types->IntType(), "transactionCode");
163 getDefaultTransactionName->parameters.push_back(code);
164 getDefaultTransactionName->statements = new StatementBlock;
165 this->code_to_method_name_switch = new SwitchStatement(code);
166 getDefaultTransactionName->statements->Add(this->code_to_method_name_switch);
167 this->elements.push_back(getDefaultTransactionName);
168
169 // getTransactionName
Olivier Gaillard11401402018-07-05 15:01:34 +0100170 Method* getTransactionName = new Method;
171 getTransactionName->modifiers = PUBLIC;
172 getTransactionName->returnType = types->StringType();
173 getTransactionName->name = "getTransactionName";
Olivier Gaillard83d7cd32018-07-30 16:20:57 +0100174 Variable* code2 = new Variable(types->IntType(), "transactionCode");
175 getTransactionName->parameters.push_back(code2);
Olivier Gaillard11401402018-07-05 15:01:34 +0100176 getTransactionName->statements = new StatementBlock;
Olivier Gaillard83d7cd32018-07-30 16:20:57 +0100177 getTransactionName->statements->Add(
178 new ReturnStatement(new MethodCall(THIS_VALUE, "getDefaultTransactionName", 1, code2)));
Olivier Gaillard11401402018-07-05 15:01:34 +0100179 this->elements.push_back(getTransactionName);
180 }
181
Christopher Wiley67502f12016-01-29 10:57:00 -0800182 // onTransact
183 this->transact_code = new Variable(types->IntType(), "code");
184 this->transact_data = new Variable(types->ParcelType(), "data");
185 this->transact_reply = new Variable(types->ParcelType(), "reply");
186 this->transact_flags = new Variable(types->IntType(), "flags");
187 Method* onTransact = new Method;
188 onTransact->modifiers = PUBLIC | OVERRIDE;
189 onTransact->returnType = types->BoolType();
190 onTransact->name = "onTransact";
191 onTransact->parameters.push_back(this->transact_code);
192 onTransact->parameters.push_back(this->transact_data);
193 onTransact->parameters.push_back(this->transact_reply);
194 onTransact->parameters.push_back(this->transact_flags);
195 onTransact->statements = new StatementBlock;
Andreas Gampe7fab0d12017-11-22 17:50:17 -0800196 transact_statements = onTransact->statements;
Christopher Wiley67502f12016-01-29 10:57:00 -0800197 onTransact->exceptions.push_back(types->RemoteExceptionType());
198 this->elements.push_back(onTransact);
199 this->transact_switch = new SwitchStatement(this->transact_code);
Andreas Gampea8a66fe2017-11-22 12:17:00 -0800200}
201
202void StubClass::finish() {
203 Case* default_case = new Case;
204
Christopher Wiley67502f12016-01-29 10:57:00 -0800205 MethodCall* superCall = new MethodCall(
Andreas Gampea8a66fe2017-11-22 12:17:00 -0800206 SUPER_VALUE, "onTransact", 4, this->transact_code, this->transact_data,
207 this->transact_reply, this->transact_flags);
208 default_case->statements->Add(new ReturnStatement(superCall));
209 transact_switch->cases.push_back(default_case);
Andreas Gampe7fab0d12017-11-22 17:50:17 -0800210
211 transact_statements->Add(this->transact_switch);
Olivier Gaillard11401402018-07-05 15:01:34 +0100212
213 // getTransactionName
Jiyong Park74595c12018-07-23 15:22:50 +0900214 if (options_.GenTransactionNames()) {
Olivier Gaillard11401402018-07-05 15:01:34 +0100215 // Some transaction codes are common, e.g. INTERFACE_TRANSACTION or DUMP_TRANSACTION.
216 // Common transaction codes will not be resolved to a string by getTransactionName. The method
217 // will return NULL in this case.
218 Case* code_switch_default_case = new Case;
219 code_switch_default_case->statements->Add(new ReturnStatement(NULL_VALUE));
220 this->code_to_method_name_switch->cases.push_back(code_switch_default_case);
221 }
Andreas Gampe7fab0d12017-11-22 17:50:17 -0800222}
223
Andreas Gampee9c816e2018-03-14 09:05:48 -0700224// The the expression for the interface's descriptor to be used when
225// generating code for the given method. Null is acceptable for method
226// and stands for synthetic cases.
227Expression* StubClass::get_transact_descriptor(const JavaTypeNamespace* types,
228 const AidlMethod* method) {
Andreas Gampe1b865af2017-11-22 11:31:47 -0800229 if (transact_outline) {
Andreas Gampee9c816e2018-03-14 09:05:48 -0700230 if (method != nullptr) {
231 // When outlining, each outlined method needs its own literal.
232 if (outline_methods.count(method) != 0) {
233 return new LiteralExpression("DESCRIPTOR");
234 }
235 } else {
236 // Synthetic case. A small number is assumed. Use its own descriptor
237 // if there are only synthetic cases.
238 if (outline_methods.size() == all_method_count) {
239 return new LiteralExpression("DESCRIPTOR");
240 }
241 }
Andreas Gampe1b865af2017-11-22 11:31:47 -0800242 }
243
Andreas Gampee9c816e2018-03-14 09:05:48 -0700244 // When not outlining, store the descriptor literal into a local variable, in
245 // an effort to save const-string instructions in each switch case.
Andreas Gampe7fab0d12017-11-22 17:50:17 -0800246 if (transact_descriptor == nullptr) {
247 transact_descriptor = new Variable(types->StringType(), "descriptor");
248 transact_statements->Add(
249 new VariableDeclaration(transact_descriptor,
250 new LiteralExpression("DESCRIPTOR")));
251 }
252 return transact_descriptor;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800253}
254
Christopher Wiley67502f12016-01-29 10:57:00 -0800255void StubClass::make_as_interface(const InterfaceType* interfaceType,
256 JavaTypeNamespace* types) {
257 Variable* obj = new Variable(types->IBinderType(), "obj");
258
259 Method* m = new Method;
260 m->comment = "/**\n * Cast an IBinder object into an ";
Christopher Wileyd21bfee2016-01-29 15:11:38 -0800261 m->comment += interfaceType->JavaType();
Christopher Wiley67502f12016-01-29 10:57:00 -0800262 m->comment += " interface,\n";
263 m->comment += " * generating a proxy if needed.\n */";
264 m->modifiers = PUBLIC | STATIC;
265 m->returnType = interfaceType;
266 m->name = "asInterface";
267 m->parameters.push_back(obj);
268 m->statements = new StatementBlock;
269
270 IfStatement* ifstatement = new IfStatement();
271 ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
272 ifstatement->statements = new StatementBlock;
273 ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
274 m->statements->Add(ifstatement);
275
276 // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
277 MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
278 queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
279 IInterfaceType* iinType = new IInterfaceType(types);
280 Variable* iin = new Variable(iinType, "iin");
281 VariableDeclaration* iinVd =
Yi Kong894d6ba2018-07-24 11:27:38 -0700282 new VariableDeclaration(iin, queryLocalInterface, nullptr);
Christopher Wiley67502f12016-01-29 10:57:00 -0800283 m->statements->Add(iinVd);
284
285 // Ensure the instance type of the local object is as expected.
286 // One scenario where this is needed is if another package (with a
287 // different class loader) runs in the same process as the service.
288
289 // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>)
290 // iin;
291 Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
292 Comparison* instOfCheck =
293 new Comparison(iin, " instanceof ",
Christopher Wileyd21bfee2016-01-29 15:11:38 -0800294 new LiteralExpression(interfaceType->JavaType()));
Christopher Wiley67502f12016-01-29 10:57:00 -0800295 IfStatement* instOfStatement = new IfStatement();
296 instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
297 instOfStatement->statements = new StatementBlock;
298 instOfStatement->statements->Add(
299 new ReturnStatement(new Cast(interfaceType, iin)));
300 m->statements->Add(instOfStatement);
301
302 NewExpression* ne = new NewExpression(interfaceType->GetProxy());
303 ne->arguments.push_back(obj);
304 m->statements->Add(new ReturnStatement(ne));
305
306 this->elements.push_back(m);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800307}
308
Adam Lesinskiffa16862014-01-23 18:17:42 -0800309// =================================================
Christopher Wiley67502f12016-01-29 10:57:00 -0800310class ProxyClass : public Class {
311 public:
Jiyong Park309668e2018-07-28 16:55:44 +0900312 ProxyClass(const JavaTypeNamespace* types, const Type* type, const InterfaceType* interfaceType,
313 const Options& options);
Christopher Wiley67502f12016-01-29 10:57:00 -0800314 virtual ~ProxyClass();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800315
Christopher Wiley67502f12016-01-29 10:57:00 -0800316 Variable* mRemote;
317 bool mOneWay;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800318};
319
Christopher Wiley67502f12016-01-29 10:57:00 -0800320ProxyClass::ProxyClass(const JavaTypeNamespace* types, const Type* type,
Jiyong Park309668e2018-07-28 16:55:44 +0900321 const InterfaceType* interfaceType, const Options& options)
Christopher Wiley67502f12016-01-29 10:57:00 -0800322 : Class() {
323 this->modifiers = PRIVATE | STATIC;
324 this->what = Class::CLASS;
325 this->type = type;
326 this->interfaces.push_back(interfaceType);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800327
Christopher Wiley67502f12016-01-29 10:57:00 -0800328 mOneWay = interfaceType->OneWay();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800329
Christopher Wiley67502f12016-01-29 10:57:00 -0800330 // IBinder mRemote
331 mRemote = new Variable(types->IBinderType(), "mRemote");
332 this->elements.push_back(new Field(PRIVATE, mRemote));
Adam Lesinskiffa16862014-01-23 18:17:42 -0800333
Christopher Wiley67502f12016-01-29 10:57:00 -0800334 // Proxy()
335 Variable* remote = new Variable(types->IBinderType(), "remote");
336 Method* ctor = new Method;
337 ctor->name = "Proxy";
338 ctor->statements = new StatementBlock;
339 ctor->parameters.push_back(remote);
340 ctor->statements->Add(new Assignment(mRemote, remote));
341 this->elements.push_back(ctor);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800342
Jiyong Park309668e2018-07-28 16:55:44 +0900343 if (options.Version() > 0) {
344 std::ostringstream code;
345 code << "private int mCachedVersion = -1;\n";
346 this->elements.emplace_back(new LiteralClassElement(code.str()));
347 }
348
Christopher Wiley67502f12016-01-29 10:57:00 -0800349 // IBinder asBinder()
350 Method* asBinder = new Method;
351 asBinder->modifiers = PUBLIC | OVERRIDE;
352 asBinder->returnType = types->IBinderType();
353 asBinder->name = "asBinder";
354 asBinder->statements = new StatementBlock;
355 asBinder->statements->Add(new ReturnStatement(mRemote));
356 this->elements.push_back(asBinder);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800357}
358
Christopher Wiley67502f12016-01-29 10:57:00 -0800359ProxyClass::~ProxyClass() {}
Adam Lesinskiffa16862014-01-23 18:17:42 -0800360
361// =================================================
Christopher Wiley67502f12016-01-29 10:57:00 -0800362static void generate_new_array(const Type* t, StatementBlock* addTo,
363 Variable* v, Variable* parcel,
364 JavaTypeNamespace* types) {
365 Variable* len = new Variable(types->IntType(), v->name + "_length");
366 addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
367 IfStatement* lencheck = new IfStatement();
368 lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
369 lencheck->statements->Add(new Assignment(v, NULL_VALUE));
370 lencheck->elseif = new IfStatement();
371 lencheck->elseif->statements->Add(
372 new Assignment(v, new NewArrayExpression(t, len)));
373 addTo->Add(lencheck);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800374}
375
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900376static void generate_write_to_parcel(const AidlTypeSpecifier& type, StatementBlock* addTo,
377 Variable* v, Variable* parcel, bool is_return_value,
378 const AidlTypenames& typenames) {
379 string code;
380 CodeWriterPtr writer = CodeWriter::ForString(&code);
381 CodeGeneratorContext context{
382 .writer = *(writer.get()),
383 .typenames = typenames,
384 .type = type,
385 .var = v->name,
386 .parcel = parcel->name,
387 .is_return_value = is_return_value,
388 };
389 WriteToParcelFor(context);
390 writer->Close();
391 addTo->Add(new LiteralStatement(code));
Adam Lesinskiffa16862014-01-23 18:17:42 -0800392}
393
Steven Moreland693640b2018-07-19 13:46:27 -0700394static void generate_int_constant(Class* interface, const std::string& name,
395 const std::string& value) {
396 IntConstant* decl = new IntConstant(name, value);
Christopher Wiley69b44cf2016-05-03 13:43:33 -0700397 interface->elements.push_back(decl);
398}
Adam Lesinskiffa16862014-01-23 18:17:42 -0800399
Steven Moreland693640b2018-07-19 13:46:27 -0700400static void generate_string_constant(Class* interface, const std::string& name,
401 const std::string& value) {
402 StringConstant* decl = new StringConstant(name, value);
Christopher Wiley67502f12016-01-29 10:57:00 -0800403 interface->elements.push_back(decl);
Casey Dahlind40e2fe2015-11-24 14:06:52 -0800404}
405
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800406static std::unique_ptr<Method> generate_interface_method(
407 const AidlMethod& method, JavaTypeNamespace* types) {
408 std::unique_ptr<Method> decl(new Method);
Christopher Wiley67502f12016-01-29 10:57:00 -0800409 decl->comment = method.GetComments();
410 decl->modifiers = PUBLIC;
411 decl->returnType = method.GetType().GetLanguageType<Type>();
412 decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
413 decl->name = method.GetName();
Jiyong Parka6605ab2018-11-11 14:30:21 +0900414 decl->annotations = generate_java_annotations(method.GetType());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800415
Christopher Wiley67502f12016-01-29 10:57:00 -0800416 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
417 decl->parameters.push_back(
418 new Variable(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
419 arg->GetType().IsArray() ? 1 : 0));
420 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800421
Christopher Wiley67502f12016-01-29 10:57:00 -0800422 decl->exceptions.push_back(types->RemoteExceptionType());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800423
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800424 return decl;
425}
Adam Lesinskiffa16862014-01-23 18:17:42 -0800426
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900427static void generate_stub_code(const AidlInterface& iface, const AidlMethod& method, bool oneway,
428 Variable* transact_data, Variable* transact_reply,
429 JavaTypeNamespace* types, StatementBlock* statements,
430 StubClass* stubClass, const Options& options) {
Martijn Coenenf1b50782018-02-21 21:06:23 +0100431 TryStatement* tryStatement = nullptr;
432 FinallyStatement* finallyStatement = nullptr;
Christopher Wiley67502f12016-01-29 10:57:00 -0800433 MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800434
Christopher Wiley67502f12016-01-29 10:57:00 -0800435 // interface token validation is the very first thing we do
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800436 statements->Add(new MethodCall(transact_data,
437 "enforceInterface", 1,
Andreas Gampee9c816e2018-03-14 09:05:48 -0700438 stubClass->get_transact_descriptor(types,
439 &method)));
Adam Lesinskiffa16862014-01-23 18:17:42 -0800440
Christopher Wiley67502f12016-01-29 10:57:00 -0800441 // args
Christopher Wiley67502f12016-01-29 10:57:00 -0800442 VariableFactory stubArgs("_arg");
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800443 {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900444 // keep this across different args in order to create the classloader
445 // at most once.
446 bool is_classloader_created = false;
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800447 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
448 const Type* t = arg->GetType().GetLanguageType<Type>();
449 Variable* v = stubArgs.Get(t);
450 v->dimension = arg->GetType().IsArray() ? 1 : 0;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800451
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800452 statements->Add(new VariableDeclaration(v));
Adam Lesinskiffa16862014-01-23 18:17:42 -0800453
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800454 if (arg->GetDirection() & AidlArgument::IN_DIR) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900455 string code;
456 CodeWriterPtr writer = CodeWriter::ForString(&code);
457 CodeGeneratorContext context{.writer = *(writer.get()),
458 .typenames = types->typenames_,
459 .type = arg->GetType(),
460 .var = v->name,
461 .parcel = transact_data->name,
462 .is_classloader_created = &is_classloader_created};
463 CreateFromParcelFor(context);
464 writer->Close();
465 statements->Add(new LiteralStatement(code));
Christopher Wiley67502f12016-01-29 10:57:00 -0800466 } else {
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800467 if (!arg->GetType().IsArray()) {
468 statements->Add(new Assignment(v, new NewExpression(v->type)));
469 } else {
470 generate_new_array(v->type,
471 statements,
472 v,
473 transact_data,
474 types);
475 }
Christopher Wiley67502f12016-01-29 10:57:00 -0800476 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800477
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800478 realCall->arguments.push_back(v);
479 }
Christopher Wiley67502f12016-01-29 10:57:00 -0800480 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800481
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900482 if (options.GenTraces()) {
Martijn Coenenf1b50782018-02-21 21:06:23 +0100483 // try and finally, but only when generating trace code
484 tryStatement = new TryStatement();
485 finallyStatement = new FinallyStatement();
486
487 tryStatement->statements->Add(new MethodCall(
488 new LiteralExpression("android.os.Trace"), "traceBegin", 2,
489 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"),
490 new StringLiteralExpression(iface.GetName() + "::"
491 + method.GetName() + "::server")));
492
493 finallyStatement->statements->Add(new MethodCall(
494 new LiteralExpression("android.os.Trace"), "traceEnd", 1,
495 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL")));
496 }
497
Christopher Wiley67502f12016-01-29 10:57:00 -0800498 // the real call
Christopher Wiley67502f12016-01-29 10:57:00 -0800499 if (method.GetType().GetName() == "void") {
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900500 if (options.GenTraces()) {
Martijn Coenenf1b50782018-02-21 21:06:23 +0100501 statements->Add(tryStatement);
502 tryStatement->statements->Add(realCall);
503 statements->Add(finallyStatement);
504 } else {
505 statements->Add(realCall);
506 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800507
Adam Lesinskiffa16862014-01-23 18:17:42 -0800508 if (!oneway) {
Christopher Wiley67502f12016-01-29 10:57:00 -0800509 // report that there were no exceptions
510 MethodCall* ex =
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800511 new MethodCall(transact_reply, "writeNoException", 0);
512 statements->Add(ex);
Christopher Wiley67502f12016-01-29 10:57:00 -0800513 }
514 } else {
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800515 Variable* _result =
516 new Variable(method.GetType().GetLanguageType<Type>(),
517 "_result",
518 method.GetType().IsArray() ? 1 : 0);
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900519 if (options.GenTraces()) {
Martijn Coenenf1b50782018-02-21 21:06:23 +0100520 statements->Add(new VariableDeclaration(_result));
521 statements->Add(tryStatement);
522 tryStatement->statements->Add(new Assignment(_result, realCall));
523 statements->Add(finallyStatement);
524 } else {
525 statements->Add(new VariableDeclaration(_result, realCall));
526 }
Christopher Wiley67502f12016-01-29 10:57:00 -0800527
528 if (!oneway) {
529 // report that there were no exceptions
530 MethodCall* ex =
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800531 new MethodCall(transact_reply, "writeNoException", 0);
532 statements->Add(ex);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800533 }
534
Christopher Wiley67502f12016-01-29 10:57:00 -0800535 // marshall the return value
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900536 generate_write_to_parcel(method.GetType(), statements, _result, transact_reply, true,
537 types->typenames_);
Christopher Wiley67502f12016-01-29 10:57:00 -0800538 }
539
540 // out parameters
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800541 int i = 0;
Christopher Wiley67502f12016-01-29 10:57:00 -0800542 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
Christopher Wiley67502f12016-01-29 10:57:00 -0800543 Variable* v = stubArgs.Get(i++);
544
545 if (arg->GetDirection() & AidlArgument::OUT_DIR) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900546 generate_write_to_parcel(arg->GetType(), statements, v, transact_reply, true,
547 types->typenames_);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800548 }
Christopher Wiley67502f12016-01-29 10:57:00 -0800549 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800550
Christopher Wiley67502f12016-01-29 10:57:00 -0800551 // return true
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800552 statements->Add(new ReturnStatement(TRUE_VALUE));
553}
Adam Lesinskiffa16862014-01-23 18:17:42 -0800554
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900555static void generate_stub_case(const AidlInterface& iface, const AidlMethod& method,
556 const std::string& transactCodeName, bool oneway,
557 StubClass* stubClass, JavaTypeNamespace* types,
558 const Options& options) {
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800559 Case* c = new Case(transactCodeName);
560
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900561 generate_stub_code(iface, method, oneway, stubClass->transact_data, stubClass->transact_reply,
562 types, c->statements, stubClass, options);
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800563
564 stubClass->transact_switch->cases.push_back(c);
565}
566
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900567static void generate_stub_case_outline(const AidlInterface& iface, const AidlMethod& method,
568 const std::string& transactCodeName, bool oneway,
569 StubClass* stubClass, JavaTypeNamespace* types,
570 const Options& options) {
Andreas Gampe1b865af2017-11-22 11:31:47 -0800571 std::string outline_name = "onTransact$" + method.GetName() + "$";
572 // Generate an "outlined" method with the actual code.
573 {
574 Variable* transact_data = new Variable(types->ParcelType(), "data");
575 Variable* transact_reply = new Variable(types->ParcelType(), "reply");
576 Method* onTransact_case = new Method;
577 onTransact_case->modifiers = PRIVATE;
578 onTransact_case->returnType = types->BoolType();
579 onTransact_case->name = outline_name;
580 onTransact_case->parameters.push_back(transact_data);
581 onTransact_case->parameters.push_back(transact_reply);
582 onTransact_case->statements = new StatementBlock;
583 onTransact_case->exceptions.push_back(types->RemoteExceptionType());
584 stubClass->elements.push_back(onTransact_case);
585
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900586 generate_stub_code(iface, method, oneway, transact_data, transact_reply, types,
587 onTransact_case->statements, stubClass, options);
Andreas Gampe1b865af2017-11-22 11:31:47 -0800588 }
589
590 // Generate the case dispatch.
591 {
592 Case* c = new Case(transactCodeName);
593
594 MethodCall* helper_call = new MethodCall(THIS_VALUE,
595 outline_name,
596 2,
597 stubClass->transact_data,
598 stubClass->transact_reply);
599 c->statements->Add(new ReturnStatement(helper_call));
600
601 stubClass->transact_switch->cases.push_back(c);
602 }
603}
604
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800605static std::unique_ptr<Method> generate_proxy_method(
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900606 const AidlInterface& iface, const AidlMethod& method, const std::string& transactCodeName,
607 bool oneway, ProxyClass* proxyClass, JavaTypeNamespace* types, const Options& options) {
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800608 std::unique_ptr<Method> proxy(new Method);
Christopher Wiley67502f12016-01-29 10:57:00 -0800609 proxy->comment = method.GetComments();
610 proxy->modifiers = PUBLIC | OVERRIDE;
611 proxy->returnType = method.GetType().GetLanguageType<Type>();
612 proxy->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
613 proxy->name = method.GetName();
614 proxy->statements = new StatementBlock;
615 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
616 proxy->parameters.push_back(
617 new Variable(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
618 arg->GetType().IsArray() ? 1 : 0));
619 }
620 proxy->exceptions.push_back(types->RemoteExceptionType());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800621
Christopher Wiley67502f12016-01-29 10:57:00 -0800622 // the parcels
623 Variable* _data = new Variable(types->ParcelType(), "_data");
624 proxy->statements->Add(new VariableDeclaration(
625 _data, new MethodCall(types->ParcelType(), "obtain")));
Yi Kong894d6ba2018-07-24 11:27:38 -0700626 Variable* _reply = nullptr;
Christopher Wiley67502f12016-01-29 10:57:00 -0800627 if (!oneway) {
628 _reply = new Variable(types->ParcelType(), "_reply");
629 proxy->statements->Add(new VariableDeclaration(
630 _reply, new MethodCall(types->ParcelType(), "obtain")));
631 }
632
633 // the return value
Yi Kong894d6ba2018-07-24 11:27:38 -0700634 Variable* _result = nullptr;
Christopher Wiley67502f12016-01-29 10:57:00 -0800635 if (method.GetType().GetName() != "void") {
636 _result = new Variable(proxy->returnType, "_result",
637 method.GetType().IsArray() ? 1 : 0);
638 proxy->statements->Add(new VariableDeclaration(_result));
639 }
640
641 // try and finally
642 TryStatement* tryStatement = new TryStatement();
643 proxy->statements->Add(tryStatement);
644 FinallyStatement* finallyStatement = new FinallyStatement();
645 proxy->statements->Add(finallyStatement);
646
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900647 if (options.GenTraces()) {
Martijn Coenenf1b50782018-02-21 21:06:23 +0100648 tryStatement->statements->Add(new MethodCall(
649 new LiteralExpression("android.os.Trace"), "traceBegin", 2,
650 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"),
651 new StringLiteralExpression(iface.GetName() + "::" +
652 method.GetName() + "::client")));
653 }
654
Christopher Wiley67502f12016-01-29 10:57:00 -0800655 // the interface identifier token: the DESCRIPTOR constant, marshalled as a
656 // string
657 tryStatement->statements->Add(new MethodCall(
658 _data, "writeInterfaceToken", 1, new LiteralExpression("DESCRIPTOR")));
659
660 // the parameters
661 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
662 const Type* t = arg->GetType().GetLanguageType<Type>();
663 Variable* v =
664 new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
665 AidlArgument::Direction dir = arg->GetDirection();
666 if (dir == AidlArgument::OUT_DIR && arg->GetType().IsArray()) {
667 IfStatement* checklen = new IfStatement();
668 checklen->expression = new Comparison(v, "==", NULL_VALUE);
669 checklen->statements->Add(
670 new MethodCall(_data, "writeInt", 1, new LiteralExpression("-1")));
671 checklen->elseif = new IfStatement();
672 checklen->elseif->statements->Add(
673 new MethodCall(_data, "writeInt", 1, new FieldVariable(v, "length")));
674 tryStatement->statements->Add(checklen);
675 } else if (dir & AidlArgument::IN_DIR) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900676 generate_write_to_parcel(arg->GetType(), tryStatement->statements, v, _data, false,
677 types->typenames_);
Christopher Wiley5f848522016-03-01 16:29:41 -0800678 } else {
679 delete v;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800680 }
Christopher Wiley67502f12016-01-29 10:57:00 -0800681 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800682
Christopher Wiley67502f12016-01-29 10:57:00 -0800683 // the transact call
Jiyong Park75e1a742018-07-04 12:31:23 +0900684 unique_ptr<MethodCall> call(new MethodCall(
685 proxyClass->mRemote, "transact", 4, new LiteralExpression("Stub." + transactCodeName), _data,
Christopher Wiley67502f12016-01-29 10:57:00 -0800686 _reply ? _reply : NULL_VALUE,
Jiyong Park75e1a742018-07-04 12:31:23 +0900687 new LiteralExpression(oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0")));
688 unique_ptr<Variable> _status(new Variable(types->BoolType(), "_status"));
689 tryStatement->statements->Add(new VariableDeclaration(_status.release(), call.release()));
690
691 // If the transaction returns false, which means UNKNOWN_TRANSACTION, fall
692 // back to the local method in the default impl, if set before.
693 vector<string> arg_names;
694 for (const auto& arg : method.GetArguments()) {
695 arg_names.emplace_back(arg->GetName());
696 }
697 bool has_return_type = method.GetType().GetName() != "void";
698 tryStatement->statements->Add(new LiteralStatement(
699 android::base::StringPrintf(has_return_type ? "if (!_status && getDefaultImpl() != null) {\n"
700 " return getDefaultImpl().%s(%s);\n"
701 "}\n"
702 : "if (!_status && getDefaultImpl() != null) {\n"
703 " getDefaultImpl().%s(%s);\n"
704 " return;\n"
705 "}\n",
706 method.GetName().c_str(), Join(arg_names, ", ").c_str())));
Adam Lesinskiffa16862014-01-23 18:17:42 -0800707
Christopher Wiley67502f12016-01-29 10:57:00 -0800708 // throw back exceptions.
709 if (_reply) {
710 MethodCall* ex = new MethodCall(_reply, "readException", 0);
711 tryStatement->statements->Add(ex);
712 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800713
Christopher Wiley67502f12016-01-29 10:57:00 -0800714 // returning and cleanup
Yi Kong894d6ba2018-07-24 11:27:38 -0700715 if (_reply != nullptr) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900716 // keep this across return value and arguments in order to create the
717 // classloader at most once.
718 bool is_classloader_created = false;
Yi Kong894d6ba2018-07-24 11:27:38 -0700719 if (_result != nullptr) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900720 string code;
721 CodeWriterPtr writer = CodeWriter::ForString(&code);
722 CodeGeneratorContext context{.writer = *(writer.get()),
723 .typenames = types->typenames_,
724 .type = method.GetType(),
725 .var = _result->name,
726 .parcel = _reply->name,
727 .is_classloader_created = &is_classloader_created};
728 CreateFromParcelFor(context);
729 writer->Close();
730 tryStatement->statements->Add(new LiteralStatement(code));
Adam Lesinskiffa16862014-01-23 18:17:42 -0800731 }
Christopher Wiley67502f12016-01-29 10:57:00 -0800732
733 // the out/inout parameters
734 for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
Christopher Wiley67502f12016-01-29 10:57:00 -0800735 if (arg->GetDirection() & AidlArgument::OUT_DIR) {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900736 string code;
737 CodeWriterPtr writer = CodeWriter::ForString(&code);
738 CodeGeneratorContext context{.writer = *(writer.get()),
739 .typenames = types->typenames_,
740 .type = arg->GetType(),
741 .var = arg->GetName(),
742 .parcel = _reply->name,
743 .is_classloader_created = &is_classloader_created};
744 ReadFromParcelFor(context);
745 writer->Close();
746 tryStatement->statements->Add(new LiteralStatement(code));
Christopher Wiley67502f12016-01-29 10:57:00 -0800747 }
748 }
749
750 finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
751 }
752 finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
753
Jiyong Parkfbbfa932018-07-30 21:44:10 +0900754 if (options.GenTraces()) {
Martijn Coenenf1b50782018-02-21 21:06:23 +0100755 finallyStatement->statements->Add(new MethodCall(
756 new LiteralExpression("android.os.Trace"), "traceEnd", 1,
757 new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL")));
758 }
759
Yi Kong894d6ba2018-07-24 11:27:38 -0700760 if (_result != nullptr) {
Christopher Wiley67502f12016-01-29 10:57:00 -0800761 proxy->statements->Add(new ReturnStatement(_result));
762 }
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800763
764 return proxy;
765}
766
Jiyong Park74595c12018-07-23 15:22:50 +0900767static void generate_methods(const AidlInterface& iface, const AidlMethod& method, Class* interface,
768 StubClass* stubClass, ProxyClass* proxyClass, int index,
769 JavaTypeNamespace* types, const Options& options) {
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800770 const bool oneway = proxyClass->mOneWay || method.IsOneway();
771
772 // == the TRANSACT_ constant =============================================
773 string transactCodeName = "TRANSACTION_";
774 transactCodeName += method.GetName();
775
776 Field* transactCode = new Field(
777 STATIC | FINAL, new Variable(types->IntType(), transactCodeName));
778 transactCode->value =
779 StringPrintf("(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
780 stubClass->elements.push_back(transactCode);
781
Olivier Gaillard11401402018-07-05 15:01:34 +0100782 // getTransactionName
Jiyong Park74595c12018-07-23 15:22:50 +0900783 if (options.GenTransactionNames()) {
Olivier Gaillard11401402018-07-05 15:01:34 +0100784 Case* c = new Case(transactCodeName);
785 c->statements->Add(new ReturnStatement(new StringLiteralExpression(method.GetName())));
786 stubClass->code_to_method_name_switch->cases.push_back(c);
787 }
788
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800789 // == the declaration in the interface ===================================
Jiyong Park309668e2018-07-28 16:55:44 +0900790 ClassElement* decl;
791 if (method.IsUserDefined()) {
792 decl = generate_interface_method(method, types).release();
793 } else {
794 if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
795 std::ostringstream code;
796 code << "public int " << kGetInterfaceVersion << "() "
797 << "throws android.os.RemoteException;\n";
798 decl = new LiteralClassElement(code.str());
799 }
800 }
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800801 interface->elements.push_back(decl);
802
803 // == the stub method ====================================================
Jiyong Park309668e2018-07-28 16:55:44 +0900804 if (method.IsUserDefined()) {
805 bool outline_stub =
806 stubClass->transact_outline && stubClass->outline_methods.count(&method) != 0;
807 if (outline_stub) {
808 generate_stub_case_outline(iface, method, transactCodeName, oneway, stubClass, types,
809 options);
810 } else {
811 generate_stub_case(iface, method, transactCodeName, oneway, stubClass, types, options);
812 }
Andreas Gampe1b865af2017-11-22 11:31:47 -0800813 } else {
Jiyong Park309668e2018-07-28 16:55:44 +0900814 if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
815 Case* c = new Case(transactCodeName);
816 std::ostringstream code;
817 code << "reply.writeInt(" << kGetInterfaceVersion << "());\n"
818 << "return true;\n";
819 c->statements->Add(new LiteralStatement(code.str()));
820 stubClass->transact_switch->cases.push_back(c);
821 }
Andreas Gampe1b865af2017-11-22 11:31:47 -0800822 }
Andreas Gampe7d7fa602017-11-22 10:50:03 -0800823
824 // == the proxy method ===================================================
Jiyong Park309668e2018-07-28 16:55:44 +0900825 ClassElement* proxy = nullptr;
826 if (method.IsUserDefined()) {
827 proxy =
828 generate_proxy_method(iface, method, transactCodeName, oneway, proxyClass, types, options)
829 .release();
830
831 } else {
832 if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) {
833 std::ostringstream code;
834 code << "@Override\n"
835 << "public int " << kGetInterfaceVersion << "()"
836 << " throws "
837 << "android.os.RemoteException {\n"
838 << " if (mCachedVersion == -1) {\n"
839 << " android.os.Parcel data = android.os.Parcel.obtain();\n"
840 << " android.os.Parcel reply = android.os.Parcel.obtain();\n"
841 << " try {\n"
842 << " mRemote.transact(Stub." << transactCodeName << ", "
843 << "data, reply, 0);\n"
844 << " mCachedVersion = reply.readInt();\n"
845 << " } finally {\n"
846 << " reply.recycle();\n"
847 << " data.recycle();\n"
848 << " }\n"
849 << " }\n"
850 << " return mCachedVersion;\n"
851 << "}\n";
852 proxy = new LiteralClassElement(code.str());
853 }
854 }
855 if (proxy != nullptr) {
856 proxyClass->elements.push_back(proxy);
857 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800858}
859
Christopher Wiley67502f12016-01-29 10:57:00 -0800860static void generate_interface_descriptors(StubClass* stub, ProxyClass* proxy,
861 const JavaTypeNamespace* types) {
862 // the interface descriptor transaction handler
863 Case* c = new Case("INTERFACE_TRANSACTION");
864 c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 1,
Andreas Gampee9c816e2018-03-14 09:05:48 -0700865 stub->get_transact_descriptor(types,
866 nullptr)));
Christopher Wiley67502f12016-01-29 10:57:00 -0800867 c->statements->Add(new ReturnStatement(TRUE_VALUE));
868 stub->transact_switch->cases.push_back(c);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800869
Christopher Wiley67502f12016-01-29 10:57:00 -0800870 // and the proxy-side method returning the descriptor directly
871 Method* getDesc = new Method;
872 getDesc->modifiers = PUBLIC;
873 getDesc->returnType = types->StringType();
874 getDesc->returnTypeDimension = 0;
875 getDesc->name = "getInterfaceDescriptor";
876 getDesc->statements = new StatementBlock;
877 getDesc->statements->Add(
878 new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
879 proxy->elements.push_back(getDesc);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800880}
881
Andreas Gampee9c816e2018-03-14 09:05:48 -0700882// Check whether (some) methods in this interface should be "outlined," that
883// is, have specific onTransact methods for certain cases. Set up StubClass
884// metadata accordingly.
885//
886// Outlining will be enabled if the interface has more than outline_threshold
887// methods. In that case, the methods are sorted by number of arguments
888// (so that more "complex" methods come later), and the first non_outline_count
889// number of methods not outlined (are kept in the onTransact() method).
890//
891// Requirements: non_outline_count <= outline_threshold.
892static void compute_outline_methods(const AidlInterface* iface,
893 StubClass* stub,
894 size_t outline_threshold,
895 size_t non_outline_count) {
896 CHECK_LE(non_outline_count, outline_threshold);
897 // We'll outline (create sub methods) if there are more than min_methods
898 // cases.
899 stub->transact_outline = iface->GetMethods().size() > outline_threshold;
900 if (stub->transact_outline) {
901 stub->all_method_count = iface->GetMethods().size();
902 std::vector<const AidlMethod*> methods;
903 methods.reserve(iface->GetMethods().size());
904 for (const std::unique_ptr<AidlMethod>& ptr : iface->GetMethods()) {
905 methods.push_back(ptr.get());
906 }
907
908 std::stable_sort(
909 methods.begin(),
910 methods.end(),
911 [](const AidlMethod* m1, const AidlMethod* m2) {
912 return m1->GetArguments().size() < m2->GetArguments().size();
913 });
914
915 stub->outline_methods.insert(methods.begin() + non_outline_count,
916 methods.end());
917 }
918}
919
Jiyong Park75e1a742018-07-04 12:31:23 +0900920static unique_ptr<ClassElement> generate_default_impl_method(const AidlMethod& method) {
921 unique_ptr<Method> default_method(new Method);
922 default_method->comment = method.GetComments();
923 default_method->modifiers = PUBLIC | OVERRIDE;
924 default_method->returnType = method.GetType().GetLanguageType<Type>();
925 default_method->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
926 default_method->name = method.GetName();
927 default_method->statements = new StatementBlock;
928 for (const auto& arg : method.GetArguments()) {
929 default_method->parameters.push_back(new Variable(
930 arg->GetType().GetLanguageType<Type>(), arg->GetName(), arg->GetType().IsArray() ? 1 : 0));
931 }
932 default_method->exceptions.push_back(
933 method.GetType().GetLanguageType<Type>()->GetTypeNamespace()->RemoteExceptionType());
934
935 if (method.GetType().GetName() != "void") {
Jiyong Park1d2df7d2018-07-23 15:22:50 +0900936 const string& defaultValue = DefaultJavaValueOf(method.GetType());
Jiyong Park75e1a742018-07-04 12:31:23 +0900937 default_method->statements->Add(
938 new LiteralStatement(StringPrintf("return %s;\n", defaultValue.c_str())));
939 }
940 return default_method;
941}
942
Jiyong Park309668e2018-07-28 16:55:44 +0900943static unique_ptr<Class> generate_default_impl_class(const AidlInterface& iface,
944 const Options& options) {
Jiyong Park75e1a742018-07-04 12:31:23 +0900945 unique_ptr<Class> default_class(new Class);
946 default_class->comment = "/** Default implementation for " + iface.GetName() + ". */";
947 default_class->modifiers = PUBLIC | STATIC;
948 default_class->what = Class::CLASS;
949 default_class->type = iface.GetLanguageType<InterfaceType>()->GetDefaultImpl();
950 default_class->interfaces.emplace_back(iface.GetLanguageType<InterfaceType>());
951
952 for (const auto& m : iface.GetMethods()) {
Jiyong Park309668e2018-07-28 16:55:44 +0900953 if (m->IsUserDefined()) {
954 default_class->elements.emplace_back(generate_default_impl_method(*(m.get())).release());
955 } else {
956 if (m->GetName() == kGetInterfaceVersion && options.Version() > 0) {
Jiyong Parka2f9ca32018-08-01 21:04:11 +0900957 // This is called only when the remote side is not implementing this
958 // method, which is impossible in normal case, because this method is
959 // automatically declared in the interface class and not implementing
960 // it in the remote side is causing compilation error. But if the remote
961 // side somehow managed to not implement it, that's an error and we
962 // report the case by returning -1 here.
Jiyong Park309668e2018-07-28 16:55:44 +0900963 std::ostringstream code;
964 code << "@Override\n"
965 << "public int " << kGetInterfaceVersion << "() {\n"
Jiyong Parka2f9ca32018-08-01 21:04:11 +0900966 << " return -1;\n"
Jiyong Park309668e2018-07-28 16:55:44 +0900967 << "}\n";
968 default_class->elements.emplace_back(new LiteralClassElement(code.str()));
969 }
970 }
Jiyong Park75e1a742018-07-04 12:31:23 +0900971 }
972
973 default_class->elements.emplace_back(
974 new LiteralClassElement("@Override\n"
975 "public android.os.IBinder asBinder() {\n"
976 " return null;\n"
977 "}\n"));
978
979 return default_class;
980}
981
Jiyong Park74595c12018-07-23 15:22:50 +0900982Class* generate_binder_interface_class(const AidlInterface* iface, JavaTypeNamespace* types,
983 const Options& options) {
Christopher Wiley67502f12016-01-29 10:57:00 -0800984 const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800985
Christopher Wiley67502f12016-01-29 10:57:00 -0800986 // the interface class
987 Class* interface = new Class;
988 interface->comment = iface->GetComments();
989 interface->modifiers = PUBLIC;
990 interface->what = Class::INTERFACE;
991 interface->type = interfaceType;
992 interface->interfaces.push_back(types->IInterfaceType());
Jiyong Parka6605ab2018-11-11 14:30:21 +0900993 interface->annotations = generate_java_annotations(*iface);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800994
Jiyong Park309668e2018-07-28 16:55:44 +0900995 if (options.Version()) {
996 std::ostringstream code;
997 code << "/**\n"
998 << " * The version of this interface that the caller is built against.\n"
999 << " * This might be different from what {@link #getInterfaceVersion()\n"
1000 << " * getInterfaceVersion} returns as that is the version of the interface\n"
1001 << " * that the remote object is implementing.\n"
1002 << " */\n"
1003 << "public static final int VERSION = " << options.Version() << ";\n";
1004 interface->elements.emplace_back(new LiteralClassElement(code.str()));
1005 }
1006
Jiyong Park75e1a742018-07-04 12:31:23 +09001007 // the default impl class
Jiyong Park309668e2018-07-28 16:55:44 +09001008 Class* default_impl = generate_default_impl_class(*iface, options).release();
1009 interface->elements.emplace_back(default_impl);
Jiyong Park75e1a742018-07-04 12:31:23 +09001010
Christopher Wiley67502f12016-01-29 10:57:00 -08001011 // the stub inner class
1012 StubClass* stub =
Olivier Gaillard11401402018-07-05 15:01:34 +01001013 new StubClass(interfaceType->GetStub(), interfaceType, types, options);
Christopher Wiley67502f12016-01-29 10:57:00 -08001014 interface->elements.push_back(stub);
Adam Lesinskiffa16862014-01-23 18:17:42 -08001015
Andreas Gampee9c816e2018-03-14 09:05:48 -07001016 compute_outline_methods(iface,
1017 stub,
1018 options.onTransact_outline_threshold_,
1019 options.onTransact_non_outline_count_);
Andreas Gampe1b865af2017-11-22 11:31:47 -08001020
Christopher Wiley67502f12016-01-29 10:57:00 -08001021 // the proxy inner class
Jiyong Park309668e2018-07-28 16:55:44 +09001022 ProxyClass* proxy = new ProxyClass(types, interfaceType->GetProxy(), interfaceType, options);
Christopher Wiley67502f12016-01-29 10:57:00 -08001023 stub->elements.push_back(proxy);
Adam Lesinskiffa16862014-01-23 18:17:42 -08001024
Christopher Wiley67502f12016-01-29 10:57:00 -08001025 // stub and proxy support for getInterfaceDescriptor()
1026 generate_interface_descriptors(stub, proxy, types);
Adam Lesinskiffa16862014-01-23 18:17:42 -08001027
Christopher Wiley67502f12016-01-29 10:57:00 -08001028 // all the declared constants of the interface
Steven Moreland693640b2018-07-19 13:46:27 -07001029 for (const auto& constant : iface->GetConstantDeclarations()) {
1030 const AidlConstantValue& value = constant->GetValue();
1031
1032 switch (value.GetType()) {
1033 case AidlConstantValue::Type::STRING: {
Steven Moreland860b1942018-08-16 14:59:28 -07001034 generate_string_constant(interface, constant->GetName(),
1035 constant->ValueString(ConstantValueDecorator));
Steven Moreland693640b2018-07-19 13:46:27 -07001036 break;
1037 }
Steven Moreland25294322018-08-07 18:13:55 -07001038 case AidlConstantValue::Type::INTEGRAL:
1039 case AidlConstantValue::Type::HEXIDECIMAL: {
Steven Moreland860b1942018-08-16 14:59:28 -07001040 generate_int_constant(interface, constant->GetName(),
1041 constant->ValueString(ConstantValueDecorator));
Steven Moreland693640b2018-07-19 13:46:27 -07001042 break;
1043 }
1044 default: {
1045 LOG(FATAL) << "Unrecognized constant type: " << static_cast<int>(value.GetType());
1046 }
1047 }
Christopher Wiley67502f12016-01-29 10:57:00 -08001048 }
Casey Dahlind40e2fe2015-11-24 14:06:52 -08001049
Christopher Wiley67502f12016-01-29 10:57:00 -08001050 // all the declared methods of the interface
Andreas Gampe1b865af2017-11-22 11:31:47 -08001051
Christopher Wiley67502f12016-01-29 10:57:00 -08001052 for (const auto& item : iface->GetMethods()) {
Martijn Coenenf1b50782018-02-21 21:06:23 +01001053 generate_methods(*iface,
1054 *item,
Andreas Gampe1b865af2017-11-22 11:31:47 -08001055 interface,
1056 stub,
1057 proxy,
1058 item->GetId(),
Olivier Gaillard11401402018-07-05 15:01:34 +01001059 types,
1060 options);
Christopher Wiley67502f12016-01-29 10:57:00 -08001061 }
Jiyong Park75e1a742018-07-04 12:31:23 +09001062
1063 // additional static methods for the default impl set/get to the
1064 // stub class. Can't add them to the interface as the generated java files
1065 // may be compiled with Java < 1.7 where static interface method isn't
1066 // supported.
1067 // TODO(b/111417145) make this conditional depending on the Java language
1068 // version requested
1069 const string i_name = interfaceType->JavaType();
1070 stub->elements.emplace_back(new LiteralClassElement(
1071 StringPrintf("public static boolean setDefaultImpl(%s impl) {\n"
1072 " if (Stub.Proxy.sDefaultImpl == null && impl != null) {\n"
1073 " Stub.Proxy.sDefaultImpl = impl;\n"
1074 " return true;\n"
1075 " }\n"
1076 " return false;\n"
1077 "}\n",
1078 i_name.c_str())));
1079 stub->elements.emplace_back(
1080 new LiteralClassElement(StringPrintf("public static %s getDefaultImpl() {\n"
1081 " return Stub.Proxy.sDefaultImpl;\n"
1082 "}\n",
1083 i_name.c_str())));
1084
1085 // the static field is defined in the proxy class, not in the interface class
1086 // because all fields in an interface class are by default final.
1087 proxy->elements.emplace_back(new LiteralClassElement(
1088 StringPrintf("public static %s sDefaultImpl = null;\n", i_name.c_str())));
1089
Andreas Gampea8a66fe2017-11-22 12:17:00 -08001090 stub->finish();
Adam Lesinskiffa16862014-01-23 18:17:42 -08001091
Christopher Wiley67502f12016-01-29 10:57:00 -08001092 return interface;
Adam Lesinskiffa16862014-01-23 18:17:42 -08001093}
1094
Christopher Wileydb154a52015-09-28 16:32:25 -07001095} // namespace java
Christopher Wileyfdeb0f42015-09-11 15:38:22 -07001096} // namespace android
1097} // namespace aidl