blob: e97f76105f0803343367af88e37164c43ba1ed61 [file] [log] [blame]
Christopher Wileyeb1acc12015-09-16 11:25:13 -07001/*
2 * Copyright (C) 2015, 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_cpp.h"
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070018
Casey Dahlin082f1d12015-09-21 14:06:25 -070019#include <cctype>
Christopher Wileyad339272015-10-05 19:11:58 -070020#include <cstring>
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070021#include <memory>
Casey Dahlin082f1d12015-09-21 14:06:25 -070022#include <random>
Casey Dahlince776cf2015-10-15 18:45:54 -070023#include <set>
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070024#include <string>
25
Christopher Wileye3550c62015-09-29 13:26:10 -070026#include <base/stringprintf.h>
27
Casey Dahlina834dd42015-09-23 11:52:15 -070028#include "aidl_language.h"
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070029#include "ast_cpp.h"
30#include "code_writer.h"
Christopher Wileyeb1acc12015-09-16 11:25:13 -070031#include "logging.h"
Christopher Wiley054afbd2015-10-16 17:08:43 -070032#include "os.h"
Christopher Wileyeb1acc12015-09-16 11:25:13 -070033
Christopher Wileye3550c62015-09-29 13:26:10 -070034using android::base::StringPrintf;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070035using std::string;
Casey Dahlin082f1d12015-09-21 14:06:25 -070036using std::unique_ptr;
Casey Dahlina834dd42015-09-23 11:52:15 -070037using std::vector;
Casey Dahlince776cf2015-10-15 18:45:54 -070038using std::set;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070039
Christopher Wileyeb1acc12015-09-16 11:25:13 -070040namespace android {
41namespace aidl {
Christopher Wileyf944e792015-09-29 10:00:46 -070042namespace cpp {
Casey Dahlina834dd42015-09-23 11:52:15 -070043namespace internals {
Christopher Wiley0c732db2015-09-29 14:36:44 -070044namespace {
Christopher Wiley36570f42015-10-08 17:20:11 -070045
Christopher Wileyad339272015-10-05 19:11:58 -070046const char kStatusOkOrBreakCheck[] = "if (status != android::OK) { break; }";
Christopher Wiley36570f42015-10-08 17:20:11 -070047const char kStatusOkOrReturnLiteral[] =
48 "if (status != android::OK) { return status; }";
Christopher Wileyad339272015-10-05 19:11:58 -070049const char kReturnVarName[] = "_aidl_return";
Christopher Wiley0c732db2015-09-29 14:36:44 -070050const char kAndroidStatusLiteral[] = "android::status_t";
Christopher Wiley36570f42015-10-08 17:20:11 -070051const char kAndroidParcelLiteral[] = "android::Parcel";
Christopher Wiley0c732db2015-09-29 14:36:44 -070052const char kIBinderHeader[] = "binder/IBinder.h";
53const char kIInterfaceHeader[] = "binder/IInterface.h";
Christopher Wileyad339272015-10-05 19:11:58 -070054const char kParcelHeader[] = "binder/Parcel.h";
Casey Dahlin082f1d12015-09-21 14:06:25 -070055
Christopher Wiley0c732db2015-09-29 14:36:44 -070056string UpperCase(const std::string& s) {
57 string result = s;
58 for (char& c : result)
59 c = toupper(c);
60 return result;
Casey Dahlina834dd42015-09-23 11:52:15 -070061}
Casey Dahlin082f1d12015-09-21 14:06:25 -070062
Christopher Wileyad339272015-10-05 19:11:58 -070063string BuildVarName(const AidlArgument& a) {
64 string prefix = "out_";
65 if (a.GetDirection() & AidlArgument::IN_DIR) {
66 prefix = "in_";
Christopher Wileye3550c62015-09-29 13:26:10 -070067 }
Christopher Wileyad339272015-10-05 19:11:58 -070068 return prefix + a.GetName();
69}
70
Christopher Wileyade4b452015-10-10 11:06:03 -070071ArgList BuildArgList(const TypeNamespace& types,
72 const AidlMethod& method,
73 bool for_declaration) {
Christopher Wileyad339272015-10-05 19:11:58 -070074 // Build up the argument list for the server method call.
75 vector<string> method_arguments;
76 for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
77 string literal;
78 if (for_declaration) {
79 // Method declarations need types, pointers to out params, and variable
80 // names that match the .aidl specification.
81 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlince776cf2015-10-15 18:45:54 -070082
Casey Dahlinb0966612015-10-19 16:35:26 -070083 literal = type->CppType(a->GetType().IsArray());
84
85 if (a->IsOut())
86 literal += "*";
87 else if (a->GetType().IsArray())
88 literal = "const " + literal + "&";
89
90 literal += " " + a->GetName();
Christopher Wileyad339272015-10-05 19:11:58 -070091 } else {
92 if (a->IsOut()) { literal = "&"; }
93 literal += BuildVarName(*a);
94 }
95 method_arguments.push_back(literal);
96 }
97
98 const Type* return_type = types.Find(method.GetType().GetName());
Casey Dahlince776cf2015-10-15 18:45:54 -070099
Christopher Wileyad339272015-10-05 19:11:58 -0700100 if (return_type != types.VoidType()) {
Christopher Wileyade4b452015-10-10 11:06:03 -0700101 string literal;
Christopher Wileyad339272015-10-05 19:11:58 -0700102 if (for_declaration) {
Christopher Wileyade4b452015-10-10 11:06:03 -0700103 literal = StringPrintf(
Casey Dahlinb0966612015-10-19 16:35:26 -0700104 "%s* %s", return_type->CppType(false /* not array */).c_str(),
105 kReturnVarName);
Christopher Wileyad339272015-10-05 19:11:58 -0700106 } else {
Christopher Wileyade4b452015-10-10 11:06:03 -0700107 literal = string{"&"} + kReturnVarName;
Christopher Wileyad339272015-10-05 19:11:58 -0700108 }
Christopher Wileyade4b452015-10-10 11:06:03 -0700109 method_arguments.push_back(literal);
Christopher Wileyad339272015-10-05 19:11:58 -0700110 }
111
Christopher Wileyade4b452015-10-10 11:06:03 -0700112 return ArgList(method_arguments);
Casey Dahlina834dd42015-09-23 11:52:15 -0700113}
114
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700115unique_ptr<Declaration> BuildMethodDecl(const AidlMethod& method,
Christopher Wiley0c732db2015-09-29 14:36:44 -0700116 const TypeNamespace& types,
117 bool for_interface) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700118 uint32_t modifiers = 0;
119 if (for_interface) {
120 modifiers |= MethodDecl::IS_VIRTUAL;
121 modifiers |= MethodDecl::IS_PURE_VIRTUAL;
122 } else {
123 modifiers |= MethodDecl::IS_OVERRIDE;
124 }
125
126 return unique_ptr<Declaration>{
127 new MethodDecl{kAndroidStatusLiteral,
Casey Dahlinf4a93112015-10-05 16:58:09 -0700128 method.GetName(),
Christopher Wileyad339272015-10-05 19:11:58 -0700129 BuildArgList(types, method, true /* for method decl */),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700130 modifiers}};
131}
132
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700133unique_ptr<CppNamespace> NestInNamespaces(
134 vector<unique_ptr<Declaration>> decls,
135 const vector<string>& package) {
136 if (package.empty()) {
137 // We should also be checking this before we get this far, but do it again
138 // for the sake of unit tests and meaningful errors.
139 LOG(FATAL) << "C++ generation requires a package declaration "
140 "for namespacing";
141 }
142 auto it = package.crbegin(); // Iterate over the namespaces inner to outer
143 unique_ptr<CppNamespace> inner{new CppNamespace{*it, std::move(decls)}};
144 ++it;
145 for (; it != package.crend(); ++it) {
146 inner.reset(new CppNamespace{*it, std::move(inner)});
147 }
148 return inner;
Christopher Wiley0c732db2015-09-29 14:36:44 -0700149}
150
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700151unique_ptr<CppNamespace> NestInNamespaces(unique_ptr<Declaration> decl,
152 const vector<string>& package) {
153 vector<unique_ptr<Declaration>> decls;
154 decls.push_back(std::move(decl));
155 return NestInNamespaces(std::move(decls), package);
Christopher Wiley36570f42015-10-08 17:20:11 -0700156}
157
Christopher Wileyad339272015-10-05 19:11:58 -0700158bool DeclareLocalVariable(const TypeNamespace& types, const AidlArgument& a,
159 StatementBlock* b) {
160 const Type* cpp_type = types.Find(a.GetType().GetName());
161 if (!cpp_type) { return false; }
162
Casey Dahlinb0966612015-10-19 16:35:26 -0700163 string type = cpp_type->CppType(a.GetType().IsArray());
164
165 b->AddLiteral(type + " " + BuildVarName(a));
Christopher Wileyad339272015-10-05 19:11:58 -0700166 return true;
167}
168
Christopher Wiley0c732db2015-09-29 14:36:44 -0700169enum class ClassNames { BASE, CLIENT, SERVER, INTERFACE };
170
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700171string ClassName(const AidlInterface& interface, ClassNames type) {
Casey Dahlinfb7da2e2015-10-08 17:26:09 -0700172 string c_name = interface.GetName();
Christopher Wiley0c732db2015-09-29 14:36:44 -0700173
174 if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
175 c_name = c_name.substr(1);
176
177 switch (type) {
178 case ClassNames::CLIENT:
179 c_name = "Bp" + c_name;
180 break;
181 case ClassNames::SERVER:
182 c_name = "Bn" + c_name;
183 break;
184 case ClassNames::INTERFACE:
185 c_name = "I" + c_name;
186 break;
187 case ClassNames::BASE:
188 break;
189 }
190 return c_name;
191}
192
Christopher Wiley054afbd2015-10-16 17:08:43 -0700193string HeaderFile(const AidlInterface& interface,
194 ClassNames class_type,
195 bool use_os_sep = true) {
196 string file_path = interface.GetPackage();
197 for (char& c: file_path) {
198 if (c == '.') {
199 c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
200 }
201 }
202 if (!file_path.empty()) {
203 file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
204 }
205 file_path += ClassName(interface, class_type);
206 file_path += ".h";
207
208 return file_path;
209}
210
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700211string BuildHeaderGuard(const AidlInterface& interface,
212 ClassNames header_type) {
213 string class_name = ClassName(interface, header_type);
214 for (size_t i = 1; i < class_name.size(); ++i) {
215 if (isupper(class_name[i])) {
216 class_name.insert(i, "_");
217 ++i;
218 }
219 }
220 string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_",
221 interface.GetPackage().c_str(),
222 class_name.c_str());
223 for (char& c : ret) {
224 if (c == '.') {
225 c = '_';
226 }
227 c = toupper(c);
228 }
229 return ret;
230}
Christopher Wiley36570f42015-10-08 17:20:11 -0700231
232unique_ptr<Declaration> DefineClientTransaction(const TypeNamespace& types,
233 const AidlInterface& interface,
234 const AidlMethod& method) {
235 const string i_name = ClassName(interface, ClassNames::INTERFACE);
236 const string bp_name = ClassName(interface, ClassNames::CLIENT);
237 unique_ptr<MethodImpl> ret{new MethodImpl{
238 kAndroidStatusLiteral, bp_name, method.GetName(),
239 ArgList{BuildArgList(types, method, true /* for method decl */)}}};
240 StatementBlock* b = ret->GetStatementBlock();
241
242 // Declare parcels to hold our query and the response.
243 b->AddLiteral(StringPrintf("%s data", kAndroidParcelLiteral));
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700244
245 if (!interface.IsOneway() && !method.IsOneway()) {
246 b->AddLiteral(StringPrintf("%s reply", kAndroidParcelLiteral));
247 }
248
Christopher Wiley36570f42015-10-08 17:20:11 -0700249 // And declare the status variable we need for error handling.
250 b->AddLiteral(StringPrintf("%s status", kAndroidStatusLiteral));
251
252 // Serialization looks roughly like:
253 // status = data.WriteInt32(in_param_name);
254 // if (status != android::OK) { return status; }
255 for (const AidlArgument* a : method.GetInArguments()) {
Casey Dahlinb0966612015-10-19 16:35:26 -0700256 string method =
257 types.Find(a->GetType().GetName())
258 ->WriteToParcelMethod(a->GetType().IsArray());
259
Christopher Wiley36570f42015-10-08 17:20:11 -0700260 string var_name = ((a->IsOut()) ? "*" : "") + a->GetName();
261 b->AddStatement(new Assignment(
262 "status",
263 new MethodCall("data." + method, ArgList(var_name))));
264 b->AddLiteral(kStatusOkOrReturnLiteral, false /* no semicolon */);
265 }
266
267 // Invoke the transaction on the remote binder and confirm status.
268 string transaction_code = StringPrintf(
269 "%s::%s", i_name.c_str(), UpperCase(method.GetName()).c_str());
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700270
271 vector<string> args = {transaction_code, "data", "&reply"};
272
273 if (interface.IsOneway() || method.IsOneway()) {
274 args.push_back("android::IBinder::FLAG_ONEWAY");
275 }
276
277 // Type checking should guarantee that nothing below emits code until "return
278 // status" if we are a oneway method, so no more fear of accessing reply.
279
Christopher Wiley36570f42015-10-08 17:20:11 -0700280 b->AddStatement(new Assignment(
281 "status",
282 new MethodCall("remote()->transact",
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700283 ArgList(args))));
Christopher Wiley36570f42015-10-08 17:20:11 -0700284 b->AddLiteral(kStatusOkOrReturnLiteral, false /* no semicolon */);
285
286 // If the method is expected to return something, read it first by convention.
287 const Type* return_type = types.Find(method.GetType().GetName());
288 if (return_type != types.VoidType()) {
Casey Dahlinb0966612015-10-19 16:35:26 -0700289 string method = return_type->ReadFromParcelMethod(false);
Christopher Wiley36570f42015-10-08 17:20:11 -0700290 b->AddStatement(new Assignment(
291 "status",
292 new MethodCall("reply." + method, ArgList(kReturnVarName))));
293 b->AddLiteral(kStatusOkOrReturnLiteral, false /* no semicolon */);
294 }
295
296 for (const AidlArgument* a : method.GetOutArguments()) {
297 // Deserialization looks roughly like:
298 // status = reply.ReadInt32(out_param_name);
299 // if (status != android::OK) { return status; }
Casey Dahlinb0966612015-10-19 16:35:26 -0700300 string method =
301 types.Find(a->GetType().GetName())
302 ->ReadFromParcelMethod(a->GetType().IsArray());
303
Christopher Wiley36570f42015-10-08 17:20:11 -0700304 b->AddStatement(new Assignment(
305 "status",
306 new MethodCall("reply." + method, ArgList(a->GetName()))));
307 b->AddLiteral(kStatusOkOrReturnLiteral, false /* no semicolon */);
308 }
309
310 b->AddLiteral("return status");
311
312 return unique_ptr<Declaration>(ret.release());
313}
314
315} // namespace
316
Christopher Wileye3550c62015-09-29 13:26:10 -0700317unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
Christopher Wiley36570f42015-10-08 17:20:11 -0700318 const AidlInterface& interface) {
Christopher Wiley054afbd2015-10-16 17:08:43 -0700319 vector<string> include_list = {
320 HeaderFile(interface, ClassNames::CLIENT, false),
321 kParcelHeader
322 };
Christopher Wiley36570f42015-10-08 17:20:11 -0700323 vector<unique_ptr<Declaration>> file_decls;
324
325 // The constructor just passes the IBinder instance up to the super
326 // class.
327 file_decls.push_back(unique_ptr<Declaration>{new ConstructorImpl{
Christopher Wiley054afbd2015-10-16 17:08:43 -0700328 ClassName(interface, ClassNames::CLIENT),
Christopher Wiley36570f42015-10-08 17:20:11 -0700329 ArgList{"const android::sp<android::IBinder>& impl"},
330 { "BpInterface<IPingResponder>(impl)" }}});
331
332 // Clients define a method per transaction.
333 for (const auto& method : interface.GetMethods()) {
334 unique_ptr<Declaration> m = DefineClientTransaction(
335 types, interface, *method);
336 if (!m) { return nullptr; }
337 file_decls.push_back(std::move(m));
338 }
339 return unique_ptr<Document>{new CppSource{
340 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700341 NestInNamespaces(std::move(file_decls), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700342}
343
Christopher Wileyad339272015-10-05 19:11:58 -0700344namespace {
345
346bool HandleServerTransaction(const TypeNamespace& types,
347 const AidlMethod& method,
348 StatementBlock* b) {
349 // Declare all the parameters now. In the common case, we expect no errors
350 // in serialization.
351 for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
352 if (!DeclareLocalVariable(types, *a, b)) { return false; }
353 }
354
355 // Declare a variable to hold the return value.
356 const Type* return_type = types.Find(method.GetType().GetName());
357 if (return_type != types.VoidType()) {
358 b->AddLiteral(StringPrintf(
Casey Dahlinb0966612015-10-19 16:35:26 -0700359 "%s %s", return_type->CppType(false /* not array */).c_str(),
360 kReturnVarName));
Christopher Wileyad339272015-10-05 19:11:58 -0700361 }
362
Christopher Wileyad339272015-10-05 19:11:58 -0700363 // Deserialize each "in" parameter to the transaction.
364 for (const AidlArgument* a : method.GetInArguments()) {
365 // Deserialization looks roughly like:
366 // status = data.ReadInt32(&in_param_name);
367 // if (status != android::OK) { break; }
368 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlinb0966612015-10-19 16:35:26 -0700369 string readMethod = type->ReadFromParcelMethod(a->GetType().IsArray());
370
Christopher Wileyad339272015-10-05 19:11:58 -0700371 b->AddStatement(new Assignment{
372 "status",
Casey Dahlinb0966612015-10-19 16:35:26 -0700373 new MethodCall{"data." + readMethod,
Christopher Wileyad339272015-10-05 19:11:58 -0700374 "&" + BuildVarName(*a)}});
375 b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
376 }
377
378 // Call the actual method. This is implemented by the subclass.
379 b->AddStatement(new Assignment{
380 "status", new MethodCall{
381 method.GetName(),
Christopher Wileyade4b452015-10-10 11:06:03 -0700382 BuildArgList(types, method, false /* not for method decl */)}});
Christopher Wileyad339272015-10-05 19:11:58 -0700383 b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
384
Casey Dahlinb0966612015-10-19 16:35:26 -0700385 string writeMethod =
386 return_type->WriteToParcelMethod(method.GetType().IsArray());
387
Christopher Wiley36570f42015-10-08 17:20:11 -0700388 // If we have a return value, write it first.
389 if (return_type != types.VoidType()) {
Casey Dahlinb0966612015-10-19 16:35:26 -0700390 string method = "reply->" + writeMethod;
Christopher Wiley36570f42015-10-08 17:20:11 -0700391 b->AddStatement(new Assignment{
392 "status", new MethodCall{method, ArgList{kReturnVarName}}});
393 b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
394 }
395
Christopher Wileyad339272015-10-05 19:11:58 -0700396 // Write each out parameter to the reply parcel.
397 for (const AidlArgument* a : method.GetOutArguments()) {
398 // Serialization looks roughly like:
399 // status = data.WriteInt32(out_param_name);
400 // if (status != android::OK) { break; }
401 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlinb0966612015-10-19 16:35:26 -0700402 string writeMethod = type->WriteToParcelMethod(a->GetType().IsArray());
403
Christopher Wileyad339272015-10-05 19:11:58 -0700404 b->AddStatement(new Assignment{
405 "status",
Casey Dahlinb0966612015-10-19 16:35:26 -0700406 new MethodCall{"reply->" + writeMethod,
Christopher Wileyad339272015-10-05 19:11:58 -0700407 BuildVarName(*a)}});
408 b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
409 }
410
411 return true;
412}
413
414} // namespace
415
Christopher Wileye3550c62015-09-29 13:26:10 -0700416unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700417 const AidlInterface& interface) {
418 const string bn_name = ClassName(interface, ClassNames::SERVER);
419 vector<string> include_list{
420 HeaderFile(interface, ClassNames::SERVER, false),
421 kParcelHeader
422 };
Christopher Wileyad339272015-10-05 19:11:58 -0700423 unique_ptr<MethodImpl> on_transact{new MethodImpl{
424 kAndroidStatusLiteral, bn_name, "onTransact",
Christopher Wileyade4b452015-10-10 11:06:03 -0700425 ArgList{{"uint32_t code",
Christopher Wiley36570f42015-10-08 17:20:11 -0700426 StringPrintf("const %s& data", kAndroidParcelLiteral),
427 StringPrintf("%s* reply", kAndroidParcelLiteral),
428 "uint32_t flags"}}
429 }};
Christopher Wileyad339272015-10-05 19:11:58 -0700430
Christopher Wiley05f4f892015-10-14 13:30:43 -0700431 // Declare the status variable
432 on_transact->GetStatementBlock()->AddLiteral(
433 StringPrintf("%s status", kAndroidStatusLiteral));
434
Christopher Wileyad339272015-10-05 19:11:58 -0700435 // Add the all important switch statement, but retain a pointer to it.
436 SwitchStatement* s = new SwitchStatement{"code"};
Christopher Wileyf9688b02015-10-08 17:17:50 -0700437 on_transact->GetStatementBlock()->AddStatement(s);
Christopher Wileyad339272015-10-05 19:11:58 -0700438
439 // The switch statement has a case statement for each transaction code.
Christopher Wiley054afbd2015-10-16 17:08:43 -0700440 for (const auto& method : interface.GetMethods()) {
Christopher Wileyad339272015-10-05 19:11:58 -0700441 StatementBlock* b = s->AddCase("Call::" + UpperCase(method->GetName()));
442 if (!b) { return nullptr; }
443
444 if (!HandleServerTransaction(types, *method, b)) { return nullptr; }
445 }
446
447 // The switch statement has a default case which defers to the super class.
448 // The superclass handles a few pre-defined transactions.
449 StatementBlock* b = s->AddCase("");
450 b->AddLiteral(
451 "status = android::BBinder::onTransact(code, data, reply, flags)");
452
453 // Finally, the server's onTransact method just returns a status code.
Christopher Wileyf9688b02015-10-08 17:17:50 -0700454 on_transact->GetStatementBlock()->AddLiteral("return status");
Christopher Wileyad339272015-10-05 19:11:58 -0700455
456 return unique_ptr<Document>{new CppSource{
457 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700458 NestInNamespaces(std::move(on_transact), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700459}
460
Christopher Wileyf59c4992015-10-08 13:12:44 -0700461unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& /* types */,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700462 const AidlInterface& interface) {
463 vector<string> include_list{
464 HeaderFile(interface, ClassNames::INTERFACE, false),
465 HeaderFile(interface, ClassNames::CLIENT, false),
466 };
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700467
Christopher Wiley054afbd2015-10-16 17:08:43 -0700468 string fq_name = ClassName(interface, ClassNames::INTERFACE);
469 if (!interface.GetPackage().empty()) {
470 fq_name = interface.GetPackage() + "." + fq_name;
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700471 }
472
473 unique_ptr<ConstructorDecl> meta_if{new ConstructorDecl{
474 "IMPLEMENT_META_INTERFACE",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700475 ArgList{vector<string>{ClassName(interface, ClassNames::BASE),
Christopher Wileyade4b452015-10-10 11:06:03 -0700476 '"' + fq_name + '"'}}}};
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700477
478 return unique_ptr<Document>{new CppSource{
479 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700480 NestInNamespaces(std::move(meta_if), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700481}
482
Christopher Wileye3550c62015-09-29 13:26:10 -0700483unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700484 const AidlInterface& interface) {
485 const string i_name = ClassName(interface, ClassNames::INTERFACE);
486 const string bp_name = ClassName(interface, ClassNames::CLIENT);
Casey Dahlina834dd42015-09-23 11:52:15 -0700487
Christopher Wileyb23149d2015-10-14 13:52:21 -0700488 unique_ptr<ConstructorDecl> constructor{new ConstructorDecl{
489 bp_name,
490 ArgList{"const android::sp<android::IBinder>& impl"},
491 ConstructorDecl::IS_EXPLICIT
492 }};
493 unique_ptr<ConstructorDecl> destructor{new ConstructorDecl{
494 "~" + bp_name,
495 ArgList{},
496 ConstructorDecl::IS_VIRTUAL | ConstructorDecl::IS_DEFAULT}};
Casey Dahlina834dd42015-09-23 11:52:15 -0700497
Christopher Wileyf944e792015-09-29 10:00:46 -0700498 vector<unique_ptr<Declaration>> publics;
Casey Dahlina834dd42015-09-23 11:52:15 -0700499 publics.push_back(std::move(constructor));
500 publics.push_back(std::move(destructor));
501
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700502 for (const auto& method: interface.GetMethods()) {
Christopher Wiley36570f42015-10-08 17:20:11 -0700503 publics.push_back(BuildMethodDecl(*method, types, false));
Casey Dahlina834dd42015-09-23 11:52:15 -0700504 }
505
Christopher Wileyf944e792015-09-29 10:00:46 -0700506 unique_ptr<ClassDecl> bp_class{
507 new ClassDecl{bp_name,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700508 "android::BpInterface<" + i_name + ">",
Christopher Wileyf944e792015-09-29 10:00:46 -0700509 std::move(publics),
510 {}
Casey Dahlina834dd42015-09-23 11:52:15 -0700511 }};
512
Christopher Wiley0c732db2015-09-29 14:36:44 -0700513 return unique_ptr<Document>{new CppHeader{
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700514 BuildHeaderGuard(interface, ClassNames::CLIENT),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700515 {kIBinderHeader,
516 kIInterfaceHeader,
517 "utils/Errors.h",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700518 HeaderFile(interface, ClassNames::INTERFACE, false)},
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700519 NestInNamespaces(std::move(bp_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700520}
521
Christopher Wileyf59c4992015-10-08 13:12:44 -0700522unique_ptr<Document> BuildServerHeader(const TypeNamespace& /* types */,
Christopher Wileyfd51d602015-10-14 13:04:48 -0700523 const AidlInterface& interface) {
524 const string i_name = ClassName(interface, ClassNames::INTERFACE);
525 const string bn_name = ClassName(interface, ClassNames::SERVER);
Casey Dahlin082f1d12015-09-21 14:06:25 -0700526
Christopher Wileyfd51d602015-10-14 13:04:48 -0700527 unique_ptr<Declaration> on_transact{new MethodDecl{
Christopher Wileyade4b452015-10-10 11:06:03 -0700528 kAndroidStatusLiteral, "onTransact",
529 ArgList{{"uint32_t code",
Christopher Wiley36570f42015-10-08 17:20:11 -0700530 StringPrintf("const %s& data", kAndroidParcelLiteral),
531 StringPrintf("%s* reply", kAndroidParcelLiteral),
Christopher Wileyfd51d602015-10-14 13:04:48 -0700532 "uint32_t flags = 0"}},
533 MethodDecl::IS_OVERRIDE
534 }};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700535
Christopher Wileyf944e792015-09-29 10:00:46 -0700536 std::vector<unique_ptr<Declaration>> publics;
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700537 publics.push_back(std::move(on_transact));
538
Christopher Wileyf944e792015-09-29 10:00:46 -0700539 unique_ptr<ClassDecl> bn_class{
540 new ClassDecl{bn_name,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700541 "android::BnInterface<" + i_name + ">",
Christopher Wileyf944e792015-09-29 10:00:46 -0700542 std::move(publics),
543 {}
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700544 }};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700545
Christopher Wiley0c732db2015-09-29 14:36:44 -0700546 return unique_ptr<Document>{new CppHeader{
Christopher Wileyfd51d602015-10-14 13:04:48 -0700547 BuildHeaderGuard(interface, ClassNames::SERVER),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700548 {"binder/IInterface.h",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700549 HeaderFile(interface, ClassNames::INTERFACE, false)},
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700550 NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700551}
552
Christopher Wileye3550c62015-09-29 13:26:10 -0700553unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700554 const AidlInterface& interface) {
Casey Dahlince776cf2015-10-15 18:45:54 -0700555 set<string> includes = { kIBinderHeader, kIInterfaceHeader };
556
557 for (const auto& method : interface.GetMethods()) {
558 for (const auto& argument : method->GetArguments()) {
559 const Type* type = types.Find(argument->GetType().GetName());
560 const std::string& header = type->Header();
561 if (! header.empty())
562 includes.insert(header);
Casey Dahlinb0966612015-10-19 16:35:26 -0700563 if (argument->GetType().IsArray())
564 includes.insert("vector");
Casey Dahlince776cf2015-10-15 18:45:54 -0700565 }
566
567 const Type* type = types.Find(method->GetType().GetName());
568 const std::string& header = type->Header();
569 if (! header.empty())
570 includes.insert(header);
571 }
572
Christopher Wiley0c732db2015-09-29 14:36:44 -0700573 unique_ptr<ClassDecl> if_class{
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700574 new ClassDecl{ClassName(interface, ClassNames::INTERFACE),
575 "android::IInterface"}};
Christopher Wileyade4b452015-10-10 11:06:03 -0700576 if_class->AddPublic(unique_ptr<Declaration>{new ConstructorDecl{
577 "DECLARE_META_INTERFACE",
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700578 ArgList{vector<string>{ClassName(interface, ClassNames::BASE)}}}});
Christopher Wiley0c732db2015-09-29 14:36:44 -0700579
580 unique_ptr<Enum> call_enum{new Enum{"Call"}};
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700581 for (const auto& method : interface.GetMethods()) {
582 // Each method gets an enum entry and pure virtual declaration.
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700583 if_class->AddPublic(BuildMethodDecl(*method, types, true));
Christopher Wiley0c732db2015-09-29 14:36:44 -0700584 call_enum->AddValue(
Casey Dahlinf4a93112015-10-05 16:58:09 -0700585 UpperCase(method->GetName()),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700586 StringPrintf("android::IBinder::FIRST_CALL_TRANSACTION + %d",
Casey Dahlinf4a93112015-10-05 16:58:09 -0700587 method->GetId()));
Christopher Wiley0c732db2015-09-29 14:36:44 -0700588 }
589 if_class->AddPublic(std::move(call_enum));
590
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700591 return unique_ptr<Document>{new CppHeader{
592 BuildHeaderGuard(interface, ClassNames::INTERFACE),
Casey Dahlince776cf2015-10-15 18:45:54 -0700593 vector<string>(includes.begin(), includes.end()),
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700594 NestInNamespaces(std::move(if_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700595}
596
Christopher Wiley054afbd2015-10-16 17:08:43 -0700597bool WriteHeader(const CppOptions& options,
598 const TypeNamespace& types,
599 const AidlInterface& interface,
600 const IoDelegate& io_delegate,
601 ClassNames header_type) {
602 unique_ptr<Document> header;
603 switch (header_type) {
604 case ClassNames::INTERFACE:
605 header = BuildInterfaceHeader(types, interface);
606 break;
607 case ClassNames::CLIENT:
608 header = BuildClientHeader(types, interface);
609 break;
610 case ClassNames::SERVER:
611 header = BuildServerHeader(types, interface);
612 break;
613 default:
614 LOG(FATAL) << "aidl internal error";
615 }
616 if (!header) {
617 LOG(ERROR) << "aidl internal error: Failed to generate header.";
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700618 return false;
619 }
Christopher Wiley054afbd2015-10-16 17:08:43 -0700620
621 // TODO(wiley): b/25026025 error checking for file I/O
622 header->Write(io_delegate.GetCodeWriter(
623 options.OutputHeaderDir() + OS_PATH_SEPARATOR +
624 HeaderFile(interface, header_type)).get());
625
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700626 return true;
627}
628
Casey Dahlina834dd42015-09-23 11:52:15 -0700629} // namespace internals
630
631using namespace internals;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700632
Christopher Wileye3550c62015-09-29 13:26:10 -0700633bool GenerateCpp(const CppOptions& options,
634 const TypeNamespace& types,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700635 const AidlInterface& interface,
636 const IoDelegate& io_delegate) {
637 auto interface_src = BuildInterfaceSource(types, interface);
638 auto client_src = BuildClientSource(types, interface);
639 auto server_src = BuildServerSource(types, interface);
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700640
Christopher Wiley054afbd2015-10-16 17:08:43 -0700641 if (!interface_src || !client_src || !server_src) {
642 return false;
643 }
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700644
Christopher Wiley054afbd2015-10-16 17:08:43 -0700645 if (!io_delegate.CreatedNestedDirs(options.OutputHeaderDir(),
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700646 interface.GetSplitPackage())) {
Christopher Wiley054afbd2015-10-16 17:08:43 -0700647 LOG(ERROR) << "Failed to create directory structure for headers.";
648 return false;
649 }
650
651 if (!WriteHeader(options, types, interface, io_delegate,
652 ClassNames::INTERFACE) ||
653 !WriteHeader(options, types, interface, io_delegate,
654 ClassNames::CLIENT) ||
655 !WriteHeader(options, types, interface, io_delegate,
656 ClassNames::SERVER)) {
657 return false;
658 }
659
660 // TODO(wiley): b/25026025 error checking for file I/O.
661 // If it fails, we should remove all the partial results.
662 unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(
663 options.OutputCppFilePath());
664 interface_src->Write(writer.get());
665 client_src->Write(writer.get());
666 server_src->Write(writer.get());
667
668 return true;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700669}
670
Christopher Wileyf944e792015-09-29 10:00:46 -0700671} // namespace cpp
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700672} // namespace aidl
Christopher Wileyf944e792015-09-29 10:00:46 -0700673} // namespace android