blob: 128e8a800a72fcedd91ce68618853fb724c428ca [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"
Casey Dahlina834dd42015-09-23 11:52:15 -070018#include "parse_helpers.h"
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070019
Casey Dahlin082f1d12015-09-21 14:06:25 -070020#include <cctype>
Christopher Wileyad339272015-10-05 19:11:58 -070021#include <cstring>
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070022#include <memory>
Casey Dahlin082f1d12015-09-21 14:06:25 -070023#include <random>
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070024#include <string>
25
Christopher Wileye3550c62015-09-29 13:26:10 -070026#include <base/stringprintf.h>
Christopher Wileyad339272015-10-05 19:11:58 -070027#include <base/strings.h>
Christopher Wileye3550c62015-09-29 13:26:10 -070028
Casey Dahlina834dd42015-09-23 11:52:15 -070029#include "aidl_language.h"
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070030#include "ast_cpp.h"
31#include "code_writer.h"
Christopher Wileyeb1acc12015-09-16 11:25:13 -070032#include "logging.h"
33
Christopher Wileye3550c62015-09-29 13:26:10 -070034using android::base::StringPrintf;
Christopher Wileyad339272015-10-05 19:11:58 -070035using android::base::Join;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -070036using std::string;
Casey Dahlin082f1d12015-09-21 14:06:25 -070037using std::unique_ptr;
Casey Dahlina834dd42015-09-23 11:52:15 -070038using std::vector;
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 Wileyad339272015-10-05 19:11:58 -070045const char kStatusOkOrBreakCheck[] = "if (status != android::OK) { break; }";
46const char kReturnVarName[] = "_aidl_return";
Christopher Wiley0c732db2015-09-29 14:36:44 -070047const char kAndroidStatusLiteral[] = "android::status_t";
48const char kIBinderHeader[] = "binder/IBinder.h";
49const char kIInterfaceHeader[] = "binder/IInterface.h";
Christopher Wileyad339272015-10-05 19:11:58 -070050const char kParcelHeader[] = "binder/Parcel.h";
Casey Dahlin082f1d12015-09-21 14:06:25 -070051
Christopher Wiley0c732db2015-09-29 14:36:44 -070052string UpperCase(const std::string& s) {
53 string result = s;
54 for (char& c : result)
55 c = toupper(c);
56 return result;
Casey Dahlina834dd42015-09-23 11:52:15 -070057}
Casey Dahlin082f1d12015-09-21 14:06:25 -070058
Christopher Wileyad339272015-10-05 19:11:58 -070059string BuildVarName(const AidlArgument& a) {
60 string prefix = "out_";
61 if (a.GetDirection() & AidlArgument::IN_DIR) {
62 prefix = "in_";
Christopher Wileye3550c62015-09-29 13:26:10 -070063 }
Christopher Wileyad339272015-10-05 19:11:58 -070064 return prefix + a.GetName();
65}
66
67vector<string> BuildArgList(const TypeNamespace& types,
68 const AidlMethod& method,
69 bool for_declaration) {
70 // Build up the argument list for the server method call.
71 vector<string> method_arguments;
72 for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
73 string literal;
74 if (for_declaration) {
75 // Method declarations need types, pointers to out params, and variable
76 // names that match the .aidl specification.
77 const Type* type = types.Find(a->GetType().GetName());
78 literal = StringPrintf(
79 "%s%s %s", type->CppType().c_str(),
80 (a->IsOut()) ? "*" : "",
81 a->GetName().c_str());
82 } else {
83 if (a->IsOut()) { literal = "&"; }
84 literal += BuildVarName(*a);
85 }
86 method_arguments.push_back(literal);
87 }
88
89 const Type* return_type = types.Find(method.GetType().GetName());
90 if (return_type != types.VoidType()) {
91 if (for_declaration) {
92 method_arguments.push_back(
93 StringPrintf("%s* %s", return_type->CppType().c_str(),
94 kReturnVarName));
95 } else {
96 method_arguments.push_back(string{"&"} + kReturnVarName);
97 }
98 }
99
100 return method_arguments;
Casey Dahlina834dd42015-09-23 11:52:15 -0700101}
102
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700103unique_ptr<Declaration> BuildMethodDecl(const AidlMethod& method,
Christopher Wiley0c732db2015-09-29 14:36:44 -0700104 const TypeNamespace& types,
105 bool for_interface) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700106 uint32_t modifiers = 0;
107 if (for_interface) {
108 modifiers |= MethodDecl::IS_VIRTUAL;
109 modifiers |= MethodDecl::IS_PURE_VIRTUAL;
110 } else {
111 modifiers |= MethodDecl::IS_OVERRIDE;
112 }
113
114 return unique_ptr<Declaration>{
115 new MethodDecl{kAndroidStatusLiteral,
Casey Dahlinf4a93112015-10-05 16:58:09 -0700116 method.GetName(),
Christopher Wileyad339272015-10-05 19:11:58 -0700117 BuildArgList(types, method, true /* for method decl */),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700118 modifiers}};
119}
120
121unique_ptr<CppNamespace> NestInNamespaces(unique_ptr<Declaration> decl) {
122 using N = CppNamespace;
123 using NPtr = unique_ptr<N>;
124 return NPtr{new N{"android", NPtr{new N{"generated", std::move(decl)}}}};
125}
126
Christopher Wileyad339272015-10-05 19:11:58 -0700127bool DeclareLocalVariable(const TypeNamespace& types, const AidlArgument& a,
128 StatementBlock* b) {
129 const Type* cpp_type = types.Find(a.GetType().GetName());
130 if (!cpp_type) { return false; }
131
132 b->AddLiteral(cpp_type->CppType() + " " + BuildVarName(a));
133 return true;
134}
135
Christopher Wiley0c732db2015-09-29 14:36:44 -0700136} // namespace
137
138enum class ClassNames { BASE, CLIENT, SERVER, INTERFACE };
139
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700140string ClassName(const AidlInterface& interface, ClassNames type) {
Casey Dahlinfb7da2e2015-10-08 17:26:09 -0700141 string c_name = interface.GetName();
Christopher Wiley0c732db2015-09-29 14:36:44 -0700142
143 if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
144 c_name = c_name.substr(1);
145
146 switch (type) {
147 case ClassNames::CLIENT:
148 c_name = "Bp" + c_name;
149 break;
150 case ClassNames::SERVER:
151 c_name = "Bn" + c_name;
152 break;
153 case ClassNames::INTERFACE:
154 c_name = "I" + c_name;
155 break;
156 case ClassNames::BASE:
157 break;
158 }
159 return c_name;
160}
161
Christopher Wileye3550c62015-09-29 13:26:10 -0700162unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700163 const AidlInterface& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700164 unique_ptr<CppNamespace> ns{new CppNamespace{"android"}};
Christopher Wileyf944e792015-09-29 10:00:46 -0700165 return unique_ptr<Document>{new CppSource{ {}, std::move(ns)}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700166}
167
Christopher Wileyad339272015-10-05 19:11:58 -0700168namespace {
169
170bool HandleServerTransaction(const TypeNamespace& types,
171 const AidlMethod& method,
172 StatementBlock* b) {
173 // Declare all the parameters now. In the common case, we expect no errors
174 // in serialization.
175 for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
176 if (!DeclareLocalVariable(types, *a, b)) { return false; }
177 }
178
179 // Declare a variable to hold the return value.
180 const Type* return_type = types.Find(method.GetType().GetName());
181 if (return_type != types.VoidType()) {
182 b->AddLiteral(StringPrintf(
183 "%s %s", return_type->CppType().c_str(), kReturnVarName));
184 }
185
186 // Declare the status variable
187 b->AddLiteral(StringPrintf("%s status", kAndroidStatusLiteral));
188
189 // Deserialize each "in" parameter to the transaction.
190 for (const AidlArgument* a : method.GetInArguments()) {
191 // Deserialization looks roughly like:
192 // status = data.ReadInt32(&in_param_name);
193 // if (status != android::OK) { break; }
194 const Type* type = types.Find(a->GetType().GetName());
195 b->AddStatement(new Assignment{
196 "status",
197 new MethodCall{"data." + type->ReadFromParcelMethod(),
198 "&" + BuildVarName(*a)}});
199 b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
200 }
201
202 // Call the actual method. This is implemented by the subclass.
203 b->AddStatement(new Assignment{
204 "status", new MethodCall{
205 method.GetName(),
206 new ArgList{BuildArgList(types, method,
207 false /* not for method decl */)}}});
208 b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
209
210 // Write each out parameter to the reply parcel.
211 for (const AidlArgument* a : method.GetOutArguments()) {
212 // Serialization looks roughly like:
213 // status = data.WriteInt32(out_param_name);
214 // if (status != android::OK) { break; }
215 const Type* type = types.Find(a->GetType().GetName());
216 b->AddStatement(new Assignment{
217 "status",
218 new MethodCall{"reply->" + type->WriteToParcelMethod(),
219 BuildVarName(*a)}});
220 b->AddLiteral(kStatusOkOrBreakCheck, false /* no semicolon */);
221 }
222
223 return true;
224}
225
226} // namespace
227
Christopher Wileye3550c62015-09-29 13:26:10 -0700228unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700229 const AidlInterface& parsed_doc) {
Christopher Wileyad339272015-10-05 19:11:58 -0700230 const string bn_name = ClassName(parsed_doc, ClassNames::SERVER);
231 vector<string> include_list{bn_name + ".h", kParcelHeader};
232 unique_ptr<MethodImpl> on_transact{new MethodImpl{
233 kAndroidStatusLiteral, bn_name, "onTransact",
234 {"uint32_t code",
235 "const android::Parcel& data",
236 "android::Parcel* reply",
237 "uint32_t flags"}
238 }};
239
240 // Add the all important switch statement, but retain a pointer to it.
241 SwitchStatement* s = new SwitchStatement{"code"};
242 on_transact->AddStatement(unique_ptr<AstNode>{s});
243
244 // The switch statement has a case statement for each transaction code.
245 for (const auto& method : parsed_doc.GetMethods()) {
246 StatementBlock* b = s->AddCase("Call::" + UpperCase(method->GetName()));
247 if (!b) { return nullptr; }
248
249 if (!HandleServerTransaction(types, *method, b)) { return nullptr; }
250 }
251
252 // The switch statement has a default case which defers to the super class.
253 // The superclass handles a few pre-defined transactions.
254 StatementBlock* b = s->AddCase("");
255 b->AddLiteral(
256 "status = android::BBinder::onTransact(code, data, reply, flags)");
257
258 // Finally, the server's onTransact method just returns a status code.
259 on_transact->AddStatement(unique_ptr<AstNode>{
260 new LiteralStatement{"return status"}});
261
262 return unique_ptr<Document>{new CppSource{
263 include_list,
264 NestInNamespaces(std::move(on_transact))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700265}
266
Christopher Wileye3550c62015-09-29 13:26:10 -0700267unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& types,
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700268 const AidlInterface& parsed_doc) {
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700269 const string i_name = ClassName(parsed_doc, ClassNames::INTERFACE);
270 const string bp_name = ClassName(parsed_doc, ClassNames::CLIENT);
271 vector<string> include_list{i_name + ".h", bp_name + ".h"};
272
273 string fq_name = i_name;
Casey Dahlinfb7da2e2015-10-08 17:26:09 -0700274 if (!parsed_doc.GetPackage().empty()) {
275 fq_name = StringPrintf("%s.%s", parsed_doc.GetPackage().c_str(), i_name.c_str());
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700276 }
277
278 unique_ptr<ConstructorDecl> meta_if{new ConstructorDecl{
279 "IMPLEMENT_META_INTERFACE",
280 {ClassName(parsed_doc, ClassNames::BASE), '"' + fq_name + '"'}
281 }};
282
283 return unique_ptr<Document>{new CppSource{
284 include_list,
285 NestInNamespaces(std::move(meta_if))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700286}
287
Christopher Wileye3550c62015-09-29 13:26:10 -0700288unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700289 const AidlInterface& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700290 const string i_name = ClassName(parsed_doc, ClassNames::INTERFACE);
291 const string bp_name = ClassName(parsed_doc, ClassNames::CLIENT);
Casey Dahlina834dd42015-09-23 11:52:15 -0700292
Christopher Wiley0c732db2015-09-29 14:36:44 -0700293 unique_ptr<ConstructorDecl> constructor{new ConstructorDecl(bp_name, {})};
Christopher Wileyf944e792015-09-29 10:00:46 -0700294 unique_ptr<ConstructorDecl> destructor{
Christopher Wiley0c732db2015-09-29 14:36:44 -0700295 new ConstructorDecl("~" + bp_name, {})};
Casey Dahlina834dd42015-09-23 11:52:15 -0700296
Christopher Wileyf944e792015-09-29 10:00:46 -0700297 vector<unique_ptr<Declaration>> publics;
Casey Dahlina834dd42015-09-23 11:52:15 -0700298 publics.push_back(std::move(constructor));
299 publics.push_back(std::move(destructor));
300
Casey Dahlinfb7da2e2015-10-08 17:26:09 -0700301 for (const auto& item : parsed_doc.GetMethods()) {
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700302 publics.push_back(BuildMethodDecl(*item, types, false));
Casey Dahlina834dd42015-09-23 11:52:15 -0700303 }
304
Christopher Wileyf944e792015-09-29 10:00:46 -0700305 unique_ptr<ClassDecl> bp_class{
306 new ClassDecl{bp_name,
307 "public android::BpInterface<" + i_name + ">",
308 std::move(publics),
309 {}
Casey Dahlina834dd42015-09-23 11:52:15 -0700310 }};
311
Christopher Wiley0c732db2015-09-29 14:36:44 -0700312 return unique_ptr<Document>{new CppHeader{
313 bp_name + "_H",
314 {kIBinderHeader,
315 kIInterfaceHeader,
316 "utils/Errors.h",
317 i_name + ".h"},
318 NestInNamespaces(std::move(bp_class))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700319}
320
Christopher Wileye3550c62015-09-29 13:26:10 -0700321unique_ptr<Document> BuildServerHeader(const TypeNamespace& types,
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700322 const AidlInterface& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700323 const string i_name = ClassName(parsed_doc, ClassNames::INTERFACE);
324 const string bn_name = ClassName(parsed_doc, ClassNames::SERVER);
Casey Dahlin082f1d12015-09-21 14:06:25 -0700325
Christopher Wileyf944e792015-09-29 10:00:46 -0700326 unique_ptr<Declaration> on_transact{
Christopher Wiley0c732db2015-09-29 14:36:44 -0700327 new MethodDecl(kAndroidStatusLiteral, "onTransact",
Christopher Wileyf944e792015-09-29 10:00:46 -0700328 { "uint32_t code",
329 "const android::Parcel& data",
330 "android::Parcel* reply",
331 "uint32_t flags = 0"
332 })};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700333
Christopher Wileyf944e792015-09-29 10:00:46 -0700334 std::vector<unique_ptr<Declaration>> publics;
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700335 publics.push_back(std::move(on_transact));
336
Christopher Wileyf944e792015-09-29 10:00:46 -0700337 unique_ptr<ClassDecl> bn_class{
338 new ClassDecl{bn_name,
339 "public android::BnInterface<" + i_name + ">",
340 std::move(publics),
341 {}
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700342 }};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700343
Christopher Wiley0c732db2015-09-29 14:36:44 -0700344 return unique_ptr<Document>{new CppHeader{
345 bn_name + "_H",
346 {"binder/IInterface.h",
347 i_name + ".h"},
348 NestInNamespaces(std::move(bn_class))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700349}
350
Christopher Wileye3550c62015-09-29 13:26:10 -0700351unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700352 const AidlInterface& parsed_doc) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700353 unique_ptr<ClassDecl> if_class{
354 new ClassDecl{ClassName(parsed_doc, ClassNames::INTERFACE),
355 "public android::IInterface"}};
356 if_class->AddPublic(unique_ptr<Declaration>{
357 new ConstructorDecl{
358 "DECLARE_META_INTERFACE",
359 {ClassName(parsed_doc, ClassNames::BASE)}}});
360
361 unique_ptr<Enum> call_enum{new Enum{"Call"}};
Casey Dahlinfb7da2e2015-10-08 17:26:09 -0700362 for (const auto& method : parsed_doc.GetMethods()) {
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700363 if_class->AddPublic(BuildMethodDecl(*method, types, true));
Christopher Wiley0c732db2015-09-29 14:36:44 -0700364 call_enum->AddValue(
Casey Dahlinf4a93112015-10-05 16:58:09 -0700365 UpperCase(method->GetName()),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700366 StringPrintf("android::IBinder::FIRST_CALL_TRANSACTION + %d",
Casey Dahlinf4a93112015-10-05 16:58:09 -0700367 method->GetId()));
Christopher Wiley0c732db2015-09-29 14:36:44 -0700368 }
369 if_class->AddPublic(std::move(call_enum));
370
371 return unique_ptr<Document>{new CppSource{
372 {kIBinderHeader,
373 kIInterfaceHeader},
374 NestInNamespaces(std::move(if_class))}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700375}
376
Christopher Wileyf944e792015-09-29 10:00:46 -0700377bool GenerateCppForFile(const std::string& name, unique_ptr<Document> doc) {
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700378 if (!doc) {
379 return false;
380 }
381 unique_ptr<CodeWriter> writer = GetFileWriter(name);
382 doc->Write(writer.get());
383 return true;
384}
385
Casey Dahlina834dd42015-09-23 11:52:15 -0700386} // namespace internals
387
388using namespace internals;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700389
Christopher Wileye3550c62015-09-29 13:26:10 -0700390bool GenerateCpp(const CppOptions& options,
391 const TypeNamespace& types,
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700392 const AidlInterface& parsed_doc) {
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700393 bool success = true;
394
395 success &= GenerateCppForFile(options.ClientCppFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700396 BuildClientSource(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700397 success &= GenerateCppForFile(options.ClientHeaderFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700398 BuildClientHeader(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700399 success &= GenerateCppForFile(options.ServerCppFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700400 BuildServerSource(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700401 success &= GenerateCppForFile(options.ServerHeaderFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700402 BuildServerHeader(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700403 success &= GenerateCppForFile(options.InterfaceCppFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700404 BuildInterfaceSource(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700405 success &= GenerateCppForFile(options.InterfaceHeaderFileName(),
Christopher Wileye3550c62015-09-29 13:26:10 -0700406 BuildInterfaceHeader(types, parsed_doc));
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700407
408 return success;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700409}
410
Christopher Wileyf944e792015-09-29 10:00:46 -0700411} // namespace cpp
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700412} // namespace aidl
Christopher Wileyf944e792015-09-29 10:00:46 -0700413} // namespace android