• 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 <string.h>
23 
24 #include <android-base/macros.h>
25 
26 #include "type_java.h"
27 
28 using std::string;
29 
30 namespace android {
31 namespace aidl {
32 namespace java {
33 
34 // =================================================
35 class StubClass : public Class {
36  public:
37   StubClass(const Type* type, const InterfaceType* interfaceType,
38             JavaTypeNamespace* types);
39   virtual ~StubClass() = default;
40 
41   Variable* transact_code;
42   Variable* transact_data;
43   Variable* transact_reply;
44   Variable* transact_flags;
45   SwitchStatement* transact_switch;
46 
47  private:
48   void make_as_interface(const InterfaceType* interfaceType,
49                          JavaTypeNamespace* types);
50 
51   DISALLOW_COPY_AND_ASSIGN(StubClass);
52 };
53 
StubClass(const Type * type,const InterfaceType * interfaceType,JavaTypeNamespace * types)54 StubClass::StubClass(const Type* type, const InterfaceType* interfaceType,
55                      JavaTypeNamespace* types)
56     : Class() {
57   this->comment = "/** Local-side IPC implementation stub class. */";
58   this->modifiers = PUBLIC | ABSTRACT | STATIC;
59   this->what = Class::CLASS;
60   this->type = type;
61   this->extends = types->BinderNativeType();
62   this->interfaces.push_back(interfaceType);
63 
64   // descriptor
65   Field* descriptor =
66       new Field(STATIC | FINAL | PRIVATE,
67                 new Variable(types->StringType(), "DESCRIPTOR"));
68   descriptor->value = "\"" + interfaceType->JavaType() + "\"";
69   this->elements.push_back(descriptor);
70 
71   // ctor
72   Method* ctor = new Method;
73   ctor->modifiers = PUBLIC;
74   ctor->comment =
75       "/** Construct the stub at attach it to the "
76       "interface. */";
77   ctor->name = "Stub";
78   ctor->statements = new StatementBlock;
79   MethodCall* attach =
80       new MethodCall(THIS_VALUE, "attachInterface", 2, THIS_VALUE,
81                      new LiteralExpression("DESCRIPTOR"));
82   ctor->statements->Add(attach);
83   this->elements.push_back(ctor);
84 
85   // asInterface
86   make_as_interface(interfaceType, types);
87 
88   // asBinder
89   Method* asBinder = new Method;
90   asBinder->modifiers = PUBLIC | OVERRIDE;
91   asBinder->returnType = types->IBinderType();
92   asBinder->name = "asBinder";
93   asBinder->statements = new StatementBlock;
94   asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
95   this->elements.push_back(asBinder);
96 
97   // onTransact
98   this->transact_code = new Variable(types->IntType(), "code");
99   this->transact_data = new Variable(types->ParcelType(), "data");
100   this->transact_reply = new Variable(types->ParcelType(), "reply");
101   this->transact_flags = new Variable(types->IntType(), "flags");
102   Method* onTransact = new Method;
103   onTransact->modifiers = PUBLIC | OVERRIDE;
104   onTransact->returnType = types->BoolType();
105   onTransact->name = "onTransact";
106   onTransact->parameters.push_back(this->transact_code);
107   onTransact->parameters.push_back(this->transact_data);
108   onTransact->parameters.push_back(this->transact_reply);
109   onTransact->parameters.push_back(this->transact_flags);
110   onTransact->statements = new StatementBlock;
111   onTransact->exceptions.push_back(types->RemoteExceptionType());
112   this->elements.push_back(onTransact);
113   this->transact_switch = new SwitchStatement(this->transact_code);
114 
115   onTransact->statements->Add(this->transact_switch);
116   MethodCall* superCall = new MethodCall(
117       SUPER_VALUE, "onTransact", 4, this->transact_code, this->transact_data,
118       this->transact_reply, this->transact_flags);
119   onTransact->statements->Add(new ReturnStatement(superCall));
120 }
121 
make_as_interface(const InterfaceType * interfaceType,JavaTypeNamespace * types)122 void StubClass::make_as_interface(const InterfaceType* interfaceType,
123                                   JavaTypeNamespace* types) {
124   Variable* obj = new Variable(types->IBinderType(), "obj");
125 
126   Method* m = new Method;
127   m->comment = "/**\n * Cast an IBinder object into an ";
128   m->comment += interfaceType->JavaType();
129   m->comment += " interface,\n";
130   m->comment += " * generating a proxy if needed.\n */";
131   m->modifiers = PUBLIC | STATIC;
132   m->returnType = interfaceType;
133   m->name = "asInterface";
134   m->parameters.push_back(obj);
135   m->statements = new StatementBlock;
136 
137   IfStatement* ifstatement = new IfStatement();
138   ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
139   ifstatement->statements = new StatementBlock;
140   ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
141   m->statements->Add(ifstatement);
142 
143   // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
144   MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
145   queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
146   IInterfaceType* iinType = new IInterfaceType(types);
147   Variable* iin = new Variable(iinType, "iin");
148   VariableDeclaration* iinVd =
149       new VariableDeclaration(iin, queryLocalInterface, NULL);
150   m->statements->Add(iinVd);
151 
152   // Ensure the instance type of the local object is as expected.
153   // One scenario where this is needed is if another package (with a
154   // different class loader) runs in the same process as the service.
155 
156   // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>)
157   // iin;
158   Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
159   Comparison* instOfCheck =
160       new Comparison(iin, " instanceof ",
161                      new LiteralExpression(interfaceType->JavaType()));
162   IfStatement* instOfStatement = new IfStatement();
163   instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
164   instOfStatement->statements = new StatementBlock;
165   instOfStatement->statements->Add(
166       new ReturnStatement(new Cast(interfaceType, iin)));
167   m->statements->Add(instOfStatement);
168 
169   NewExpression* ne = new NewExpression(interfaceType->GetProxy());
170   ne->arguments.push_back(obj);
171   m->statements->Add(new ReturnStatement(ne));
172 
173   this->elements.push_back(m);
174 }
175 
176 // =================================================
177 class ProxyClass : public Class {
178  public:
179   ProxyClass(const JavaTypeNamespace* types, const Type* type,
180              const InterfaceType* interfaceType);
181   virtual ~ProxyClass();
182 
183   Variable* mRemote;
184   bool mOneWay;
185 };
186 
ProxyClass(const JavaTypeNamespace * types,const Type * type,const InterfaceType * interfaceType)187 ProxyClass::ProxyClass(const JavaTypeNamespace* types, const Type* type,
188                        const InterfaceType* interfaceType)
189     : Class() {
190   this->modifiers = PRIVATE | STATIC;
191   this->what = Class::CLASS;
192   this->type = type;
193   this->interfaces.push_back(interfaceType);
194 
195   mOneWay = interfaceType->OneWay();
196 
197   // IBinder mRemote
198   mRemote = new Variable(types->IBinderType(), "mRemote");
199   this->elements.push_back(new Field(PRIVATE, mRemote));
200 
201   // Proxy()
202   Variable* remote = new Variable(types->IBinderType(), "remote");
203   Method* ctor = new Method;
204   ctor->name = "Proxy";
205   ctor->statements = new StatementBlock;
206   ctor->parameters.push_back(remote);
207   ctor->statements->Add(new Assignment(mRemote, remote));
208   this->elements.push_back(ctor);
209 
210   // IBinder asBinder()
211   Method* asBinder = new Method;
212   asBinder->modifiers = PUBLIC | OVERRIDE;
213   asBinder->returnType = types->IBinderType();
214   asBinder->name = "asBinder";
215   asBinder->statements = new StatementBlock;
216   asBinder->statements->Add(new ReturnStatement(mRemote));
217   this->elements.push_back(asBinder);
218 }
219 
~ProxyClass()220 ProxyClass::~ProxyClass() {}
221 
222 // =================================================
generate_new_array(const Type * t,StatementBlock * addTo,Variable * v,Variable * parcel,JavaTypeNamespace * types)223 static void generate_new_array(const Type* t, StatementBlock* addTo,
224                                Variable* v, Variable* parcel,
225                                JavaTypeNamespace* types) {
226   Variable* len = new Variable(types->IntType(), v->name + "_length");
227   addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
228   IfStatement* lencheck = new IfStatement();
229   lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
230   lencheck->statements->Add(new Assignment(v, NULL_VALUE));
231   lencheck->elseif = new IfStatement();
232   lencheck->elseif->statements->Add(
233       new Assignment(v, new NewArrayExpression(t, len)));
234   addTo->Add(lencheck);
235 }
236 
generate_write_to_parcel(const Type * t,StatementBlock * addTo,Variable * v,Variable * parcel,int flags)237 static void generate_write_to_parcel(const Type* t, StatementBlock* addTo,
238                                      Variable* v, Variable* parcel, int flags) {
239   t->WriteToParcel(addTo, v, parcel, flags);
240 }
241 
generate_create_from_parcel(const Type * t,StatementBlock * addTo,Variable * v,Variable * parcel,Variable ** cl)242 static void generate_create_from_parcel(const Type* t, StatementBlock* addTo,
243                                         Variable* v, Variable* parcel,
244                                         Variable** cl) {
245   t->CreateFromParcel(addTo, v, parcel, cl);
246 }
247 
generate_int_constant(const AidlIntConstant & constant,Class * interface)248 static void generate_int_constant(const AidlIntConstant& constant,
249                                   Class* interface) {
250   IntConstant* decl = new IntConstant(constant.GetName(), constant.GetValue());
251   interface->elements.push_back(decl);
252 }
253 
generate_string_constant(const AidlStringConstant & constant,Class * interface)254 static void generate_string_constant(const AidlStringConstant& constant,
255                                      Class* interface) {
256   StringConstant* decl = new StringConstant(constant.GetName(),
257                                             constant.GetValue());
258   interface->elements.push_back(decl);
259 }
260 
generate_method(const AidlMethod & method,Class * interface,StubClass * stubClass,ProxyClass * proxyClass,int index,JavaTypeNamespace * types)261 static void generate_method(const AidlMethod& method, Class* interface,
262                             StubClass* stubClass, ProxyClass* proxyClass,
263                             int index, JavaTypeNamespace* types) {
264   int i;
265 
266   const bool oneway = proxyClass->mOneWay || method.IsOneway();
267 
268   // == the TRANSACT_ constant =============================================
269   string transactCodeName = "TRANSACTION_";
270   transactCodeName += method.GetName();
271 
272   char transactCodeValue[60];
273   sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)",
274           index);
275 
276   Field* transactCode = new Field(
277       STATIC | FINAL, new Variable(types->IntType(), transactCodeName));
278   transactCode->value = transactCodeValue;
279   stubClass->elements.push_back(transactCode);
280 
281   // == the declaration in the interface ===================================
282   Method* decl = new Method;
283   decl->comment = method.GetComments();
284   decl->modifiers = PUBLIC;
285   decl->returnType = method.GetType().GetLanguageType<Type>();
286   decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
287   decl->name = method.GetName();
288 
289   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
290     decl->parameters.push_back(
291         new Variable(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
292                      arg->GetType().IsArray() ? 1 : 0));
293   }
294 
295   decl->exceptions.push_back(types->RemoteExceptionType());
296 
297   interface->elements.push_back(decl);
298 
299   // == the stub method ====================================================
300 
301   Case* c = new Case(transactCodeName);
302 
303   MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName());
304 
305   // interface token validation is the very first thing we do
306   c->statements->Add(new MethodCall(stubClass->transact_data,
307                                     "enforceInterface", 1,
308                                     new LiteralExpression("DESCRIPTOR")));
309 
310   // args
311   Variable* cl = NULL;
312   VariableFactory stubArgs("_arg");
313   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
314     const Type* t = arg->GetType().GetLanguageType<Type>();
315     Variable* v = stubArgs.Get(t);
316     v->dimension = arg->GetType().IsArray() ? 1 : 0;
317 
318     c->statements->Add(new VariableDeclaration(v));
319 
320     if (arg->GetDirection() & AidlArgument::IN_DIR) {
321       generate_create_from_parcel(t, c->statements, v, stubClass->transact_data,
322                                   &cl);
323     } else {
324       if (!arg->GetType().IsArray()) {
325         c->statements->Add(new Assignment(v, new NewExpression(v->type)));
326       } else {
327         generate_new_array(v->type, c->statements, v, stubClass->transact_data,
328                            types);
329       }
330     }
331 
332     realCall->arguments.push_back(v);
333   }
334 
335   cl = NULL;
336 
337   // the real call
338   Variable* _result = NULL;
339   if (method.GetType().GetName() == "void") {
340     c->statements->Add(realCall);
341 
342     if (!oneway) {
343       // report that there were no exceptions
344       MethodCall* ex =
345           new MethodCall(stubClass->transact_reply, "writeNoException", 0);
346       c->statements->Add(ex);
347     }
348   } else {
349     _result =
350         new Variable(decl->returnType, "_result", decl->returnTypeDimension);
351     c->statements->Add(new VariableDeclaration(_result, realCall));
352 
353     if (!oneway) {
354       // report that there were no exceptions
355       MethodCall* ex =
356           new MethodCall(stubClass->transact_reply, "writeNoException", 0);
357       c->statements->Add(ex);
358     }
359 
360     // marshall the return value
361     generate_write_to_parcel(decl->returnType, c->statements, _result,
362                              stubClass->transact_reply,
363                              Type::PARCELABLE_WRITE_RETURN_VALUE);
364   }
365 
366   // out parameters
367   i = 0;
368   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
369     const Type* t = arg->GetType().GetLanguageType<Type>();
370     Variable* v = stubArgs.Get(i++);
371 
372     if (arg->GetDirection() & AidlArgument::OUT_DIR) {
373       generate_write_to_parcel(t, c->statements, v, stubClass->transact_reply,
374                                Type::PARCELABLE_WRITE_RETURN_VALUE);
375     }
376   }
377 
378   // return true
379   c->statements->Add(new ReturnStatement(TRUE_VALUE));
380   stubClass->transact_switch->cases.push_back(c);
381 
382   // == the proxy method ===================================================
383   Method* proxy = new Method;
384   proxy->comment = method.GetComments();
385   proxy->modifiers = PUBLIC | OVERRIDE;
386   proxy->returnType = method.GetType().GetLanguageType<Type>();
387   proxy->returnTypeDimension = method.GetType().IsArray() ? 1 : 0;
388   proxy->name = method.GetName();
389   proxy->statements = new StatementBlock;
390   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
391     proxy->parameters.push_back(
392         new Variable(arg->GetType().GetLanguageType<Type>(), arg->GetName(),
393                      arg->GetType().IsArray() ? 1 : 0));
394   }
395   proxy->exceptions.push_back(types->RemoteExceptionType());
396   proxyClass->elements.push_back(proxy);
397 
398   // the parcels
399   Variable* _data = new Variable(types->ParcelType(), "_data");
400   proxy->statements->Add(new VariableDeclaration(
401       _data, new MethodCall(types->ParcelType(), "obtain")));
402   Variable* _reply = NULL;
403   if (!oneway) {
404     _reply = new Variable(types->ParcelType(), "_reply");
405     proxy->statements->Add(new VariableDeclaration(
406         _reply, new MethodCall(types->ParcelType(), "obtain")));
407   }
408 
409   // the return value
410   _result = NULL;
411   if (method.GetType().GetName() != "void") {
412     _result = new Variable(proxy->returnType, "_result",
413                            method.GetType().IsArray() ? 1 : 0);
414     proxy->statements->Add(new VariableDeclaration(_result));
415   }
416 
417   // try and finally
418   TryStatement* tryStatement = new TryStatement();
419   proxy->statements->Add(tryStatement);
420   FinallyStatement* finallyStatement = new FinallyStatement();
421   proxy->statements->Add(finallyStatement);
422 
423   // the interface identifier token: the DESCRIPTOR constant, marshalled as a
424   // string
425   tryStatement->statements->Add(new MethodCall(
426       _data, "writeInterfaceToken", 1, new LiteralExpression("DESCRIPTOR")));
427 
428   // the parameters
429   for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
430     const Type* t = arg->GetType().GetLanguageType<Type>();
431     Variable* v =
432         new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
433     AidlArgument::Direction dir = arg->GetDirection();
434     if (dir == AidlArgument::OUT_DIR && arg->GetType().IsArray()) {
435       IfStatement* checklen = new IfStatement();
436       checklen->expression = new Comparison(v, "==", NULL_VALUE);
437       checklen->statements->Add(
438           new MethodCall(_data, "writeInt", 1, new LiteralExpression("-1")));
439       checklen->elseif = new IfStatement();
440       checklen->elseif->statements->Add(
441           new MethodCall(_data, "writeInt", 1, new FieldVariable(v, "length")));
442       tryStatement->statements->Add(checklen);
443     } else if (dir & AidlArgument::IN_DIR) {
444       generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
445     } else {
446       delete v;
447     }
448   }
449 
450   // the transact call
451   MethodCall* call = new MethodCall(
452       proxyClass->mRemote, "transact", 4,
453       new LiteralExpression("Stub." + transactCodeName), _data,
454       _reply ? _reply : NULL_VALUE,
455       new LiteralExpression(oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
456   tryStatement->statements->Add(call);
457 
458   // throw back exceptions.
459   if (_reply) {
460     MethodCall* ex = new MethodCall(_reply, "readException", 0);
461     tryStatement->statements->Add(ex);
462   }
463 
464   // returning and cleanup
465   if (_reply != NULL) {
466     if (_result != NULL) {
467       generate_create_from_parcel(proxy->returnType, tryStatement->statements,
468                                   _result, _reply, &cl);
469     }
470 
471     // the out/inout parameters
472     for (const std::unique_ptr<AidlArgument>& arg : method.GetArguments()) {
473       const Type* t = arg->GetType().GetLanguageType<Type>();
474       if (arg->GetDirection() & AidlArgument::OUT_DIR) {
475         Variable* v =
476             new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0);
477         t->ReadFromParcel(tryStatement->statements, v, _reply, &cl);
478       }
479     }
480 
481     finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
482   }
483   finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
484 
485   if (_result != NULL) {
486     proxy->statements->Add(new ReturnStatement(_result));
487   }
488 }
489 
generate_interface_descriptors(StubClass * stub,ProxyClass * proxy,const JavaTypeNamespace * types)490 static void generate_interface_descriptors(StubClass* stub, ProxyClass* proxy,
491                                            const JavaTypeNamespace* types) {
492   // the interface descriptor transaction handler
493   Case* c = new Case("INTERFACE_TRANSACTION");
494   c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 1,
495                                     new LiteralExpression("DESCRIPTOR")));
496   c->statements->Add(new ReturnStatement(TRUE_VALUE));
497   stub->transact_switch->cases.push_back(c);
498 
499   // and the proxy-side method returning the descriptor directly
500   Method* getDesc = new Method;
501   getDesc->modifiers = PUBLIC;
502   getDesc->returnType = types->StringType();
503   getDesc->returnTypeDimension = 0;
504   getDesc->name = "getInterfaceDescriptor";
505   getDesc->statements = new StatementBlock;
506   getDesc->statements->Add(
507       new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
508   proxy->elements.push_back(getDesc);
509 }
510 
generate_binder_interface_class(const AidlInterface * iface,JavaTypeNamespace * types)511 Class* generate_binder_interface_class(const AidlInterface* iface,
512                                        JavaTypeNamespace* types) {
513   const InterfaceType* interfaceType = iface->GetLanguageType<InterfaceType>();
514 
515   // the interface class
516   Class* interface = new Class;
517   interface->comment = iface->GetComments();
518   interface->modifiers = PUBLIC;
519   interface->what = Class::INTERFACE;
520   interface->type = interfaceType;
521   interface->interfaces.push_back(types->IInterfaceType());
522 
523   // the stub inner class
524   StubClass* stub =
525       new StubClass(interfaceType->GetStub(), interfaceType, types);
526   interface->elements.push_back(stub);
527 
528   // the proxy inner class
529   ProxyClass* proxy =
530       new ProxyClass(types, interfaceType->GetProxy(), interfaceType);
531   stub->elements.push_back(proxy);
532 
533   // stub and proxy support for getInterfaceDescriptor()
534   generate_interface_descriptors(stub, proxy, types);
535 
536   // all the declared constants of the interface
537   for (const auto& item : iface->GetIntConstants()) {
538     generate_int_constant(*item, interface);
539   }
540   for (const auto& item : iface->GetStringConstants()) {
541     generate_string_constant(*item, interface);
542   }
543 
544   // all the declared methods of the interface
545   for (const auto& item : iface->GetMethods()) {
546     generate_method(*item, interface, stub, proxy, item->GetId(), types);
547   }
548 
549   return interface;
550 }
551 
552 }  // namespace java
553 }  // namespace android
554 }  // namespace aidl
555