blob: 8bb3f95de8bca2e63760160aac3e3164e3f8ce59 [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 kReturnVarName[] = "_aidl_return";
Christopher Wiley0c732db2015-09-29 14:36:44 -070047const char kAndroidStatusLiteral[] = "android::status_t";
Christopher Wiley36570f42015-10-08 17:20:11 -070048const char kAndroidParcelLiteral[] = "android::Parcel";
Christopher Wiley0c732db2015-09-29 14:36:44 -070049const char kIBinderHeader[] = "binder/IBinder.h";
50const char kIInterfaceHeader[] = "binder/IInterface.h";
Christopher Wileyad339272015-10-05 19:11:58 -070051const char kParcelHeader[] = "binder/Parcel.h";
Casey Dahlin082f1d12015-09-21 14:06:25 -070052
Christopher Wiley0eb903e2015-10-20 17:07:08 -070053unique_ptr<AstNode> BreakOnStatusNotOk() {
54 IfStatement* ret = new IfStatement(new Comparison(
55 new LiteralExpression("status"), "!=",
56 new LiteralExpression("android::OK")));
57 ret->OnTrue()->AddLiteral("break");
58 return unique_ptr<AstNode>(ret);
59}
60
61unique_ptr<AstNode> ReturnOnStatusNotOk() {
62 IfStatement* ret = new IfStatement(new Comparison(
63 new LiteralExpression("status"), "!=",
64 new LiteralExpression("android::OK")));
65 ret->OnTrue()->AddLiteral("return status");
66 return unique_ptr<AstNode>(ret);
67}
68
Christopher Wiley0c732db2015-09-29 14:36:44 -070069string UpperCase(const std::string& s) {
70 string result = s;
71 for (char& c : result)
72 c = toupper(c);
73 return result;
Casey Dahlina834dd42015-09-23 11:52:15 -070074}
Casey Dahlin082f1d12015-09-21 14:06:25 -070075
Christopher Wileyad339272015-10-05 19:11:58 -070076string BuildVarName(const AidlArgument& a) {
77 string prefix = "out_";
78 if (a.GetDirection() & AidlArgument::IN_DIR) {
79 prefix = "in_";
Christopher Wileye3550c62015-09-29 13:26:10 -070080 }
Christopher Wileyad339272015-10-05 19:11:58 -070081 return prefix + a.GetName();
82}
83
Christopher Wileyade4b452015-10-10 11:06:03 -070084ArgList BuildArgList(const TypeNamespace& types,
85 const AidlMethod& method,
86 bool for_declaration) {
Christopher Wileyad339272015-10-05 19:11:58 -070087 // Build up the argument list for the server method call.
88 vector<string> method_arguments;
89 for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
90 string literal;
91 if (for_declaration) {
92 // Method declarations need types, pointers to out params, and variable
93 // names that match the .aidl specification.
94 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlince776cf2015-10-15 18:45:54 -070095
Casey Dahlinb0966612015-10-19 16:35:26 -070096 literal = type->CppType(a->GetType().IsArray());
97
Christopher Wileyb8e49a42015-10-27 12:55:18 -070098 if (a->IsOut()) {
99 literal = literal + "*";
100 } else {
101 // We pass in parameters that are not primitives by const reference.
102 // Arrays of primitives are not primitives.
103 if (!type->IsCppPrimitive() || a->GetType().IsArray()) {
104 literal = "const " + literal + "&";
105 }
106 }
Casey Dahlinb0966612015-10-19 16:35:26 -0700107
108 literal += " " + a->GetName();
Christopher Wileyad339272015-10-05 19:11:58 -0700109 } else {
110 if (a->IsOut()) { literal = "&"; }
111 literal += BuildVarName(*a);
112 }
113 method_arguments.push_back(literal);
114 }
115
116 const Type* return_type = types.Find(method.GetType().GetName());
Casey Dahlince776cf2015-10-15 18:45:54 -0700117
Christopher Wileyad339272015-10-05 19:11:58 -0700118 if (return_type != types.VoidType()) {
Christopher Wileyade4b452015-10-10 11:06:03 -0700119 string literal;
Christopher Wileyad339272015-10-05 19:11:58 -0700120 if (for_declaration) {
Christopher Wileyade4b452015-10-10 11:06:03 -0700121 literal = StringPrintf(
Casey Dahlinb0966612015-10-19 16:35:26 -0700122 "%s* %s", return_type->CppType(false /* not array */).c_str(),
123 kReturnVarName);
Christopher Wileyad339272015-10-05 19:11:58 -0700124 } else {
Christopher Wileyade4b452015-10-10 11:06:03 -0700125 literal = string{"&"} + kReturnVarName;
Christopher Wileyad339272015-10-05 19:11:58 -0700126 }
Christopher Wileyade4b452015-10-10 11:06:03 -0700127 method_arguments.push_back(literal);
Christopher Wileyad339272015-10-05 19:11:58 -0700128 }
129
Christopher Wileyade4b452015-10-10 11:06:03 -0700130 return ArgList(method_arguments);
Casey Dahlina834dd42015-09-23 11:52:15 -0700131}
132
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700133unique_ptr<Declaration> BuildMethodDecl(const AidlMethod& method,
Christopher Wiley0c732db2015-09-29 14:36:44 -0700134 const TypeNamespace& types,
135 bool for_interface) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700136 uint32_t modifiers = 0;
137 if (for_interface) {
138 modifiers |= MethodDecl::IS_VIRTUAL;
139 modifiers |= MethodDecl::IS_PURE_VIRTUAL;
140 } else {
141 modifiers |= MethodDecl::IS_OVERRIDE;
142 }
143
144 return unique_ptr<Declaration>{
145 new MethodDecl{kAndroidStatusLiteral,
Casey Dahlinf4a93112015-10-05 16:58:09 -0700146 method.GetName(),
Christopher Wileyad339272015-10-05 19:11:58 -0700147 BuildArgList(types, method, true /* for method decl */),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700148 modifiers}};
149}
150
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700151unique_ptr<CppNamespace> NestInNamespaces(
152 vector<unique_ptr<Declaration>> decls,
153 const vector<string>& package) {
154 if (package.empty()) {
155 // We should also be checking this before we get this far, but do it again
156 // for the sake of unit tests and meaningful errors.
157 LOG(FATAL) << "C++ generation requires a package declaration "
158 "for namespacing";
159 }
160 auto it = package.crbegin(); // Iterate over the namespaces inner to outer
161 unique_ptr<CppNamespace> inner{new CppNamespace{*it, std::move(decls)}};
162 ++it;
163 for (; it != package.crend(); ++it) {
164 inner.reset(new CppNamespace{*it, std::move(inner)});
165 }
166 return inner;
Christopher Wiley0c732db2015-09-29 14:36:44 -0700167}
168
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700169unique_ptr<CppNamespace> NestInNamespaces(unique_ptr<Declaration> decl,
170 const vector<string>& package) {
171 vector<unique_ptr<Declaration>> decls;
172 decls.push_back(std::move(decl));
173 return NestInNamespaces(std::move(decls), package);
Christopher Wiley36570f42015-10-08 17:20:11 -0700174}
175
Christopher Wileyad339272015-10-05 19:11:58 -0700176bool DeclareLocalVariable(const TypeNamespace& types, const AidlArgument& a,
177 StatementBlock* b) {
178 const Type* cpp_type = types.Find(a.GetType().GetName());
179 if (!cpp_type) { return false; }
180
Casey Dahlinb0966612015-10-19 16:35:26 -0700181 string type = cpp_type->CppType(a.GetType().IsArray());
182
183 b->AddLiteral(type + " " + BuildVarName(a));
Christopher Wileyad339272015-10-05 19:11:58 -0700184 return true;
185}
186
Christopher Wiley0c732db2015-09-29 14:36:44 -0700187enum class ClassNames { BASE, CLIENT, SERVER, INTERFACE };
188
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700189string ClassName(const AidlInterface& interface, ClassNames type) {
Casey Dahlinfb7da2e2015-10-08 17:26:09 -0700190 string c_name = interface.GetName();
Christopher Wiley0c732db2015-09-29 14:36:44 -0700191
192 if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
193 c_name = c_name.substr(1);
194
195 switch (type) {
196 case ClassNames::CLIENT:
197 c_name = "Bp" + c_name;
198 break;
199 case ClassNames::SERVER:
200 c_name = "Bn" + c_name;
201 break;
202 case ClassNames::INTERFACE:
203 c_name = "I" + c_name;
204 break;
205 case ClassNames::BASE:
206 break;
207 }
208 return c_name;
209}
210
Christopher Wiley054afbd2015-10-16 17:08:43 -0700211string HeaderFile(const AidlInterface& interface,
212 ClassNames class_type,
213 bool use_os_sep = true) {
214 string file_path = interface.GetPackage();
215 for (char& c: file_path) {
216 if (c == '.') {
217 c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
218 }
219 }
220 if (!file_path.empty()) {
221 file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
222 }
223 file_path += ClassName(interface, class_type);
224 file_path += ".h";
225
226 return file_path;
227}
228
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700229string BuildHeaderGuard(const AidlInterface& interface,
230 ClassNames header_type) {
231 string class_name = ClassName(interface, header_type);
232 for (size_t i = 1; i < class_name.size(); ++i) {
233 if (isupper(class_name[i])) {
234 class_name.insert(i, "_");
235 ++i;
236 }
237 }
238 string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_",
239 interface.GetPackage().c_str(),
240 class_name.c_str());
241 for (char& c : ret) {
242 if (c == '.') {
243 c = '_';
244 }
245 c = toupper(c);
246 }
247 return ret;
248}
Christopher Wiley36570f42015-10-08 17:20:11 -0700249
250unique_ptr<Declaration> DefineClientTransaction(const TypeNamespace& types,
251 const AidlInterface& interface,
252 const AidlMethod& method) {
253 const string i_name = ClassName(interface, ClassNames::INTERFACE);
254 const string bp_name = ClassName(interface, ClassNames::CLIENT);
255 unique_ptr<MethodImpl> ret{new MethodImpl{
256 kAndroidStatusLiteral, bp_name, method.GetName(),
257 ArgList{BuildArgList(types, method, true /* for method decl */)}}};
258 StatementBlock* b = ret->GetStatementBlock();
259
260 // Declare parcels to hold our query and the response.
261 b->AddLiteral(StringPrintf("%s data", kAndroidParcelLiteral));
Christopher Wiley1227d612015-10-26 16:59:20 -0700262 // Even if we're oneway, the transact method still takes a parcel.
263 b->AddLiteral(StringPrintf("%s reply", kAndroidParcelLiteral));
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700264
Christopher Wiley36570f42015-10-08 17:20:11 -0700265 // And declare the status variable we need for error handling.
266 b->AddLiteral(StringPrintf("%s status", kAndroidStatusLiteral));
267
Christopher Wiley8993cb52015-10-21 09:53:24 -0700268 // Add the name of the interface we're hoping to call.
269 b->AddStatement(new Assignment(
270 "status",
271 new MethodCall("data.writeInterfaceToken", "getInterfaceDescriptor()")));
272 b->AddStatement(ReturnOnStatusNotOk());
273
Christopher Wiley36570f42015-10-08 17:20:11 -0700274 // Serialization looks roughly like:
275 // status = data.WriteInt32(in_param_name);
276 // if (status != android::OK) { return status; }
277 for (const AidlArgument* a : method.GetInArguments()) {
Casey Dahlinb0966612015-10-19 16:35:26 -0700278 string method =
279 types.Find(a->GetType().GetName())
280 ->WriteToParcelMethod(a->GetType().IsArray());
281
Christopher Wiley36570f42015-10-08 17:20:11 -0700282 string var_name = ((a->IsOut()) ? "*" : "") + a->GetName();
283 b->AddStatement(new Assignment(
284 "status",
285 new MethodCall("data." + method, ArgList(var_name))));
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700286 b->AddStatement(ReturnOnStatusNotOk());
Christopher Wiley36570f42015-10-08 17:20:11 -0700287 }
288
289 // Invoke the transaction on the remote binder and confirm status.
290 string transaction_code = StringPrintf(
291 "%s::%s", i_name.c_str(), UpperCase(method.GetName()).c_str());
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700292
293 vector<string> args = {transaction_code, "data", "&reply"};
294
295 if (interface.IsOneway() || method.IsOneway()) {
296 args.push_back("android::IBinder::FLAG_ONEWAY");
297 }
298
Christopher Wiley36570f42015-10-08 17:20:11 -0700299 b->AddStatement(new Assignment(
300 "status",
301 new MethodCall("remote()->transact",
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700302 ArgList(args))));
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700303 b->AddStatement(ReturnOnStatusNotOk());
Christopher Wiley36570f42015-10-08 17:20:11 -0700304
Christopher Wiley1227d612015-10-26 16:59:20 -0700305 if (!interface.IsOneway() && !method.IsOneway()) {
306 // Strip off the exception header and fail if we see a remote exception.
307 // if (reply.readExceptionCode()) {
308 // status = android::FAILED_TRANSACTION;
309 // return status;
310 // }
311 IfStatement* exception_check = new IfStatement(
312 new LiteralExpression("reply.readExceptionCode()"));
313 b->AddStatement(exception_check);
314 exception_check->OnTrue()->AddStatement(
315 new Assignment("status", "android::FAILED_TRANSACTION"));
316 exception_check->OnTrue()->AddLiteral("return status");
317 }
318
319 // Type checking should guarantee that nothing below emits code until "return
320 // status" if we are a oneway method, so no more fear of accessing reply.
Christopher Wiley2aaeda82015-10-19 15:16:49 -0700321
Christopher Wiley36570f42015-10-08 17:20:11 -0700322 // If the method is expected to return something, read it first by convention.
323 const Type* return_type = types.Find(method.GetType().GetName());
324 if (return_type != types.VoidType()) {
Casey Dahlinb0966612015-10-19 16:35:26 -0700325 string method = return_type->ReadFromParcelMethod(false);
Christopher Wiley36570f42015-10-08 17:20:11 -0700326 b->AddStatement(new Assignment(
327 "status",
328 new MethodCall("reply." + method, ArgList(kReturnVarName))));
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700329 b->AddStatement(ReturnOnStatusNotOk());
Christopher Wiley36570f42015-10-08 17:20:11 -0700330 }
331
332 for (const AidlArgument* a : method.GetOutArguments()) {
333 // Deserialization looks roughly like:
334 // status = reply.ReadInt32(out_param_name);
335 // if (status != android::OK) { return status; }
Casey Dahlinb0966612015-10-19 16:35:26 -0700336 string method =
337 types.Find(a->GetType().GetName())
338 ->ReadFromParcelMethod(a->GetType().IsArray());
339
Christopher Wiley36570f42015-10-08 17:20:11 -0700340 b->AddStatement(new Assignment(
341 "status",
342 new MethodCall("reply." + method, ArgList(a->GetName()))));
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700343 b->AddStatement(ReturnOnStatusNotOk());
Christopher Wiley36570f42015-10-08 17:20:11 -0700344 }
345
346 b->AddLiteral("return status");
347
348 return unique_ptr<Declaration>(ret.release());
349}
350
351} // namespace
352
Christopher Wileye3550c62015-09-29 13:26:10 -0700353unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
Christopher Wiley36570f42015-10-08 17:20:11 -0700354 const AidlInterface& interface) {
Christopher Wiley054afbd2015-10-16 17:08:43 -0700355 vector<string> include_list = {
356 HeaderFile(interface, ClassNames::CLIENT, false),
357 kParcelHeader
358 };
Christopher Wiley36570f42015-10-08 17:20:11 -0700359 vector<unique_ptr<Declaration>> file_decls;
360
361 // The constructor just passes the IBinder instance up to the super
362 // class.
Christopher Wiley1db03482015-10-22 11:42:02 -0700363 const string i_name = ClassName(interface, ClassNames::INTERFACE);
Christopher Wiley36570f42015-10-08 17:20:11 -0700364 file_decls.push_back(unique_ptr<Declaration>{new ConstructorImpl{
Christopher Wiley054afbd2015-10-16 17:08:43 -0700365 ClassName(interface, ClassNames::CLIENT),
Christopher Wiley36570f42015-10-08 17:20:11 -0700366 ArgList{"const android::sp<android::IBinder>& impl"},
Christopher Wiley1db03482015-10-22 11:42:02 -0700367 { "BpInterface<" + i_name + ">(impl)" }}});
Christopher Wiley36570f42015-10-08 17:20:11 -0700368
369 // Clients define a method per transaction.
370 for (const auto& method : interface.GetMethods()) {
371 unique_ptr<Declaration> m = DefineClientTransaction(
372 types, interface, *method);
373 if (!m) { return nullptr; }
374 file_decls.push_back(std::move(m));
375 }
376 return unique_ptr<Document>{new CppSource{
377 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700378 NestInNamespaces(std::move(file_decls), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700379}
380
Christopher Wileyad339272015-10-05 19:11:58 -0700381namespace {
382
383bool HandleServerTransaction(const TypeNamespace& types,
384 const AidlMethod& method,
385 StatementBlock* b) {
386 // Declare all the parameters now. In the common case, we expect no errors
387 // in serialization.
388 for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
389 if (!DeclareLocalVariable(types, *a, b)) { return false; }
390 }
391
392 // Declare a variable to hold the return value.
393 const Type* return_type = types.Find(method.GetType().GetName());
394 if (return_type != types.VoidType()) {
395 b->AddLiteral(StringPrintf(
Casey Dahlinb0966612015-10-19 16:35:26 -0700396 "%s %s", return_type->CppType(false /* not array */).c_str(),
397 kReturnVarName));
Christopher Wileyad339272015-10-05 19:11:58 -0700398 }
399
Christopher Wiley8993cb52015-10-21 09:53:24 -0700400 // Check that the client is calling the correct interface.
401 IfStatement* interface_check = new IfStatement(
402 new MethodCall("data.checkInterface", "this"),
403 true /* invert the check */);
404 b->AddStatement(interface_check);
405 interface_check->OnTrue()->AddStatement(
406 new Assignment("status", "android::BAD_TYPE"));
407 interface_check->OnTrue()->AddLiteral("break");
408
Christopher Wileyad339272015-10-05 19:11:58 -0700409 // Deserialize each "in" parameter to the transaction.
410 for (const AidlArgument* a : method.GetInArguments()) {
411 // Deserialization looks roughly like:
412 // status = data.ReadInt32(&in_param_name);
413 // if (status != android::OK) { break; }
414 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlinb0966612015-10-19 16:35:26 -0700415 string readMethod = type->ReadFromParcelMethod(a->GetType().IsArray());
416
Christopher Wileyad339272015-10-05 19:11:58 -0700417 b->AddStatement(new Assignment{
418 "status",
Casey Dahlinb0966612015-10-19 16:35:26 -0700419 new MethodCall{"data." + readMethod,
Christopher Wileyad339272015-10-05 19:11:58 -0700420 "&" + BuildVarName(*a)}});
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700421 b->AddStatement(BreakOnStatusNotOk());
Christopher Wileyad339272015-10-05 19:11:58 -0700422 }
423
424 // Call the actual method. This is implemented by the subclass.
425 b->AddStatement(new Assignment{
426 "status", new MethodCall{
427 method.GetName(),
Christopher Wileyade4b452015-10-10 11:06:03 -0700428 BuildArgList(types, method, false /* not for method decl */)}});
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700429 b->AddStatement(BreakOnStatusNotOk());
Christopher Wileyad339272015-10-05 19:11:58 -0700430
Christopher Wiley2aaeda82015-10-19 15:16:49 -0700431 // Write that we encountered no exceptions during transaction handling.
432 b->AddStatement(new Assignment("status", "reply->writeNoException()"));
433 b->AddStatement(BreakOnStatusNotOk());
Casey Dahlinb0966612015-10-19 16:35:26 -0700434
Christopher Wiley36570f42015-10-08 17:20:11 -0700435 // If we have a return value, write it first.
436 if (return_type != types.VoidType()) {
Christopher Wiley2aaeda82015-10-19 15:16:49 -0700437 string writeMethod =
438 "reply->" +
439 return_type->WriteToParcelMethod(method.GetType().IsArray());
Christopher Wiley36570f42015-10-08 17:20:11 -0700440 b->AddStatement(new Assignment{
Christopher Wiley2aaeda82015-10-19 15:16:49 -0700441 "status", new MethodCall{writeMethod, ArgList{kReturnVarName}}});
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700442 b->AddStatement(BreakOnStatusNotOk());
Christopher Wiley36570f42015-10-08 17:20:11 -0700443 }
444
Christopher Wileyad339272015-10-05 19:11:58 -0700445 // Write each out parameter to the reply parcel.
446 for (const AidlArgument* a : method.GetOutArguments()) {
447 // Serialization looks roughly like:
448 // status = data.WriteInt32(out_param_name);
449 // if (status != android::OK) { break; }
450 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlinb0966612015-10-19 16:35:26 -0700451 string writeMethod = type->WriteToParcelMethod(a->GetType().IsArray());
452
Christopher Wileyad339272015-10-05 19:11:58 -0700453 b->AddStatement(new Assignment{
454 "status",
Casey Dahlinb0966612015-10-19 16:35:26 -0700455 new MethodCall{"reply->" + writeMethod,
Christopher Wileyad339272015-10-05 19:11:58 -0700456 BuildVarName(*a)}});
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700457 b->AddStatement(BreakOnStatusNotOk());
Christopher Wileyad339272015-10-05 19:11:58 -0700458 }
459
460 return true;
461}
462
463} // namespace
464
Christopher Wileye3550c62015-09-29 13:26:10 -0700465unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700466 const AidlInterface& interface) {
467 const string bn_name = ClassName(interface, ClassNames::SERVER);
468 vector<string> include_list{
469 HeaderFile(interface, ClassNames::SERVER, false),
470 kParcelHeader
471 };
Christopher Wileyad339272015-10-05 19:11:58 -0700472 unique_ptr<MethodImpl> on_transact{new MethodImpl{
473 kAndroidStatusLiteral, bn_name, "onTransact",
Christopher Wileyade4b452015-10-10 11:06:03 -0700474 ArgList{{"uint32_t code",
Christopher Wiley36570f42015-10-08 17:20:11 -0700475 StringPrintf("const %s& data", kAndroidParcelLiteral),
476 StringPrintf("%s* reply", kAndroidParcelLiteral),
477 "uint32_t flags"}}
478 }};
Christopher Wileyad339272015-10-05 19:11:58 -0700479
Christopher Wiley05f4f892015-10-14 13:30:43 -0700480 // Declare the status variable
481 on_transact->GetStatementBlock()->AddLiteral(
482 StringPrintf("%s status", kAndroidStatusLiteral));
483
Christopher Wileyad339272015-10-05 19:11:58 -0700484 // Add the all important switch statement, but retain a pointer to it.
485 SwitchStatement* s = new SwitchStatement{"code"};
Christopher Wileyf9688b02015-10-08 17:17:50 -0700486 on_transact->GetStatementBlock()->AddStatement(s);
Christopher Wileyad339272015-10-05 19:11:58 -0700487
488 // The switch statement has a case statement for each transaction code.
Christopher Wiley054afbd2015-10-16 17:08:43 -0700489 for (const auto& method : interface.GetMethods()) {
Christopher Wileyad339272015-10-05 19:11:58 -0700490 StatementBlock* b = s->AddCase("Call::" + UpperCase(method->GetName()));
491 if (!b) { return nullptr; }
492
493 if (!HandleServerTransaction(types, *method, b)) { return nullptr; }
494 }
495
496 // The switch statement has a default case which defers to the super class.
497 // The superclass handles a few pre-defined transactions.
498 StatementBlock* b = s->AddCase("");
499 b->AddLiteral(
500 "status = android::BBinder::onTransact(code, data, reply, flags)");
501
502 // Finally, the server's onTransact method just returns a status code.
Christopher Wileyf9688b02015-10-08 17:17:50 -0700503 on_transact->GetStatementBlock()->AddLiteral("return status");
Christopher Wileyad339272015-10-05 19:11:58 -0700504
505 return unique_ptr<Document>{new CppSource{
506 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700507 NestInNamespaces(std::move(on_transact), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700508}
509
Christopher Wileyf59c4992015-10-08 13:12:44 -0700510unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& /* types */,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700511 const AidlInterface& interface) {
512 vector<string> include_list{
513 HeaderFile(interface, ClassNames::INTERFACE, false),
514 HeaderFile(interface, ClassNames::CLIENT, false),
515 };
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700516
Christopher Wiley054afbd2015-10-16 17:08:43 -0700517 string fq_name = ClassName(interface, ClassNames::INTERFACE);
518 if (!interface.GetPackage().empty()) {
519 fq_name = interface.GetPackage() + "." + fq_name;
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700520 }
521
522 unique_ptr<ConstructorDecl> meta_if{new ConstructorDecl{
523 "IMPLEMENT_META_INTERFACE",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700524 ArgList{vector<string>{ClassName(interface, ClassNames::BASE),
Christopher Wileyade4b452015-10-10 11:06:03 -0700525 '"' + fq_name + '"'}}}};
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700526
527 return unique_ptr<Document>{new CppSource{
528 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700529 NestInNamespaces(std::move(meta_if), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700530}
531
Christopher Wileye3550c62015-09-29 13:26:10 -0700532unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700533 const AidlInterface& interface) {
534 const string i_name = ClassName(interface, ClassNames::INTERFACE);
535 const string bp_name = ClassName(interface, ClassNames::CLIENT);
Casey Dahlina834dd42015-09-23 11:52:15 -0700536
Christopher Wileyb23149d2015-10-14 13:52:21 -0700537 unique_ptr<ConstructorDecl> constructor{new ConstructorDecl{
538 bp_name,
539 ArgList{"const android::sp<android::IBinder>& impl"},
540 ConstructorDecl::IS_EXPLICIT
541 }};
542 unique_ptr<ConstructorDecl> destructor{new ConstructorDecl{
543 "~" + bp_name,
544 ArgList{},
545 ConstructorDecl::IS_VIRTUAL | ConstructorDecl::IS_DEFAULT}};
Casey Dahlina834dd42015-09-23 11:52:15 -0700546
Christopher Wileyf944e792015-09-29 10:00:46 -0700547 vector<unique_ptr<Declaration>> publics;
Casey Dahlina834dd42015-09-23 11:52:15 -0700548 publics.push_back(std::move(constructor));
549 publics.push_back(std::move(destructor));
550
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700551 for (const auto& method: interface.GetMethods()) {
Christopher Wiley36570f42015-10-08 17:20:11 -0700552 publics.push_back(BuildMethodDecl(*method, types, false));
Casey Dahlina834dd42015-09-23 11:52:15 -0700553 }
554
Christopher Wileyf944e792015-09-29 10:00:46 -0700555 unique_ptr<ClassDecl> bp_class{
556 new ClassDecl{bp_name,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700557 "android::BpInterface<" + i_name + ">",
Christopher Wileyf944e792015-09-29 10:00:46 -0700558 std::move(publics),
559 {}
Casey Dahlina834dd42015-09-23 11:52:15 -0700560 }};
561
Christopher Wiley0c732db2015-09-29 14:36:44 -0700562 return unique_ptr<Document>{new CppHeader{
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700563 BuildHeaderGuard(interface, ClassNames::CLIENT),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700564 {kIBinderHeader,
565 kIInterfaceHeader,
566 "utils/Errors.h",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700567 HeaderFile(interface, ClassNames::INTERFACE, false)},
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700568 NestInNamespaces(std::move(bp_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700569}
570
Christopher Wileyf59c4992015-10-08 13:12:44 -0700571unique_ptr<Document> BuildServerHeader(const TypeNamespace& /* types */,
Christopher Wileyfd51d602015-10-14 13:04:48 -0700572 const AidlInterface& interface) {
573 const string i_name = ClassName(interface, ClassNames::INTERFACE);
574 const string bn_name = ClassName(interface, ClassNames::SERVER);
Casey Dahlin082f1d12015-09-21 14:06:25 -0700575
Christopher Wileyfd51d602015-10-14 13:04:48 -0700576 unique_ptr<Declaration> on_transact{new MethodDecl{
Christopher Wileyade4b452015-10-10 11:06:03 -0700577 kAndroidStatusLiteral, "onTransact",
578 ArgList{{"uint32_t code",
Christopher Wiley36570f42015-10-08 17:20:11 -0700579 StringPrintf("const %s& data", kAndroidParcelLiteral),
580 StringPrintf("%s* reply", kAndroidParcelLiteral),
Christopher Wileyfd51d602015-10-14 13:04:48 -0700581 "uint32_t flags = 0"}},
582 MethodDecl::IS_OVERRIDE
583 }};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700584
Christopher Wileyf944e792015-09-29 10:00:46 -0700585 std::vector<unique_ptr<Declaration>> publics;
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700586 publics.push_back(std::move(on_transact));
587
Christopher Wileyf944e792015-09-29 10:00:46 -0700588 unique_ptr<ClassDecl> bn_class{
589 new ClassDecl{bn_name,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700590 "android::BnInterface<" + i_name + ">",
Christopher Wileyf944e792015-09-29 10:00:46 -0700591 std::move(publics),
592 {}
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700593 }};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700594
Christopher Wiley0c732db2015-09-29 14:36:44 -0700595 return unique_ptr<Document>{new CppHeader{
Christopher Wileyfd51d602015-10-14 13:04:48 -0700596 BuildHeaderGuard(interface, ClassNames::SERVER),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700597 {"binder/IInterface.h",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700598 HeaderFile(interface, ClassNames::INTERFACE, false)},
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700599 NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700600}
601
Christopher Wileye3550c62015-09-29 13:26:10 -0700602unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700603 const AidlInterface& interface) {
Casey Dahlince776cf2015-10-15 18:45:54 -0700604 set<string> includes = { kIBinderHeader, kIInterfaceHeader };
605
606 for (const auto& method : interface.GetMethods()) {
607 for (const auto& argument : method->GetArguments()) {
608 const Type* type = types.Find(argument->GetType().GetName());
609 const std::string& header = type->Header();
610 if (! header.empty())
611 includes.insert(header);
Casey Dahlinb0966612015-10-19 16:35:26 -0700612 if (argument->GetType().IsArray())
613 includes.insert("vector");
Casey Dahlince776cf2015-10-15 18:45:54 -0700614 }
615
616 const Type* type = types.Find(method->GetType().GetName());
617 const std::string& header = type->Header();
618 if (! header.empty())
619 includes.insert(header);
620 }
621
Christopher Wiley0c732db2015-09-29 14:36:44 -0700622 unique_ptr<ClassDecl> if_class{
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700623 new ClassDecl{ClassName(interface, ClassNames::INTERFACE),
624 "android::IInterface"}};
Christopher Wileyade4b452015-10-10 11:06:03 -0700625 if_class->AddPublic(unique_ptr<Declaration>{new ConstructorDecl{
626 "DECLARE_META_INTERFACE",
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700627 ArgList{vector<string>{ClassName(interface, ClassNames::BASE)}}}});
Christopher Wiley0c732db2015-09-29 14:36:44 -0700628
629 unique_ptr<Enum> call_enum{new Enum{"Call"}};
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700630 for (const auto& method : interface.GetMethods()) {
631 // Each method gets an enum entry and pure virtual declaration.
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700632 if_class->AddPublic(BuildMethodDecl(*method, types, true));
Christopher Wiley0c732db2015-09-29 14:36:44 -0700633 call_enum->AddValue(
Casey Dahlinf4a93112015-10-05 16:58:09 -0700634 UpperCase(method->GetName()),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700635 StringPrintf("android::IBinder::FIRST_CALL_TRANSACTION + %d",
Casey Dahlinf4a93112015-10-05 16:58:09 -0700636 method->GetId()));
Christopher Wiley0c732db2015-09-29 14:36:44 -0700637 }
638 if_class->AddPublic(std::move(call_enum));
639
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700640 return unique_ptr<Document>{new CppHeader{
641 BuildHeaderGuard(interface, ClassNames::INTERFACE),
Casey Dahlince776cf2015-10-15 18:45:54 -0700642 vector<string>(includes.begin(), includes.end()),
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700643 NestInNamespaces(std::move(if_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700644}
645
Christopher Wiley054afbd2015-10-16 17:08:43 -0700646bool WriteHeader(const CppOptions& options,
647 const TypeNamespace& types,
648 const AidlInterface& interface,
649 const IoDelegate& io_delegate,
650 ClassNames header_type) {
651 unique_ptr<Document> header;
652 switch (header_type) {
653 case ClassNames::INTERFACE:
654 header = BuildInterfaceHeader(types, interface);
655 break;
656 case ClassNames::CLIENT:
657 header = BuildClientHeader(types, interface);
658 break;
659 case ClassNames::SERVER:
660 header = BuildServerHeader(types, interface);
661 break;
662 default:
663 LOG(FATAL) << "aidl internal error";
664 }
665 if (!header) {
666 LOG(ERROR) << "aidl internal error: Failed to generate header.";
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700667 return false;
668 }
Christopher Wiley054afbd2015-10-16 17:08:43 -0700669
670 // TODO(wiley): b/25026025 error checking for file I/O
671 header->Write(io_delegate.GetCodeWriter(
672 options.OutputHeaderDir() + OS_PATH_SEPARATOR +
673 HeaderFile(interface, header_type)).get());
674
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700675 return true;
676}
677
Casey Dahlina834dd42015-09-23 11:52:15 -0700678} // namespace internals
679
680using namespace internals;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700681
Christopher Wileye3550c62015-09-29 13:26:10 -0700682bool GenerateCpp(const CppOptions& options,
683 const TypeNamespace& types,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700684 const AidlInterface& interface,
685 const IoDelegate& io_delegate) {
686 auto interface_src = BuildInterfaceSource(types, interface);
687 auto client_src = BuildClientSource(types, interface);
688 auto server_src = BuildServerSource(types, interface);
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700689
Christopher Wiley054afbd2015-10-16 17:08:43 -0700690 if (!interface_src || !client_src || !server_src) {
691 return false;
692 }
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700693
Christopher Wiley054afbd2015-10-16 17:08:43 -0700694 if (!io_delegate.CreatedNestedDirs(options.OutputHeaderDir(),
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700695 interface.GetSplitPackage())) {
Christopher Wiley054afbd2015-10-16 17:08:43 -0700696 LOG(ERROR) << "Failed to create directory structure for headers.";
697 return false;
698 }
699
700 if (!WriteHeader(options, types, interface, io_delegate,
701 ClassNames::INTERFACE) ||
702 !WriteHeader(options, types, interface, io_delegate,
703 ClassNames::CLIENT) ||
704 !WriteHeader(options, types, interface, io_delegate,
705 ClassNames::SERVER)) {
706 return false;
707 }
708
709 // TODO(wiley): b/25026025 error checking for file I/O.
710 // If it fails, we should remove all the partial results.
711 unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(
712 options.OutputCppFilePath());
713 interface_src->Write(writer.get());
714 client_src->Write(writer.get());
715 server_src->Write(writer.get());
716
717 return true;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700718}
719
Christopher Wileyf944e792015-09-29 10:00:46 -0700720} // namespace cpp
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700721} // namespace aidl
Christopher Wileyf944e792015-09-29 10:00:46 -0700722} // namespace android