blob: 001ea44f585062ffe8cf116bee1cccacabe4a97c [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
Casey Dahlinb8d9e882015-11-24 10:57:23 -080046const char kAndroidStatusVarName[] = "_aidl_ret_status";
47const char kCodeVarName[] = "_aidl_code";
48const char kFlagsVarName[] = "_aidl_flags";
49const char kDataVarName[] = "_aidl_data";
50const char kErrorLabel[] = "_aidl_error";
51const char kImplVarName[] = "_aidl_impl";
52const char kReplyVarName[] = "_aidl_reply";
Christopher Wileyad339272015-10-05 19:11:58 -070053const char kReturnVarName[] = "_aidl_return";
Casey Dahlinb8d9e882015-11-24 10:57:23 -080054const char kStatusVarName[] = "_aidl_status";
55const char kAndroidParcelLiteral[] = "::android::Parcel";
56const char kAndroidStatusLiteral[] = "::android::status_t";
57const char kAndroidStatusOk[] = "::android::OK";
58const char kBinderStatusLiteral[] = "::android::binder::Status";
Christopher Wiley0c732db2015-09-29 14:36:44 -070059const char kIBinderHeader[] = "binder/IBinder.h";
60const char kIInterfaceHeader[] = "binder/IInterface.h";
Christopher Wileyad339272015-10-05 19:11:58 -070061const char kParcelHeader[] = "binder/Parcel.h";
Christopher Wiley433c8bb2015-11-12 14:20:46 -080062const char kStatusHeader[] = "binder/Status.h";
Casey Dahlin389781f2015-10-22 13:13:21 -070063const char kStrongPointerHeader[] = "utils/StrongPointer.h";
Casey Dahlin082f1d12015-09-21 14:06:25 -070064
Christopher Wiley0eb903e2015-10-20 17:07:08 -070065unique_ptr<AstNode> BreakOnStatusNotOk() {
66 IfStatement* ret = new IfStatement(new Comparison(
Casey Dahlinb8d9e882015-11-24 10:57:23 -080067 new LiteralExpression(kAndroidStatusVarName), "!=",
68 new LiteralExpression(kAndroidStatusOk)));
Christopher Wiley0eb903e2015-10-20 17:07:08 -070069 ret->OnTrue()->AddLiteral("break");
70 return unique_ptr<AstNode>(ret);
71}
72
Christopher Wiley433c8bb2015-11-12 14:20:46 -080073unique_ptr<AstNode> GotoErrorOnBadStatus() {
74 IfStatement* ret = new IfStatement(new Comparison(
Casey Dahlinb8d9e882015-11-24 10:57:23 -080075 new LiteralExpression(kAndroidStatusVarName), "!=",
76 new LiteralExpression(kAndroidStatusOk)));
77 ret->OnTrue()->AddLiteral(StringPrintf("goto %s", kErrorLabel));
Christopher Wiley433c8bb2015-11-12 14:20:46 -080078 return unique_ptr<AstNode>(ret);
79}
80
81
Christopher Wiley0eb903e2015-10-20 17:07:08 -070082unique_ptr<AstNode> ReturnOnStatusNotOk() {
83 IfStatement* ret = new IfStatement(new Comparison(
Casey Dahlinb8d9e882015-11-24 10:57:23 -080084 new LiteralExpression(kAndroidStatusVarName), "!=",
85 new LiteralExpression(kAndroidStatusOk)));
86 ret->OnTrue()->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName));
Christopher Wiley0eb903e2015-10-20 17:07:08 -070087 return unique_ptr<AstNode>(ret);
88}
89
Christopher Wiley0c732db2015-09-29 14:36:44 -070090string UpperCase(const std::string& s) {
91 string result = s;
92 for (char& c : result)
93 c = toupper(c);
94 return result;
Casey Dahlina834dd42015-09-23 11:52:15 -070095}
Casey Dahlin082f1d12015-09-21 14:06:25 -070096
Christopher Wileyad339272015-10-05 19:11:58 -070097string BuildVarName(const AidlArgument& a) {
98 string prefix = "out_";
99 if (a.GetDirection() & AidlArgument::IN_DIR) {
100 prefix = "in_";
Christopher Wileye3550c62015-09-29 13:26:10 -0700101 }
Christopher Wileyad339272015-10-05 19:11:58 -0700102 return prefix + a.GetName();
103}
104
Christopher Wileyade4b452015-10-10 11:06:03 -0700105ArgList BuildArgList(const TypeNamespace& types,
106 const AidlMethod& method,
107 bool for_declaration) {
Christopher Wileyad339272015-10-05 19:11:58 -0700108 // Build up the argument list for the server method call.
109 vector<string> method_arguments;
110 for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
111 string literal;
112 if (for_declaration) {
113 // Method declarations need types, pointers to out params, and variable
114 // names that match the .aidl specification.
115 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlince776cf2015-10-15 18:45:54 -0700116
Casey Dahlinb0966612015-10-19 16:35:26 -0700117 literal = type->CppType(a->GetType().IsArray());
118
Christopher Wileyb8e49a42015-10-27 12:55:18 -0700119 if (a->IsOut()) {
120 literal = literal + "*";
121 } else {
122 // We pass in parameters that are not primitives by const reference.
123 // Arrays of primitives are not primitives.
124 if (!type->IsCppPrimitive() || a->GetType().IsArray()) {
125 literal = "const " + literal + "&";
126 }
127 }
Casey Dahlinb0966612015-10-19 16:35:26 -0700128
129 literal += " " + a->GetName();
Christopher Wileyad339272015-10-05 19:11:58 -0700130 } else {
131 if (a->IsOut()) { literal = "&"; }
132 literal += BuildVarName(*a);
133 }
134 method_arguments.push_back(literal);
135 }
136
137 const Type* return_type = types.Find(method.GetType().GetName());
Casey Dahlince776cf2015-10-15 18:45:54 -0700138
Christopher Wileyad339272015-10-05 19:11:58 -0700139 if (return_type != types.VoidType()) {
Christopher Wileyade4b452015-10-10 11:06:03 -0700140 string literal;
Christopher Wileyad339272015-10-05 19:11:58 -0700141 if (for_declaration) {
Christopher Wileyade4b452015-10-10 11:06:03 -0700142 literal = StringPrintf(
Christopher Wileybb967822015-10-27 14:04:53 -0700143 "%s* %s", return_type->CppType(method.GetType().IsArray()).c_str(),
Casey Dahlinb0966612015-10-19 16:35:26 -0700144 kReturnVarName);
Christopher Wileyad339272015-10-05 19:11:58 -0700145 } else {
Christopher Wileyade4b452015-10-10 11:06:03 -0700146 literal = string{"&"} + kReturnVarName;
Christopher Wileyad339272015-10-05 19:11:58 -0700147 }
Christopher Wileyade4b452015-10-10 11:06:03 -0700148 method_arguments.push_back(literal);
Christopher Wileyad339272015-10-05 19:11:58 -0700149 }
150
Christopher Wileyade4b452015-10-10 11:06:03 -0700151 return ArgList(method_arguments);
Casey Dahlina834dd42015-09-23 11:52:15 -0700152}
153
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700154unique_ptr<Declaration> BuildMethodDecl(const AidlMethod& method,
Christopher Wiley0c732db2015-09-29 14:36:44 -0700155 const TypeNamespace& types,
156 bool for_interface) {
Christopher Wiley0c732db2015-09-29 14:36:44 -0700157 uint32_t modifiers = 0;
158 if (for_interface) {
159 modifiers |= MethodDecl::IS_VIRTUAL;
160 modifiers |= MethodDecl::IS_PURE_VIRTUAL;
161 } else {
162 modifiers |= MethodDecl::IS_OVERRIDE;
163 }
164
165 return unique_ptr<Declaration>{
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800166 new MethodDecl{kBinderStatusLiteral,
Casey Dahlinf4a93112015-10-05 16:58:09 -0700167 method.GetName(),
Christopher Wileyad339272015-10-05 19:11:58 -0700168 BuildArgList(types, method, true /* for method decl */),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700169 modifiers}};
170}
171
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700172unique_ptr<CppNamespace> NestInNamespaces(
173 vector<unique_ptr<Declaration>> decls,
174 const vector<string>& package) {
175 if (package.empty()) {
176 // We should also be checking this before we get this far, but do it again
177 // for the sake of unit tests and meaningful errors.
178 LOG(FATAL) << "C++ generation requires a package declaration "
179 "for namespacing";
180 }
181 auto it = package.crbegin(); // Iterate over the namespaces inner to outer
182 unique_ptr<CppNamespace> inner{new CppNamespace{*it, std::move(decls)}};
183 ++it;
184 for (; it != package.crend(); ++it) {
185 inner.reset(new CppNamespace{*it, std::move(inner)});
186 }
187 return inner;
Christopher Wiley0c732db2015-09-29 14:36:44 -0700188}
189
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700190unique_ptr<CppNamespace> NestInNamespaces(unique_ptr<Declaration> decl,
191 const vector<string>& package) {
192 vector<unique_ptr<Declaration>> decls;
193 decls.push_back(std::move(decl));
194 return NestInNamespaces(std::move(decls), package);
Christopher Wiley36570f42015-10-08 17:20:11 -0700195}
196
Christopher Wileyad339272015-10-05 19:11:58 -0700197bool DeclareLocalVariable(const TypeNamespace& types, const AidlArgument& a,
198 StatementBlock* b) {
199 const Type* cpp_type = types.Find(a.GetType().GetName());
200 if (!cpp_type) { return false; }
201
Casey Dahlinb0966612015-10-19 16:35:26 -0700202 string type = cpp_type->CppType(a.GetType().IsArray());
203
204 b->AddLiteral(type + " " + BuildVarName(a));
Christopher Wileyad339272015-10-05 19:11:58 -0700205 return true;
206}
207
Christopher Wiley0c732db2015-09-29 14:36:44 -0700208enum class ClassNames { BASE, CLIENT, SERVER, INTERFACE };
209
Casey Dahlin1ae2bc52015-10-07 18:49:10 -0700210string ClassName(const AidlInterface& interface, ClassNames type) {
Casey Dahlinfb7da2e2015-10-08 17:26:09 -0700211 string c_name = interface.GetName();
Christopher Wiley0c732db2015-09-29 14:36:44 -0700212
213 if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
214 c_name = c_name.substr(1);
215
216 switch (type) {
217 case ClassNames::CLIENT:
218 c_name = "Bp" + c_name;
219 break;
220 case ClassNames::SERVER:
221 c_name = "Bn" + c_name;
222 break;
223 case ClassNames::INTERFACE:
224 c_name = "I" + c_name;
225 break;
226 case ClassNames::BASE:
227 break;
228 }
229 return c_name;
230}
231
Christopher Wiley054afbd2015-10-16 17:08:43 -0700232string HeaderFile(const AidlInterface& interface,
233 ClassNames class_type,
234 bool use_os_sep = true) {
235 string file_path = interface.GetPackage();
236 for (char& c: file_path) {
237 if (c == '.') {
238 c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
239 }
240 }
241 if (!file_path.empty()) {
242 file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
243 }
244 file_path += ClassName(interface, class_type);
245 file_path += ".h";
246
247 return file_path;
248}
249
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700250string BuildHeaderGuard(const AidlInterface& interface,
251 ClassNames header_type) {
252 string class_name = ClassName(interface, header_type);
253 for (size_t i = 1; i < class_name.size(); ++i) {
254 if (isupper(class_name[i])) {
255 class_name.insert(i, "_");
256 ++i;
257 }
258 }
259 string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_",
260 interface.GetPackage().c_str(),
261 class_name.c_str());
262 for (char& c : ret) {
263 if (c == '.') {
264 c = '_';
265 }
266 c = toupper(c);
267 }
268 return ret;
269}
Christopher Wiley36570f42015-10-08 17:20:11 -0700270
271unique_ptr<Declaration> DefineClientTransaction(const TypeNamespace& types,
272 const AidlInterface& interface,
273 const AidlMethod& method) {
274 const string i_name = ClassName(interface, ClassNames::INTERFACE);
275 const string bp_name = ClassName(interface, ClassNames::CLIENT);
276 unique_ptr<MethodImpl> ret{new MethodImpl{
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800277 kBinderStatusLiteral, bp_name, method.GetName(),
Christopher Wiley36570f42015-10-08 17:20:11 -0700278 ArgList{BuildArgList(types, method, true /* for method decl */)}}};
279 StatementBlock* b = ret->GetStatementBlock();
280
281 // Declare parcels to hold our query and the response.
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800282 b->AddLiteral(StringPrintf("%s %s", kAndroidParcelLiteral, kDataVarName));
Christopher Wiley1227d612015-10-26 16:59:20 -0700283 // Even if we're oneway, the transact method still takes a parcel.
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800284 b->AddLiteral(StringPrintf("%s %s", kAndroidParcelLiteral, kReplyVarName));
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700285
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800286 // Declare the status_t variable we need for error handling.
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800287 b->AddLiteral(StringPrintf("%s %s", kAndroidStatusLiteral,
288 kAndroidStatusVarName));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800289 // We unconditionally return a Status object.
290 b->AddLiteral(StringPrintf("%s %s", kBinderStatusLiteral, kStatusVarName));
Christopher Wiley36570f42015-10-08 17:20:11 -0700291
Christopher Wiley8993cb52015-10-21 09:53:24 -0700292 // Add the name of the interface we're hoping to call.
293 b->AddStatement(new Assignment(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800294 kAndroidStatusVarName,
295 new MethodCall(StringPrintf("%s.writeInterfaceToken",
296 kDataVarName),
297 "getInterfaceDescriptor()")));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800298 b->AddStatement(GotoErrorOnBadStatus());
Christopher Wiley8993cb52015-10-21 09:53:24 -0700299
Christopher Wiley36570f42015-10-08 17:20:11 -0700300 // Serialization looks roughly like:
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800301 // _aidl_ret_status = _aidl_data.WriteInt32(in_param_name);
302 // if (_aidl_ret_status != ::android::OK) { goto error; }
Christopher Wiley36570f42015-10-08 17:20:11 -0700303 for (const AidlArgument* a : method.GetInArguments()) {
Casey Dahlin389781f2015-10-22 13:13:21 -0700304 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlinb0966612015-10-19 16:35:26 -0700305 string method =
Casey Dahlin389781f2015-10-22 13:13:21 -0700306 type->WriteToParcelMethod(a->GetType().IsArray());
Casey Dahlinb0966612015-10-19 16:35:26 -0700307
Christopher Wiley36570f42015-10-08 17:20:11 -0700308 string var_name = ((a->IsOut()) ? "*" : "") + a->GetName();
Casey Dahlin389781f2015-10-22 13:13:21 -0700309 var_name = type->WriteCast(var_name);
Christopher Wiley36570f42015-10-08 17:20:11 -0700310 b->AddStatement(new Assignment(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800311 kAndroidStatusVarName,
312 new MethodCall(StringPrintf("%s.%s", kDataVarName, method.c_str()),
313 ArgList(var_name))));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800314 b->AddStatement(GotoErrorOnBadStatus());
Christopher Wiley36570f42015-10-08 17:20:11 -0700315 }
316
317 // Invoke the transaction on the remote binder and confirm status.
318 string transaction_code = StringPrintf(
319 "%s::%s", i_name.c_str(), UpperCase(method.GetName()).c_str());
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700320
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800321 vector<string> args = {transaction_code, kDataVarName,
322 StringPrintf("&%s", kReplyVarName)};
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700323
324 if (interface.IsOneway() || method.IsOneway()) {
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800325 args.push_back("::android::IBinder::FLAG_ONEWAY");
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700326 }
327
Christopher Wiley36570f42015-10-08 17:20:11 -0700328 b->AddStatement(new Assignment(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800329 kAndroidStatusVarName,
Christopher Wiley36570f42015-10-08 17:20:11 -0700330 new MethodCall("remote()->transact",
Casey Dahlin0dd08af2015-10-20 18:45:50 -0700331 ArgList(args))));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800332 b->AddStatement(GotoErrorOnBadStatus());
Christopher Wiley36570f42015-10-08 17:20:11 -0700333
Christopher Wiley1227d612015-10-26 16:59:20 -0700334 if (!interface.IsOneway() && !method.IsOneway()) {
335 // Strip off the exception header and fail if we see a remote exception.
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800336 // _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
337 // if (_aidl_ret_status != ::android::OK) { goto error; }
338 // if (!_aidl_status.isOk()) { return _aidl_ret_status; }
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800339 b->AddStatement(new Assignment(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800340 kAndroidStatusVarName,
341 StringPrintf("%s.readFromParcel(%s)", kStatusVarName, kReplyVarName)));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800342 b->AddStatement(GotoErrorOnBadStatus());
Christopher Wiley1227d612015-10-26 16:59:20 -0700343 IfStatement* exception_check = new IfStatement(
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800344 new LiteralExpression(StringPrintf("!%s.isOk()", kStatusVarName)));
Christopher Wiley1227d612015-10-26 16:59:20 -0700345 b->AddStatement(exception_check);
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800346 exception_check->OnTrue()->AddLiteral(
347 StringPrintf("return %s", kStatusVarName));
Christopher Wiley1227d612015-10-26 16:59:20 -0700348 }
349
350 // Type checking should guarantee that nothing below emits code until "return
351 // status" if we are a oneway method, so no more fear of accessing reply.
Christopher Wiley2aaeda82015-10-19 15:16:49 -0700352
Christopher Wiley36570f42015-10-08 17:20:11 -0700353 // If the method is expected to return something, read it first by convention.
354 const Type* return_type = types.Find(method.GetType().GetName());
355 if (return_type != types.VoidType()) {
Christopher Wileybb967822015-10-27 14:04:53 -0700356 string method_call = return_type->ReadFromParcelMethod(
357 method.GetType().IsArray());
Christopher Wiley36570f42015-10-08 17:20:11 -0700358 b->AddStatement(new Assignment(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800359 kAndroidStatusVarName,
360 new MethodCall(StringPrintf("%s.%s", kReplyVarName,
361 method_call.c_str()),
362 ArgList(kReturnVarName))));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800363 b->AddStatement(GotoErrorOnBadStatus());
Christopher Wiley36570f42015-10-08 17:20:11 -0700364 }
365
366 for (const AidlArgument* a : method.GetOutArguments()) {
367 // Deserialization looks roughly like:
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800368 // _aidl_ret_status = _aidl_reply.ReadInt32(out_param_name);
369 // if (_aidl_status != ::android::OK) { goto _aidl_error; }
Casey Dahlinb0966612015-10-19 16:35:26 -0700370 string method =
371 types.Find(a->GetType().GetName())
372 ->ReadFromParcelMethod(a->GetType().IsArray());
373
Christopher Wiley36570f42015-10-08 17:20:11 -0700374 b->AddStatement(new Assignment(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800375 kAndroidStatusVarName,
376 new MethodCall(StringPrintf("%s.%s", kReplyVarName,
377 method.c_str()),
378 ArgList(a->GetName()))));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800379 b->AddStatement(GotoErrorOnBadStatus());
Christopher Wiley36570f42015-10-08 17:20:11 -0700380 }
381
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800382 // If we've gotten to here, one of two things is true:
383 // 1) We've read some bad status_t
384 // 2) We've only read status_t == OK and there was no exception in the
385 // response.
386 // In both cases, we're free to set Status from the status_t and return.
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800387 b->AddLiteral(StringPrintf("%s:\n", kErrorLabel), false /* no semicolon */);
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800388 b->AddLiteral(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800389 StringPrintf("%s.setFromStatusT(%s)", kStatusVarName,
390 kAndroidStatusVarName));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800391 b->AddLiteral(StringPrintf("return %s", kStatusVarName));
Christopher Wiley36570f42015-10-08 17:20:11 -0700392
393 return unique_ptr<Declaration>(ret.release());
394}
395
396} // namespace
397
Christopher Wileye3550c62015-09-29 13:26:10 -0700398unique_ptr<Document> BuildClientSource(const TypeNamespace& types,
Christopher Wiley36570f42015-10-08 17:20:11 -0700399 const AidlInterface& interface) {
Christopher Wiley054afbd2015-10-16 17:08:43 -0700400 vector<string> include_list = {
401 HeaderFile(interface, ClassNames::CLIENT, false),
402 kParcelHeader
403 };
Christopher Wiley36570f42015-10-08 17:20:11 -0700404 vector<unique_ptr<Declaration>> file_decls;
405
406 // The constructor just passes the IBinder instance up to the super
407 // class.
Christopher Wiley1db03482015-10-22 11:42:02 -0700408 const string i_name = ClassName(interface, ClassNames::INTERFACE);
Christopher Wiley36570f42015-10-08 17:20:11 -0700409 file_decls.push_back(unique_ptr<Declaration>{new ConstructorImpl{
Christopher Wiley054afbd2015-10-16 17:08:43 -0700410 ClassName(interface, ClassNames::CLIENT),
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800411 ArgList{StringPrintf("const ::android::sp<::android::IBinder>& %s",
412 kImplVarName)},
413 { "BpInterface<" + i_name + ">(" + kImplVarName + ")" }}});
Christopher Wiley36570f42015-10-08 17:20:11 -0700414
415 // Clients define a method per transaction.
416 for (const auto& method : interface.GetMethods()) {
417 unique_ptr<Declaration> m = DefineClientTransaction(
418 types, interface, *method);
419 if (!m) { return nullptr; }
420 file_decls.push_back(std::move(m));
421 }
422 return unique_ptr<Document>{new CppSource{
423 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700424 NestInNamespaces(std::move(file_decls), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700425}
426
Christopher Wileyad339272015-10-05 19:11:58 -0700427namespace {
428
429bool HandleServerTransaction(const TypeNamespace& types,
430 const AidlMethod& method,
431 StatementBlock* b) {
432 // Declare all the parameters now. In the common case, we expect no errors
433 // in serialization.
434 for (const unique_ptr<AidlArgument>& a : method.GetArguments()) {
435 if (!DeclareLocalVariable(types, *a, b)) { return false; }
436 }
437
438 // Declare a variable to hold the return value.
439 const Type* return_type = types.Find(method.GetType().GetName());
440 if (return_type != types.VoidType()) {
441 b->AddLiteral(StringPrintf(
Christopher Wileybb967822015-10-27 14:04:53 -0700442 "%s %s", return_type->CppType(method.GetType().IsArray()).c_str(),
Casey Dahlinb0966612015-10-19 16:35:26 -0700443 kReturnVarName));
Christopher Wileyad339272015-10-05 19:11:58 -0700444 }
445
Christopher Wiley8993cb52015-10-21 09:53:24 -0700446 // Check that the client is calling the correct interface.
447 IfStatement* interface_check = new IfStatement(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800448 new MethodCall(StringPrintf("%s.checkInterface",
449 kDataVarName), "this"),
Christopher Wiley8993cb52015-10-21 09:53:24 -0700450 true /* invert the check */);
451 b->AddStatement(interface_check);
452 interface_check->OnTrue()->AddStatement(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800453 new Assignment(kAndroidStatusVarName, "::android::BAD_TYPE"));
Christopher Wiley8993cb52015-10-21 09:53:24 -0700454 interface_check->OnTrue()->AddLiteral("break");
455
Christopher Wileyad339272015-10-05 19:11:58 -0700456 // Deserialize each "in" parameter to the transaction.
457 for (const AidlArgument* a : method.GetInArguments()) {
458 // Deserialization looks roughly like:
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800459 // _aidl_ret_status = _aidl_data.ReadInt32(&in_param_name);
460 // if (_aidl_ret_status != ::android::OK) { break; }
Christopher Wileyad339272015-10-05 19:11:58 -0700461 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlinb0966612015-10-19 16:35:26 -0700462 string readMethod = type->ReadFromParcelMethod(a->GetType().IsArray());
463
Christopher Wileyad339272015-10-05 19:11:58 -0700464 b->AddStatement(new Assignment{
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800465 kAndroidStatusVarName,
466 new MethodCall{string(kDataVarName) + "." + readMethod,
Christopher Wileyad339272015-10-05 19:11:58 -0700467 "&" + BuildVarName(*a)}});
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700468 b->AddStatement(BreakOnStatusNotOk());
Christopher Wileyad339272015-10-05 19:11:58 -0700469 }
470
471 // Call the actual method. This is implemented by the subclass.
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800472 vector<unique_ptr<AstNode>> status_args;
473 status_args.emplace_back(new MethodCall(
Christopher Wileyad339272015-10-05 19:11:58 -0700474 method.GetName(),
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800475 BuildArgList(types, method, false /* not for method decl */)));
476 b->AddStatement(new Statement(new MethodCall(
477 StringPrintf("%s %s", kBinderStatusLiteral, kStatusVarName),
478 ArgList(std::move(status_args)))));
Christopher Wileyad339272015-10-05 19:11:58 -0700479
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800480 // Write exceptions during transaction handling to parcel.
481 if (!method.IsOneway()) {
482 b->AddStatement(new Assignment(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800483 kAndroidStatusVarName,
484 StringPrintf("%s.writeToParcel(%s)", kStatusVarName, kReplyVarName)));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800485 b->AddStatement(BreakOnStatusNotOk());
486 IfStatement* exception_check = new IfStatement(
487 new LiteralExpression(StringPrintf("!%s.isOk()", kStatusVarName)));
488 b->AddStatement(exception_check);
489 exception_check->OnTrue()->AddLiteral("break");
490 }
Casey Dahlinb0966612015-10-19 16:35:26 -0700491
Christopher Wiley36570f42015-10-08 17:20:11 -0700492 // If we have a return value, write it first.
493 if (return_type != types.VoidType()) {
Christopher Wiley2aaeda82015-10-19 15:16:49 -0700494 string writeMethod =
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800495 string(kReplyVarName) + "->" +
Christopher Wiley2aaeda82015-10-19 15:16:49 -0700496 return_type->WriteToParcelMethod(method.GetType().IsArray());
Christopher Wiley36570f42015-10-08 17:20:11 -0700497 b->AddStatement(new Assignment{
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800498 kAndroidStatusVarName, new MethodCall{writeMethod,
Casey Dahlin389781f2015-10-22 13:13:21 -0700499 ArgList{return_type->WriteCast(kReturnVarName)}}});
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700500 b->AddStatement(BreakOnStatusNotOk());
Christopher Wiley36570f42015-10-08 17:20:11 -0700501 }
502
Christopher Wileyad339272015-10-05 19:11:58 -0700503 // Write each out parameter to the reply parcel.
504 for (const AidlArgument* a : method.GetOutArguments()) {
505 // Serialization looks roughly like:
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800506 // _aidl_ret_status = data.WriteInt32(out_param_name);
507 // if (_aidl_ret_status != ::android::OK) { break; }
Christopher Wileyad339272015-10-05 19:11:58 -0700508 const Type* type = types.Find(a->GetType().GetName());
Casey Dahlinb0966612015-10-19 16:35:26 -0700509 string writeMethod = type->WriteToParcelMethod(a->GetType().IsArray());
510
Christopher Wileyad339272015-10-05 19:11:58 -0700511 b->AddStatement(new Assignment{
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800512 kAndroidStatusVarName,
513 new MethodCall{string(kReplyVarName) + "->" + writeMethod,
Casey Dahlin389781f2015-10-22 13:13:21 -0700514 type->WriteCast(BuildVarName(*a))}});
Christopher Wiley0eb903e2015-10-20 17:07:08 -0700515 b->AddStatement(BreakOnStatusNotOk());
Christopher Wileyad339272015-10-05 19:11:58 -0700516 }
517
518 return true;
519}
520
521} // namespace
522
Christopher Wileye3550c62015-09-29 13:26:10 -0700523unique_ptr<Document> BuildServerSource(const TypeNamespace& types,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700524 const AidlInterface& interface) {
525 const string bn_name = ClassName(interface, ClassNames::SERVER);
526 vector<string> include_list{
527 HeaderFile(interface, ClassNames::SERVER, false),
528 kParcelHeader
529 };
Christopher Wileyad339272015-10-05 19:11:58 -0700530 unique_ptr<MethodImpl> on_transact{new MethodImpl{
531 kAndroidStatusLiteral, bn_name, "onTransact",
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800532 ArgList{{StringPrintf("uint32_t %s", kCodeVarName),
533 StringPrintf("const %s& %s", kAndroidParcelLiteral,
534 kDataVarName),
535 StringPrintf("%s* %s", kAndroidParcelLiteral, kReplyVarName),
536 StringPrintf("uint32_t %s", kFlagsVarName)}}
Christopher Wiley36570f42015-10-08 17:20:11 -0700537 }};
Christopher Wileyad339272015-10-05 19:11:58 -0700538
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800539 // Declare the status_t variable
Christopher Wiley05f4f892015-10-14 13:30:43 -0700540 on_transact->GetStatementBlock()->AddLiteral(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800541 StringPrintf("%s %s", kAndroidStatusLiteral, kAndroidStatusVarName));
Christopher Wiley05f4f892015-10-14 13:30:43 -0700542
Christopher Wileyad339272015-10-05 19:11:58 -0700543 // Add the all important switch statement, but retain a pointer to it.
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800544 SwitchStatement* s = new SwitchStatement{kCodeVarName};
Christopher Wileyf9688b02015-10-08 17:17:50 -0700545 on_transact->GetStatementBlock()->AddStatement(s);
Christopher Wileyad339272015-10-05 19:11:58 -0700546
547 // The switch statement has a case statement for each transaction code.
Christopher Wiley054afbd2015-10-16 17:08:43 -0700548 for (const auto& method : interface.GetMethods()) {
Christopher Wileyad339272015-10-05 19:11:58 -0700549 StatementBlock* b = s->AddCase("Call::" + UpperCase(method->GetName()));
550 if (!b) { return nullptr; }
551
552 if (!HandleServerTransaction(types, *method, b)) { return nullptr; }
553 }
554
555 // The switch statement has a default case which defers to the super class.
556 // The superclass handles a few pre-defined transactions.
557 StatementBlock* b = s->AddCase("");
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800558 b->AddLiteral(StringPrintf(
559 "%s = ::android::BBinder::onTransact(%s, %s, "
560 "%s, %s)", kAndroidStatusVarName, kCodeVarName,
561 kDataVarName, kReplyVarName, kFlagsVarName));
Christopher Wileyad339272015-10-05 19:11:58 -0700562
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800563 // If we saw a null reference, we can map that to an appropriate exception.
564 IfStatement* null_check = new IfStatement(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800565 new LiteralExpression(string(kAndroidStatusVarName) +
566 " == ::android::UNEXPECTED_NULL"));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800567 on_transact->GetStatementBlock()->AddStatement(null_check);
568 null_check->OnTrue()->AddStatement(new Assignment(
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800569 kAndroidStatusVarName,
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800570 StringPrintf("%s::fromExceptionCode(%s::EX_NULL_POINTER)"
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800571 ".writeToParcel(%s)",
572 kBinderStatusLiteral, kBinderStatusLiteral,
573 kReplyVarName)));
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800574
Christopher Wileyad339272015-10-05 19:11:58 -0700575 // Finally, the server's onTransact method just returns a status code.
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800576 on_transact->GetStatementBlock()->AddLiteral(
577 StringPrintf("return %s", kAndroidStatusVarName));
Christopher Wileyad339272015-10-05 19:11:58 -0700578
579 return unique_ptr<Document>{new CppSource{
580 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700581 NestInNamespaces(std::move(on_transact), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700582}
583
Christopher Wileyf59c4992015-10-08 13:12:44 -0700584unique_ptr<Document> BuildInterfaceSource(const TypeNamespace& /* types */,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700585 const AidlInterface& interface) {
586 vector<string> include_list{
587 HeaderFile(interface, ClassNames::INTERFACE, false),
588 HeaderFile(interface, ClassNames::CLIENT, false),
589 };
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700590
Christopher Wiley054afbd2015-10-16 17:08:43 -0700591 string fq_name = ClassName(interface, ClassNames::INTERFACE);
592 if (!interface.GetPackage().empty()) {
593 fq_name = interface.GetPackage() + "." + fq_name;
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700594 }
595
596 unique_ptr<ConstructorDecl> meta_if{new ConstructorDecl{
597 "IMPLEMENT_META_INTERFACE",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700598 ArgList{vector<string>{ClassName(interface, ClassNames::BASE),
Christopher Wileyade4b452015-10-10 11:06:03 -0700599 '"' + fq_name + '"'}}}};
Christopher Wiley1dd458d2015-09-30 11:05:52 -0700600
601 return unique_ptr<Document>{new CppSource{
602 include_list,
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700603 NestInNamespaces(std::move(meta_if), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700604}
605
Christopher Wileye3550c62015-09-29 13:26:10 -0700606unique_ptr<Document> BuildClientHeader(const TypeNamespace& types,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700607 const AidlInterface& interface) {
608 const string i_name = ClassName(interface, ClassNames::INTERFACE);
609 const string bp_name = ClassName(interface, ClassNames::CLIENT);
Casey Dahlina834dd42015-09-23 11:52:15 -0700610
Christopher Wileyb23149d2015-10-14 13:52:21 -0700611 unique_ptr<ConstructorDecl> constructor{new ConstructorDecl{
612 bp_name,
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800613 ArgList{StringPrintf("const ::android::sp<::android::IBinder>& %s",
614 kImplVarName)},
Christopher Wileyb23149d2015-10-14 13:52:21 -0700615 ConstructorDecl::IS_EXPLICIT
616 }};
617 unique_ptr<ConstructorDecl> destructor{new ConstructorDecl{
618 "~" + bp_name,
619 ArgList{},
620 ConstructorDecl::IS_VIRTUAL | ConstructorDecl::IS_DEFAULT}};
Casey Dahlina834dd42015-09-23 11:52:15 -0700621
Christopher Wileyf944e792015-09-29 10:00:46 -0700622 vector<unique_ptr<Declaration>> publics;
Casey Dahlina834dd42015-09-23 11:52:15 -0700623 publics.push_back(std::move(constructor));
624 publics.push_back(std::move(destructor));
625
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700626 for (const auto& method: interface.GetMethods()) {
Christopher Wiley36570f42015-10-08 17:20:11 -0700627 publics.push_back(BuildMethodDecl(*method, types, false));
Casey Dahlina834dd42015-09-23 11:52:15 -0700628 }
629
Christopher Wileyf944e792015-09-29 10:00:46 -0700630 unique_ptr<ClassDecl> bp_class{
631 new ClassDecl{bp_name,
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800632 "::android::BpInterface<" + i_name + ">",
Christopher Wileyf944e792015-09-29 10:00:46 -0700633 std::move(publics),
634 {}
Casey Dahlina834dd42015-09-23 11:52:15 -0700635 }};
636
Christopher Wiley0c732db2015-09-29 14:36:44 -0700637 return unique_ptr<Document>{new CppHeader{
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700638 BuildHeaderGuard(interface, ClassNames::CLIENT),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700639 {kIBinderHeader,
640 kIInterfaceHeader,
641 "utils/Errors.h",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700642 HeaderFile(interface, ClassNames::INTERFACE, false)},
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700643 NestInNamespaces(std::move(bp_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700644}
645
Christopher Wileyf59c4992015-10-08 13:12:44 -0700646unique_ptr<Document> BuildServerHeader(const TypeNamespace& /* types */,
Christopher Wileyfd51d602015-10-14 13:04:48 -0700647 const AidlInterface& interface) {
648 const string i_name = ClassName(interface, ClassNames::INTERFACE);
649 const string bn_name = ClassName(interface, ClassNames::SERVER);
Casey Dahlin082f1d12015-09-21 14:06:25 -0700650
Christopher Wileyfd51d602015-10-14 13:04:48 -0700651 unique_ptr<Declaration> on_transact{new MethodDecl{
Christopher Wileyade4b452015-10-10 11:06:03 -0700652 kAndroidStatusLiteral, "onTransact",
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800653 ArgList{{StringPrintf("uint32_t %s", kCodeVarName),
654 StringPrintf("const %s& %s", kAndroidParcelLiteral,
655 kDataVarName),
656 StringPrintf("%s* %s", kAndroidParcelLiteral, kReplyVarName),
657 StringPrintf("uint32_t %s = 0", kFlagsVarName)}},
Christopher Wileyfd51d602015-10-14 13:04:48 -0700658 MethodDecl::IS_OVERRIDE
659 }};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700660
Christopher Wileyf944e792015-09-29 10:00:46 -0700661 std::vector<unique_ptr<Declaration>> publics;
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700662 publics.push_back(std::move(on_transact));
663
Christopher Wileyf944e792015-09-29 10:00:46 -0700664 unique_ptr<ClassDecl> bn_class{
665 new ClassDecl{bn_name,
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800666 "::android::BnInterface<" + i_name + ">",
Christopher Wileyf944e792015-09-29 10:00:46 -0700667 std::move(publics),
668 {}
Casey Dahlinb7d0f7f2015-09-22 17:21:08 -0700669 }};
Casey Dahlin082f1d12015-09-21 14:06:25 -0700670
Christopher Wiley0c732db2015-09-29 14:36:44 -0700671 return unique_ptr<Document>{new CppHeader{
Christopher Wileyfd51d602015-10-14 13:04:48 -0700672 BuildHeaderGuard(interface, ClassNames::SERVER),
Christopher Wiley0c732db2015-09-29 14:36:44 -0700673 {"binder/IInterface.h",
Christopher Wiley054afbd2015-10-16 17:08:43 -0700674 HeaderFile(interface, ClassNames::INTERFACE, false)},
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700675 NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700676}
677
Christopher Wileye3550c62015-09-29 13:26:10 -0700678unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700679 const AidlInterface& interface) {
Casey Dahlin389781f2015-10-22 13:13:21 -0700680 set<string> includes = { kIBinderHeader, kIInterfaceHeader,
Christopher Wiley433c8bb2015-11-12 14:20:46 -0800681 kStatusHeader, kStrongPointerHeader };
Casey Dahlince776cf2015-10-15 18:45:54 -0700682
683 for (const auto& method : interface.GetMethods()) {
684 for (const auto& argument : method->GetArguments()) {
685 const Type* type = types.Find(argument->GetType().GetName());
Christopher Wiley8a657972015-10-28 16:03:45 -0700686 type->GetHeaders(argument->GetType().IsArray(), &includes);
Casey Dahlince776cf2015-10-15 18:45:54 -0700687 }
688
Christopher Wiley8a657972015-10-28 16:03:45 -0700689 const Type* return_type = types.Find(method->GetType().GetName());
690 return_type->GetHeaders(method->GetType().IsArray(), &includes);
Casey Dahlince776cf2015-10-15 18:45:54 -0700691 }
692
Christopher Wiley0c732db2015-09-29 14:36:44 -0700693 unique_ptr<ClassDecl> if_class{
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700694 new ClassDecl{ClassName(interface, ClassNames::INTERFACE),
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800695 "::android::IInterface"}};
Christopher Wileyade4b452015-10-10 11:06:03 -0700696 if_class->AddPublic(unique_ptr<Declaration>{new ConstructorDecl{
697 "DECLARE_META_INTERFACE",
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700698 ArgList{vector<string>{ClassName(interface, ClassNames::BASE)}}}});
Christopher Wiley0c732db2015-09-29 14:36:44 -0700699
Casey Dahlind40e2fe2015-11-24 14:06:52 -0800700 for (const auto& constant : interface.GetConstants()) {
701 unique_ptr<ConstDecl> declaration{
702 new ConstDecl(constant->GetName(), constant->GetValue())};
703 if_class->AddPublic(std::move(declaration));
704 }
705
Christopher Wiley0c732db2015-09-29 14:36:44 -0700706 unique_ptr<Enum> call_enum{new Enum{"Call"}};
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700707 for (const auto& method : interface.GetMethods()) {
708 // Each method gets an enum entry and pure virtual declaration.
Casey Dahlin5c69deb2015-10-01 14:44:12 -0700709 if_class->AddPublic(BuildMethodDecl(*method, types, true));
Christopher Wiley0c732db2015-09-29 14:36:44 -0700710 call_enum->AddValue(
Casey Dahlinf4a93112015-10-05 16:58:09 -0700711 UpperCase(method->GetName()),
Casey Dahlinb8d9e882015-11-24 10:57:23 -0800712 StringPrintf("::android::IBinder::FIRST_CALL_TRANSACTION + %d",
Casey Dahlinf4a93112015-10-05 16:58:09 -0700713 method->GetId()));
Christopher Wiley0c732db2015-09-29 14:36:44 -0700714 }
715 if_class->AddPublic(std::move(call_enum));
716
Christopher Wiley3bb6bc12015-10-14 10:58:27 -0700717 return unique_ptr<Document>{new CppHeader{
718 BuildHeaderGuard(interface, ClassNames::INTERFACE),
Casey Dahlince776cf2015-10-15 18:45:54 -0700719 vector<string>(includes.begin(), includes.end()),
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700720 NestInNamespaces(std::move(if_class), interface.GetSplitPackage())}};
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700721}
722
Christopher Wiley054afbd2015-10-16 17:08:43 -0700723bool WriteHeader(const CppOptions& options,
724 const TypeNamespace& types,
725 const AidlInterface& interface,
726 const IoDelegate& io_delegate,
727 ClassNames header_type) {
728 unique_ptr<Document> header;
729 switch (header_type) {
730 case ClassNames::INTERFACE:
731 header = BuildInterfaceHeader(types, interface);
732 break;
733 case ClassNames::CLIENT:
734 header = BuildClientHeader(types, interface);
735 break;
736 case ClassNames::SERVER:
737 header = BuildServerHeader(types, interface);
738 break;
739 default:
740 LOG(FATAL) << "aidl internal error";
741 }
742 if (!header) {
743 LOG(ERROR) << "aidl internal error: Failed to generate header.";
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700744 return false;
745 }
Christopher Wiley054afbd2015-10-16 17:08:43 -0700746
Christopher Wiley9d6e0b22015-11-13 12:18:16 -0800747 const string header_path = options.OutputHeaderDir() + OS_PATH_SEPARATOR +
748 HeaderFile(interface, header_type);
749 unique_ptr<CodeWriter> code_writer(io_delegate.GetCodeWriter(header_path));
750 header->Write(code_writer.get());
Christopher Wiley054afbd2015-10-16 17:08:43 -0700751
Christopher Wiley9d6e0b22015-11-13 12:18:16 -0800752 const bool success = code_writer->Close();
753 if (!success) {
754 io_delegate.RemovePath(header_path);
755 }
756
757 return success;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700758}
759
Casey Dahlina834dd42015-09-23 11:52:15 -0700760} // namespace internals
761
762using namespace internals;
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700763
Christopher Wileye3550c62015-09-29 13:26:10 -0700764bool GenerateCpp(const CppOptions& options,
765 const TypeNamespace& types,
Christopher Wiley054afbd2015-10-16 17:08:43 -0700766 const AidlInterface& interface,
767 const IoDelegate& io_delegate) {
768 auto interface_src = BuildInterfaceSource(types, interface);
769 auto client_src = BuildClientSource(types, interface);
770 auto server_src = BuildServerSource(types, interface);
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700771
Christopher Wiley054afbd2015-10-16 17:08:43 -0700772 if (!interface_src || !client_src || !server_src) {
773 return false;
774 }
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700775
Christopher Wiley054afbd2015-10-16 17:08:43 -0700776 if (!io_delegate.CreatedNestedDirs(options.OutputHeaderDir(),
Christopher Wileyb656a3b2015-10-16 11:11:09 -0700777 interface.GetSplitPackage())) {
Christopher Wiley054afbd2015-10-16 17:08:43 -0700778 LOG(ERROR) << "Failed to create directory structure for headers.";
779 return false;
780 }
781
782 if (!WriteHeader(options, types, interface, io_delegate,
783 ClassNames::INTERFACE) ||
784 !WriteHeader(options, types, interface, io_delegate,
785 ClassNames::CLIENT) ||
786 !WriteHeader(options, types, interface, io_delegate,
787 ClassNames::SERVER)) {
788 return false;
789 }
790
Christopher Wiley054afbd2015-10-16 17:08:43 -0700791 unique_ptr<CodeWriter> writer = io_delegate.GetCodeWriter(
792 options.OutputCppFilePath());
793 interface_src->Write(writer.get());
794 client_src->Write(writer.get());
795 server_src->Write(writer.get());
796
Christopher Wiley9d6e0b22015-11-13 12:18:16 -0800797 const bool success = writer->Close();
798 if (!success) {
799 io_delegate.RemovePath(options.OutputCppFilePath());
800 }
801
802 return success;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700803}
804
Christopher Wileyf944e792015-09-29 10:00:46 -0700805} // namespace cpp
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700806} // namespace aidl
Christopher Wileyf944e792015-09-29 10:00:46 -0700807} // namespace android