blob: ffa67117fd9f1f9b503d66fc06276e88591acdc3 [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andreas Huber881227d2016-08-02 14:20:21 -070017#include "AST.h"
18
19#include "Coordinator.h"
Iliyan Malchev40d474a2016-08-16 06:20:17 -070020#include "EnumType.h"
Andreas Huber881227d2016-08-02 14:20:21 -070021#include "Interface.h"
22#include "Method.h"
Iliyan Malchev40d474a2016-08-16 06:20:17 -070023#include "ScalarType.h"
Andreas Huber881227d2016-08-02 14:20:21 -070024#include "Scope.h"
25
Andreas Huberdca261f2016-08-04 13:47:51 -070026#include <algorithm>
Iliyan Malcheva72e0d22016-09-09 11:03:08 -070027#include <hidl-util/Formatter.h>
Andreas Huber881227d2016-08-02 14:20:21 -070028#include <android-base/logging.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070029#include <string>
Andreas Huber881227d2016-08-02 14:20:21 -070030#include <vector>
31
32namespace android {
33
Andreas Huberb82318c2016-08-02 14:45:54 -070034status_t AST::generateCpp(const std::string &outputPath) const {
35 status_t err = generateInterfaceHeader(outputPath);
Andreas Huber881227d2016-08-02 14:20:21 -070036
37 if (err == OK) {
Andreas Huberb82318c2016-08-02 14:45:54 -070038 err = generateStubHeader(outputPath);
Andreas Huber881227d2016-08-02 14:20:21 -070039 }
40
41 if (err == OK) {
Steven Moreland40786312016-08-16 10:29:40 -070042 err = generateHwBinderHeader(outputPath);
43 }
44
45 if (err == OK) {
Andreas Huberb82318c2016-08-02 14:45:54 -070046 err = generateProxyHeader(outputPath);
Andreas Huber881227d2016-08-02 14:20:21 -070047 }
48
49 if (err == OK) {
Andreas Huberb82318c2016-08-02 14:45:54 -070050 err = generateAllSource(outputPath);
Andreas Huber881227d2016-08-02 14:20:21 -070051 }
52
Steven Moreland69e7c702016-09-09 11:16:32 -070053 if (err == OK) {
54 generatePassthroughHeader(outputPath);
55 }
56
Andreas Huber881227d2016-08-02 14:20:21 -070057 return err;
58}
59
Andreas Huber737080b2016-08-02 15:38:04 -070060void AST::getPackageComponents(
61 std::vector<std::string> *components) const {
Andreas Huber0e00de42016-08-03 09:56:02 -070062 mPackage.getPackageComponents(components);
Andreas Huber737080b2016-08-02 15:38:04 -070063}
64
65void AST::getPackageAndVersionComponents(
66 std::vector<std::string> *components, bool cpp_compatible) const {
Andreas Huber0e00de42016-08-03 09:56:02 -070067 mPackage.getPackageAndVersionComponents(components, cpp_compatible);
Andreas Huber737080b2016-08-02 15:38:04 -070068}
69
Andreas Huber881227d2016-08-02 14:20:21 -070070std::string AST::makeHeaderGuard(const std::string &baseName) const {
Steven Moreland9c387612016-09-07 09:54:26 -070071 std::string guard = "HIDL_GENERATED_";
72 guard += mPackage.tokenName();
Andreas Huber881227d2016-08-02 14:20:21 -070073
74 guard += "_";
75 guard += baseName;
76 guard += "_H_";
77
78 return guard;
79}
80
81void AST::enterLeaveNamespace(Formatter &out, bool enter) const {
82 std::vector<std::string> packageComponents;
83 getPackageAndVersionComponents(
84 &packageComponents, true /* cpp_compatible */);
85
86 if (enter) {
87 for (const auto &component : packageComponents) {
88 out << "namespace " << component << " {\n";
89 }
Andreas Huber0e00de42016-08-03 09:56:02 -070090
Andreas Huber2831d512016-08-15 09:33:47 -070091 out.setNamespace(mPackage.cppNamespace() + "::");
Andreas Huber881227d2016-08-02 14:20:21 -070092 } else {
Andreas Huber0e00de42016-08-03 09:56:02 -070093 out.setNamespace(std::string());
94
Andreas Huber881227d2016-08-02 14:20:21 -070095 for (auto it = packageComponents.rbegin();
96 it != packageComponents.rend();
97 ++it) {
98 out << "} // namespace " << *it << "\n";
99 }
100 }
101}
102
Andreas Huberb82318c2016-08-02 14:45:54 -0700103status_t AST::generateInterfaceHeader(const std::string &outputPath) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700104
Andreas Huberb82318c2016-08-02 14:45:54 -0700105 std::string path = outputPath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700106 path.append(mCoordinator->convertPackageRootToPath(mPackage));
Andreas Huberdca261f2016-08-04 13:47:51 -0700107 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
Andreas Huber881227d2016-08-02 14:20:21 -0700108
109 std::string ifaceName;
110 bool isInterface = true;
111 if (!AST::isInterface(&ifaceName)) {
112 ifaceName = "types";
113 isInterface = false;
114 }
115 path.append(ifaceName);
116 path.append(".h");
117
Andreas Huberd2943e12016-08-05 11:59:31 -0700118 CHECK(Coordinator::MakeParentHierarchy(path));
Andreas Huber881227d2016-08-02 14:20:21 -0700119 FILE *file = fopen(path.c_str(), "w");
120
121 if (file == NULL) {
122 return -errno;
123 }
124
125 Formatter out(file);
126
127 const std::string guard = makeHeaderGuard(ifaceName);
128
129 out << "#ifndef " << guard << "\n";
130 out << "#define " << guard << "\n\n";
131
Andreas Huber737080b2016-08-02 15:38:04 -0700132 for (const auto &item : mImportedNames) {
133 out << "#include <";
134
135 std::vector<std::string> components;
Andreas Huber0e00de42016-08-03 09:56:02 -0700136 item.getPackageAndVersionComponents(
137 &components, false /* cpp_compatible */);
Andreas Huber737080b2016-08-02 15:38:04 -0700138
139 for (const auto &component : components) {
140 out << component << "/";
141 }
142
143 out << item.name()
144 << ".h>\n";
145 }
146
147 if (!mImportedNames.empty()) {
148 out << "\n";
149 }
150
Martijn Coenen7473fab2016-08-19 14:05:40 +0200151 out << "#include <hidl/HidlSupport.h>\n";
Steven Moreland40786312016-08-16 10:29:40 -0700152 out << "#include <hidl/IServiceManager.h>\n";
Andreas Huber4bcf97d2016-08-30 11:27:49 -0700153 out << "#include <hidl/MQDescriptor.h>\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700154
155 if (isInterface) {
Martijn Coenen93915102016-09-01 01:35:52 +0200156 out << "#include <hidl/Status.h>\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700157 }
158
159 out << "#include <utils/NativeHandle.h>\n\n";
160
161 enterLeaveNamespace(out, true /* enter */);
162 out << "\n";
163
164 if (isInterface) {
165 out << "struct "
Steven Moreland40786312016-08-16 10:29:40 -0700166 << ifaceName;
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700167
168 const Interface *iface = mRootScope->getInterface();
169 const Interface *superType = iface->superType();
170
Steven Moreland40786312016-08-16 10:29:40 -0700171 if (superType == NULL) {
Yifan Hong10fe0b52016-10-19 14:20:17 -0700172 out << " : virtual public IHidlInterfaceBase";
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700173 } else {
Steven Morelandd916a702016-10-26 22:23:09 +0000174 out << " : public "
Steven Moreland40786312016-08-16 10:29:40 -0700175 << superType->fullName();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700176 }
177
178 out << " {\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700179
180 out.indent();
181
Andreas Huber881227d2016-08-02 14:20:21 -0700182 }
183
184 status_t err = emitTypeDeclarations(out);
185
186 if (err != OK) {
187 return err;
188 }
189
190 if (isInterface) {
191 const Interface *iface = mRootScope->getInterface();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700192 const Interface *superType = iface->superType();
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700193 const std::string baseName = iface->getBaseName();
Martijn Coenena21f1492016-09-08 15:55:14 +0200194 out << "constexpr static hidl_version version = {"
195 << mPackage.getPackageMajorVersion() << ","
196 << mPackage.getPackageMinorVersion() << "};\n";
197 out << "virtual const hidl_version& getInterfaceVersion() const {\n";
198 out.indent();
199 out << "return version;\n";
200 out.unindent();
201 out << "}\n\n";
Yifan Hong10fe0b52016-10-19 14:20:17 -0700202 out << "virtual bool isRemote() const override { return false; }\n\n";
Yifan Hong2d7126b2016-10-20 15:12:57 -0700203 out << "virtual ::android::sp<::android::hardware::IBinder> "
204 << "toBinder() override;\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700205 bool haveCallbacks = false;
206 for (const auto &method : iface->methods()) {
207 const bool returnsValue = !method->results().empty();
208
209 if (!returnsValue) {
210 continue;
211 }
212
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700213 if (method->canElideCallback() != nullptr) {
214 continue;
215 }
216
Andreas Huber881227d2016-08-02 14:20:21 -0700217 haveCallbacks = true;
218
219 out << "using "
220 << method->name()
221 << "_cb = std::function<void("
Steven Moreland979e0992016-09-07 09:18:08 -0700222 << Method::GetArgSignature(method->results(),
223 true /* specify namespaces */)
Andreas Huber881227d2016-08-02 14:20:21 -0700224 << ")>;\n";
225 }
226
227 if (haveCallbacks) {
228 out << "\n";
229 }
230
231 for (const auto &method : iface->methods()) {
232 const bool returnsValue = !method->results().empty();
233
Andreas Huber3599d922016-08-09 10:42:57 -0700234 method->dumpAnnotations(out);
235
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700236 const TypedVar *elidedReturn = method->canElideCallback();
237 if (elidedReturn) {
238 std::string extra;
Iliyan Malchev2b6591b2016-08-18 19:15:19 -0700239 out << "virtual ::android::hardware::Return<";
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700240 out << elidedReturn->type().getCppResultType(&extra) << "> ";
241 } else {
Iliyan Malchevd57066f2016-09-08 13:59:38 -0700242 out << "virtual ::android::hardware::Return<void> ";
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700243 }
244
245 out << method->name()
Andreas Huber881227d2016-08-02 14:20:21 -0700246 << "("
Steven Moreland979e0992016-09-07 09:18:08 -0700247 << Method::GetArgSignature(method->args(),
248 true /* specify namespaces */);
Andreas Huber881227d2016-08-02 14:20:21 -0700249
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700250 if (returnsValue && elidedReturn == nullptr) {
Andreas Huber881227d2016-08-02 14:20:21 -0700251 if (!method->args().empty()) {
252 out << ", ";
253 }
254
Steven Moreland67f67b42016-09-29 08:59:02 -0700255 out << method->name() << "_cb _hidl_cb";
Andreas Huber881227d2016-08-02 14:20:21 -0700256 }
257
Yifan Hong10fe0b52016-10-19 14:20:17 -0700258 out << ")";
259 if (method->isHidlReserved()) {
260 out << " override";
261 out << " {\n";
262 out.indent();
263 method->cppImpl(out);
264 out.unindent();
265 out << "\n}\n";
266 } else {
267 out << " = 0;\n";
268 }
Andreas Huber881227d2016-08-02 14:20:21 -0700269 }
Steven Moreland40786312016-08-16 10:29:40 -0700270
Yifan Hongfe95aa22016-10-19 17:26:45 -0700271 if (!iface->isRootType()) {
272 out << "// cast static functions\n";
273 std::string childTypeExtra;
274 std::string childTypeResult = iface->getCppResultType(&childTypeExtra);
275 childTypeResult += childTypeExtra;
276
277 for (const Interface *superType : iface->superTypeChain()) {
278 std::string superTypeExtra;
279 out << "static "
280 << childTypeResult
281 << " castFrom("
282 << superType->getCppArgumentType(&superTypeExtra)
283 << " parent"
284 << superTypeExtra
285 << ");\n";
286 }
287 }
288
Yifan Hong10fe0b52016-10-19 14:20:17 -0700289 out << "\nstatic const ::android::String16 descriptor;\n\n";
290
Steven Moreland40786312016-08-16 10:29:40 -0700291 out << "DECLARE_REGISTER_AND_GET_SERVICE(" << baseName << ")\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700292 }
293
294 if (isInterface) {
295 out.unindent();
296
Andreas Hubere3f769a2016-10-10 10:54:44 -0700297 out << "};\n\n";
298 }
299
300 err = mRootScope->emitGlobalTypeDeclarations(out);
301
302 if (err != OK) {
303 return err;
Andreas Huber881227d2016-08-02 14:20:21 -0700304 }
305
306 out << "\n";
307 enterLeaveNamespace(out, false /* enter */);
308
309 out << "\n#endif // " << guard << "\n";
310
311 return OK;
312}
313
Steven Moreland40786312016-08-16 10:29:40 -0700314status_t AST::generateHwBinderHeader(const std::string &outputPath) const {
315 std::string ifaceName;
316 if(!AST::isInterface(&ifaceName)) {
317 // types.hal does not get an HwBinder header.
318 return OK;
319 }
320
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700321 const Interface *iface = mRootScope->getInterface();
322 const std::string baseName = iface->getBaseName();
Steven Moreland40786312016-08-16 10:29:40 -0700323
324 const std::string klassName = "IHw" + baseName;
325
326 std::string path = outputPath;
327 path.append(mCoordinator->convertPackageRootToPath(mPackage));
328 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
329 path.append(klassName + ".h");
330
331 FILE* file = fopen(path.c_str(), "w");
332
333 if (file == NULL) {
334 return -errno;
335 }
336
337 Formatter out(file);
338
339 const std::string guard = makeHeaderGuard(klassName);
340
341 out << "#ifndef " << guard << "\n";
342 out << "#define " << guard << "\n\n";
343
344 std::vector<std::string> packageComponents;
345 getPackageAndVersionComponents(
346 &packageComponents, false /* cpp_compatible */);
347
348 out << "#include <";
349 for (const auto &component : packageComponents) {
350 out << component << "/";
351 }
352 out << ifaceName << ".h>\n\n";
353
354 for (const auto &item : mImportedNames) {
355 if (item.name() == "types") {
356 continue;
357 }
358
359 out << "#include <";
360
361 std::vector<std::string> components;
362 item.getPackageAndVersionComponents(
363 &components, false /* cpp_compatible */);
364
365 for (const auto &component : components) {
366 out << component << "/";
367 }
368
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700369 const std::string itemBaseName = item.getInterfaceBaseName();
Steven Moreland40786312016-08-16 10:29:40 -0700370
371 out << "Bn"
372 << itemBaseName
373 << ".h>\n";
374 }
375
376 out << "\n";
377
378 out << "#include <hidl/HidlSupport.h>\n";
Martijn Coenen93915102016-09-01 01:35:52 +0200379 out << "#include <hidl/Status.h>\n";
Steven Moreland40786312016-08-16 10:29:40 -0700380 out << "#include <hwbinder/IBinder.h>\n";
381 out << "#include <hwbinder/IInterface.h>\n";
Steven Moreland40786312016-08-16 10:29:40 -0700382
383 out << "\n";
384
385 enterLeaveNamespace(out, true /* enter */);
386 out << "\n";
387
388 out << "struct "
389 << klassName
390 << " : public "
391 << ifaceName;
392
Steven Moreland40786312016-08-16 10:29:40 -0700393 const Interface *superType = iface->superType();
394
395 out << ", public ::android::hardware::IInterface";
396
397 out << " {\n";
398
399 out.indent();
400
401 out << "DECLARE_HWBINDER_META_INTERFACE(" << baseName << ");\n\n";
402
Steven Moreland40786312016-08-16 10:29:40 -0700403 out.unindent();
404
405 out << "};\n\n";
406
407 enterLeaveNamespace(out, false /* enter */);
408
409 out << "\n#endif // " << guard << "\n";
410
411 return OK;
412}
413
Andreas Huber881227d2016-08-02 14:20:21 -0700414status_t AST::emitTypeDeclarations(Formatter &out) const {
415 return mRootScope->emitTypeDeclarations(out);
416}
417
Steven Morelanda7a421a2016-09-07 08:35:18 -0700418status_t AST::generateStubMethod(Formatter &out,
Yifan Hong068c5522016-10-31 14:07:25 -0700419 const Method *method) const {
Steven Morelanda7a421a2016-09-07 08:35:18 -0700420 out << "inline ";
421
Yifan Hong068c5522016-10-31 14:07:25 -0700422 method->generateCppSignature(out);
Steven Morelanda7a421a2016-09-07 08:35:18 -0700423
424 const bool returnsValue = !method->results().empty();
425 const TypedVar *elidedReturn = method->canElideCallback();
426 out << " {\n";
427 out.indent();
428 out << "return mImpl->"
429 << method->name()
430 << "(";
431 bool first = true;
432 for (const auto &arg : method->args()) {
433 if (!first) {
434 out << ", ";
435 }
436 first = false;
437 out << arg->name();
438 }
439 if (returnsValue && elidedReturn == nullptr) {
440 if (!method->args().empty()) {
441 out << ", ";
442 }
443
444 out << "_hidl_cb";
445 }
446 out << ");\n";
447 out.unindent();
448 out << "}";
449
450 out << ";\n";
451
452 return OK;
453}
454
Steven Moreland69e7c702016-09-09 11:16:32 -0700455status_t AST::generatePassthroughMethod(Formatter &out,
Yifan Hong068c5522016-10-31 14:07:25 -0700456 const Method *method) const {
457 method->generateCppSignature(out);
Steven Moreland69e7c702016-09-09 11:16:32 -0700458
459 out << " {\n";
460 out.indent();
461
462 const bool returnsValue = !method->results().empty();
463 const TypedVar *elidedReturn = method->canElideCallback();
464
Steven Moreland67f67b42016-09-29 08:59:02 -0700465 if (returnsValue && elidedReturn == nullptr) {
466 generateCheckNonNull(out, "_hidl_cb");
467 }
468
Steven Moreland69e7c702016-09-09 11:16:32 -0700469 out << "return ";
470
471 if (method->isOneway()) {
472 out << "addOnewayTask([this";
473 for (const auto &arg : method->args()) {
474 out << ", " << arg->name();
475 }
476 out << "] {this->";
477 }
478
479 out << "mImpl->"
480 << method->name()
481 << "(";
482
483 bool first = true;
484 for (const auto &arg : method->args()) {
485 if (!first) {
486 out << ", ";
487 }
488 first = false;
489 out << arg->name();
490 }
491 if (returnsValue && elidedReturn == nullptr) {
492 if (!method->args().empty()) {
493 out << ", ";
494 }
495
496 out << "_hidl_cb";
497 }
498 out << ")";
499
500 if (method->isOneway()) {
501 out << ";})";
502 }
503 out << ";\n";
504
505 out.unindent();
506 out << "}\n";
507
508 return OK;
509}
510
Yifan Hong068c5522016-10-31 14:07:25 -0700511status_t AST::generateMethods(Formatter &out, MethodGenerator gen) const {
Steven Morelanda7a421a2016-09-07 08:35:18 -0700512
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700513 const Interface *iface = mRootScope->getInterface();
514
Yifan Hong10fe0b52016-10-19 14:20:17 -0700515 const Interface *prevIterface = nullptr;
516 for (const auto &tuple : iface->allMethodsFromRoot()) {
517 const Method *method = tuple.method();
518 const Interface *superInterface = tuple.interface();
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700519
Yifan Hong10fe0b52016-10-19 14:20:17 -0700520 if(prevIterface != superInterface) {
521 if (prevIterface != nullptr) {
522 out << "\n";
523 }
524 out << "// Methods from "
525 << superInterface->fullName()
526 << " follow.\n";
527 prevIterface = superInterface;
528 }
Yifan Hong068c5522016-10-31 14:07:25 -0700529 status_t err = gen(method, superInterface);
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700530
Yifan Hong10fe0b52016-10-19 14:20:17 -0700531 if (err != OK) {
532 return err;
533 }
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700534 }
535
Yifan Hong10fe0b52016-10-19 14:20:17 -0700536 out << "\n";
537
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700538 return OK;
539}
540
Andreas Huberb82318c2016-08-02 14:45:54 -0700541status_t AST::generateStubHeader(const std::string &outputPath) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700542 std::string ifaceName;
543 if (!AST::isInterface(&ifaceName)) {
544 // types.hal does not get a stub header.
545 return OK;
546 }
547
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700548 const Interface *iface = mRootScope->getInterface();
549 const std::string baseName = iface->getBaseName();
Steven Moreland40786312016-08-16 10:29:40 -0700550 const std::string klassName = "Bn" + baseName;
Andreas Huber881227d2016-08-02 14:20:21 -0700551
Andreas Huberb82318c2016-08-02 14:45:54 -0700552 std::string path = outputPath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700553 path.append(mCoordinator->convertPackageRootToPath(mPackage));
Andreas Huberdca261f2016-08-04 13:47:51 -0700554 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
Steven Moreland40786312016-08-16 10:29:40 -0700555 path.append(klassName);
Andreas Huber881227d2016-08-02 14:20:21 -0700556 path.append(".h");
557
Andreas Huberd2943e12016-08-05 11:59:31 -0700558 CHECK(Coordinator::MakeParentHierarchy(path));
Andreas Huber881227d2016-08-02 14:20:21 -0700559 FILE *file = fopen(path.c_str(), "w");
560
561 if (file == NULL) {
562 return -errno;
563 }
564
565 Formatter out(file);
566
Steven Moreland40786312016-08-16 10:29:40 -0700567 const std::string guard = makeHeaderGuard(klassName);
Andreas Huber881227d2016-08-02 14:20:21 -0700568
569 out << "#ifndef " << guard << "\n";
570 out << "#define " << guard << "\n\n";
571
572 std::vector<std::string> packageComponents;
573 getPackageAndVersionComponents(
574 &packageComponents, false /* cpp_compatible */);
575
576 out << "#include <";
577 for (const auto &component : packageComponents) {
578 out << component << "/";
579 }
Steven Moreland40786312016-08-16 10:29:40 -0700580 out << "IHw" << baseName << ".h>\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700581
582 enterLeaveNamespace(out, true /* enter */);
583 out << "\n";
584
585 out << "struct "
586 << "Bn"
587 << baseName
Steven Moreland40786312016-08-16 10:29:40 -0700588 << " : public ::android::hardware::BnInterface<I"
589 << baseName << ", IHw" << baseName
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -0700590 << ">, public ::android::hardware::HidlInstrumentor {\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700591
592 out.indent();
Steven Moreland40786312016-08-16 10:29:40 -0700593 out << "explicit Bn"
594 << baseName
595 << "(const ::android::sp<" << ifaceName << "> &_hidl_impl);"
596 << "\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700597 out << "::android::status_t onTransact(\n";
598 out.indent();
599 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -0700600 out << "uint32_t _hidl_code,\n";
601 out << "const ::android::hardware::Parcel &_hidl_data,\n";
602 out << "::android::hardware::Parcel *_hidl_reply,\n";
603 out << "uint32_t _hidl_flags = 0,\n";
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700604 out << "TransactCallback _hidl_cb = nullptr) override;\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700605 out.unindent();
606 out.unindent();
607
Yifan Hong068c5522016-10-31 14:07:25 -0700608 status_t err = generateMethods(out, [&](const Method *method, const Interface *) {
609 return generateStubMethod(out, method);
610 });
Steven Moreland9c387612016-09-07 09:54:26 -0700611
612 if (err != OK) {
613 return err;
614 }
615
Zhuoyao Zhangde578002016-09-07 18:24:17 -0700616
Andreas Huber881227d2016-08-02 14:20:21 -0700617 out.unindent();
Andreas Huber881227d2016-08-02 14:20:21 -0700618 out << "};\n\n";
619
620 enterLeaveNamespace(out, false /* enter */);
621
622 out << "\n#endif // " << guard << "\n";
623
624 return OK;
625}
626
Andreas Huberb82318c2016-08-02 14:45:54 -0700627status_t AST::generateProxyHeader(const std::string &outputPath) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700628 std::string ifaceName;
629 if (!AST::isInterface(&ifaceName)) {
630 // types.hal does not get a proxy header.
631 return OK;
632 }
633
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700634 const Interface *iface = mRootScope->getInterface();
635 const std::string baseName = iface->getBaseName();
Andreas Huber881227d2016-08-02 14:20:21 -0700636
Andreas Huberb82318c2016-08-02 14:45:54 -0700637 std::string path = outputPath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700638 path.append(mCoordinator->convertPackageRootToPath(mPackage));
Andreas Huberdca261f2016-08-04 13:47:51 -0700639 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
Andreas Huber881227d2016-08-02 14:20:21 -0700640 path.append("Bp");
641 path.append(baseName);
642 path.append(".h");
643
Andreas Huberd2943e12016-08-05 11:59:31 -0700644 CHECK(Coordinator::MakeParentHierarchy(path));
Andreas Huber881227d2016-08-02 14:20:21 -0700645 FILE *file = fopen(path.c_str(), "w");
646
647 if (file == NULL) {
648 return -errno;
649 }
650
651 Formatter out(file);
652
653 const std::string guard = makeHeaderGuard("Bp" + baseName);
654
655 out << "#ifndef " << guard << "\n";
656 out << "#define " << guard << "\n\n";
657
658 std::vector<std::string> packageComponents;
659 getPackageAndVersionComponents(
660 &packageComponents, false /* cpp_compatible */);
661
662 out << "#include <";
663 for (const auto &component : packageComponents) {
664 out << component << "/";
665 }
Steven Moreland40786312016-08-16 10:29:40 -0700666 out << "IHw" << baseName << ".h>\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700667
668 enterLeaveNamespace(out, true /* enter */);
669 out << "\n";
670
671 out << "struct "
672 << "Bp"
673 << baseName
Steven Moreland40786312016-08-16 10:29:40 -0700674 << " : public ::android::hardware::BpInterface<IHw"
675 << baseName
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -0700676 << ">, public ::android::hardware::HidlInstrumentor {\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700677
678 out.indent();
679
680 out << "explicit Bp"
681 << baseName
Iliyan Malchev549e2592016-08-10 08:59:12 -0700682 << "(const ::android::sp<::android::hardware::IBinder> &_hidl_impl);"
Andreas Huber881227d2016-08-02 14:20:21 -0700683 << "\n\n";
684
Yifan Hong10fe0b52016-10-19 14:20:17 -0700685 out << "virtual bool isRemote() const override { return true; }\n\n";
Steven Moreland40786312016-08-16 10:29:40 -0700686
Yifan Hong068c5522016-10-31 14:07:25 -0700687 status_t err = generateMethods(out, [&](const Method *method, const Interface *) {
688 method->generateCppSignature(out);
689 out << " override;\n";
690 return OK;
691 });
Steven Moreland9c387612016-09-07 09:54:26 -0700692
693 if (err != OK) {
694 return err;
695 }
Andreas Huber881227d2016-08-02 14:20:21 -0700696
697 out.unindent();
Andreas Huber881227d2016-08-02 14:20:21 -0700698 out << "};\n\n";
699
700 enterLeaveNamespace(out, false /* enter */);
701
702 out << "\n#endif // " << guard << "\n";
703
704 return OK;
705}
706
Andreas Huberb82318c2016-08-02 14:45:54 -0700707status_t AST::generateAllSource(const std::string &outputPath) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700708
Andreas Huberb82318c2016-08-02 14:45:54 -0700709 std::string path = outputPath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700710 path.append(mCoordinator->convertPackageRootToPath(mPackage));
Andreas Huberdca261f2016-08-04 13:47:51 -0700711 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
Andreas Huber881227d2016-08-02 14:20:21 -0700712
713 std::string ifaceName;
714 std::string baseName;
715
Yifan Hongfe95aa22016-10-19 17:26:45 -0700716 const Interface *iface = nullptr;
717 bool isInterface;
Andreas Huber881227d2016-08-02 14:20:21 -0700718 if (!AST::isInterface(&ifaceName)) {
719 baseName = "types";
720 isInterface = false;
721 } else {
Yifan Hongfe95aa22016-10-19 17:26:45 -0700722 iface = mRootScope->getInterface();
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700723 baseName = iface->getBaseName();
Yifan Hongfe95aa22016-10-19 17:26:45 -0700724 isInterface = true;
Andreas Huber881227d2016-08-02 14:20:21 -0700725 }
726
727 path.append(baseName);
728
729 if (baseName != "types") {
730 path.append("All");
731 }
732
733 path.append(".cpp");
734
Andreas Huberd2943e12016-08-05 11:59:31 -0700735 CHECK(Coordinator::MakeParentHierarchy(path));
Andreas Huber881227d2016-08-02 14:20:21 -0700736 FILE *file = fopen(path.c_str(), "w");
737
738 if (file == NULL) {
739 return -errno;
740 }
741
742 Formatter out(file);
743
744 std::vector<std::string> packageComponents;
745 getPackageAndVersionComponents(
746 &packageComponents, false /* cpp_compatible */);
747
748 std::string prefix;
749 for (const auto &component : packageComponents) {
750 prefix += component;
751 prefix += "/";
752 }
753
754 if (isInterface) {
755 out << "#include <" << prefix << "/Bp" << baseName << ".h>\n";
756 out << "#include <" << prefix << "/Bn" << baseName << ".h>\n";
Steven Moreland69e7c702016-09-09 11:16:32 -0700757 out << "#include <" << prefix << "/Bs" << baseName << ".h>\n";
Yifan Hongfe95aa22016-10-19 17:26:45 -0700758
759 for (const Interface *superType : iface->superTypeChain()) {
760 std::vector<std::string> superPackageComponents;
761 superType->fqName().getPackageAndVersionComponents(&superPackageComponents, false /* cpp_compatible */);
762 std::string superPrefix;
763 for (const auto &component : superPackageComponents) {
764 superPrefix += component;
765 superPrefix += "/";
766 }
767 out << "#include <" << superPrefix << "/Bp" << superType->getBaseName() << ".h>\n";
768 }
Andreas Huber881227d2016-08-02 14:20:21 -0700769 } else {
770 out << "#include <" << prefix << "types.h>\n";
771 }
772
773 out << "\n";
774
775 enterLeaveNamespace(out, true /* enter */);
776 out << "\n";
777
778 status_t err = generateTypeSource(out, ifaceName);
779
780 if (err == OK && isInterface) {
Yifan Hong10fe0b52016-10-19 14:20:17 -0700781 const Interface *iface = mRootScope->getInterface();
Martijn Coenena21f1492016-09-08 15:55:14 +0200782 out << "constexpr hidl_version " << ifaceName << "::version;\n\n";
Yifan Hong10fe0b52016-10-19 14:20:17 -0700783
784 // need to be put here, generateStubSource is using this.
785 out << "const ::android::String16 I"
786 << iface->getBaseName()
787 << "::descriptor(\""
788 << iface->fqName().string()
789 << "\");\n\n";
790
Yifan Hongfe95aa22016-10-19 17:26:45 -0700791 err = generateInterfaceSource(out);
792 }
793
794 if (err == OK && isInterface) {
Andreas Huber881227d2016-08-02 14:20:21 -0700795 err = generateProxySource(out, baseName);
796 }
797
798 if (err == OK && isInterface) {
799 err = generateStubSource(out, baseName);
800 }
801
Steven Moreland40786312016-08-16 10:29:40 -0700802 if (err == OK && isInterface) {
Steven Moreland69e7c702016-09-09 11:16:32 -0700803 err = generatePassthroughSource(out);
804 }
805
806 if (err == OK && isInterface) {
Steven Moreland9c387612016-09-07 09:54:26 -0700807 const Interface *iface = mRootScope->getInterface();
808
809 out << "IMPLEMENT_REGISTER_AND_GET_SERVICE("
810 << baseName << ", "
811 << "\"" << iface->fqName().package()
Iliyan Malchev4923f932016-09-09 13:04:59 -0700812 << iface->fqName().version() << "-impl.so\""
Steven Moreland9c387612016-09-07 09:54:26 -0700813 << ")\n";
Steven Moreland40786312016-08-16 10:29:40 -0700814 }
815
Andreas Huber881227d2016-08-02 14:20:21 -0700816 enterLeaveNamespace(out, false /* enter */);
817
818 return err;
819}
820
Steven Moreland67f67b42016-09-29 08:59:02 -0700821// static
822void AST::generateCheckNonNull(Formatter &out, const std::string &nonNull) {
823 out << "if (" << nonNull << " == nullptr) {\n";
824 out.indent();
825 out << "return ::android::hardware::Status::fromExceptionCode(\n";
826 out.indent();
827 out.indent();
828 out << "::android::hardware::Status::EX_ILLEGAL_ARGUMENT);\n";
829 out.unindent();
830 out.unindent();
831 out.unindent();
832 out << "}\n\n";
833}
834
Andreas Huber881227d2016-08-02 14:20:21 -0700835status_t AST::generateTypeSource(
836 Formatter &out, const std::string &ifaceName) const {
837 return mRootScope->emitTypeDefinitions(out, ifaceName);
838}
839
Andreas Hubere7ff2282016-08-16 13:50:03 -0700840void AST::declareCppReaderLocals(
Andreas Huber5e44a292016-09-27 14:52:39 -0700841 Formatter &out,
842 const std::vector<TypedVar *> &args,
843 bool forResults) const {
Andreas Hubere7ff2282016-08-16 13:50:03 -0700844 if (args.empty()) {
845 return;
846 }
847
848 for (const auto &arg : args) {
849 const Type &type = arg->type();
850
851 std::string extra;
852 out << type.getCppResultType(&extra)
853 << " "
Andreas Huber5e44a292016-09-27 14:52:39 -0700854 << (forResults ? "_hidl_out_" : "")
Andreas Hubere7ff2282016-08-16 13:50:03 -0700855 << arg->name()
856 << extra
857 << ";\n";
858 }
859
860 out << "\n";
861}
862
Andreas Huber881227d2016-08-02 14:20:21 -0700863void AST::emitCppReaderWriter(
864 Formatter &out,
865 const std::string &parcelObj,
866 bool parcelObjIsPointer,
867 const TypedVar *arg,
868 bool isReader,
Andreas Huber5e44a292016-09-27 14:52:39 -0700869 Type::ErrorMode mode,
870 bool addPrefixToName) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700871 const Type &type = arg->type();
872
Andreas Huber881227d2016-08-02 14:20:21 -0700873 type.emitReaderWriter(
874 out,
Andreas Huber5e44a292016-09-27 14:52:39 -0700875 addPrefixToName ? ("_hidl_out_" + arg->name()) : arg->name(),
Andreas Huber881227d2016-08-02 14:20:21 -0700876 parcelObj,
877 parcelObjIsPointer,
878 isReader,
879 mode);
880}
881
Yifan Hongbf459bc2016-08-23 16:50:37 -0700882void AST::emitCppResolveReferences(
883 Formatter &out,
884 const std::string &parcelObj,
885 bool parcelObjIsPointer,
886 const TypedVar *arg,
887 bool isReader,
888 Type::ErrorMode mode,
889 bool addPrefixToName) const {
890 const Type &type = arg->type();
891 if(type.needsResolveReferences()) {
892 type.emitResolveReferences(
893 out,
894 addPrefixToName ? ("_hidl_out_" + arg->name()) : arg->name(),
895 isReader, // nameIsPointer
896 parcelObj,
897 parcelObjIsPointer,
898 isReader,
899 mode);
900 }
901}
902
Yifan Hong068c5522016-10-31 14:07:25 -0700903status_t AST::generateProxyMethodSource(Formatter &out,
904 const std::string &klassName,
905 const Method *method,
906 const Interface *superInterface) const {
907
908 method->generateCppSignature(out,
909 klassName,
910 true /* specify namespaces */);
911
912 const bool returnsValue = !method->results().empty();
913 const TypedVar *elidedReturn = method->canElideCallback();
914
915 out << "{\n";
916
917 out.indent();
918
919 if (returnsValue && elidedReturn == nullptr) {
920 generateCheckNonNull(out, "_hidl_cb");
921 }
922
923 status_t status = generateCppInstrumentationCall(
924 out,
925 InstrumentationEvent::CLIENT_API_ENTRY,
926 superInterface,
927 method);
928 if (status != OK) {
929 return status;
930 }
931
932 out << "::android::hardware::Parcel _hidl_data;\n";
933 out << "::android::hardware::Parcel _hidl_reply;\n";
934 out << "::android::status_t _hidl_err;\n";
935 out << "::android::hardware::Status _hidl_status;\n\n";
936
937 declareCppReaderLocals(
938 out, method->results(), true /* forResults */);
939
940 out << "_hidl_err = _hidl_data.writeInterfaceToken(";
941 if (!method->isHidlReserved()) {
942 out << superInterface->fqName().cppNamespace()
943 << "::IHw"
944 << superInterface->getBaseName();
945 } else {
946 out << "::android::hardware::IHidlInterfaceBase";
947 }
948 out << "::descriptor);\n";
949
950 out << "if (_hidl_err != ::android::OK) { goto _hidl_error; }\n\n";
951
952 // First DFS: write all buffers and resolve pointers for parent
953 for (const auto &arg : method->args()) {
954 emitCppReaderWriter(
955 out,
956 "_hidl_data",
957 false /* parcelObjIsPointer */,
958 arg,
959 false /* reader */,
960 Type::ErrorMode_Goto,
961 false /* addPrefixToName */);
962 }
963
964 // Second DFS: resolve references.
965 for (const auto &arg : method->args()) {
966 emitCppResolveReferences(
967 out,
968 "_hidl_data",
969 false /* parcelObjIsPointer */,
970 arg,
971 false /* reader */,
972 Type::ErrorMode_Goto,
973 false /* addPrefixToName */);
974 }
975
976 out << "_hidl_err = remote()->transact("
977 << method->getSerialId()
978 << " /* "
979 << method->name()
980 << " */, _hidl_data, &_hidl_reply";
981
982 if (method->isOneway()) {
983 out << ", ::android::hardware::IBinder::FLAG_ONEWAY";
984 }
985 out << ");\n";
986
987 out << "if (_hidl_err != ::android::OK) { goto _hidl_error; }\n\n";
988
989 if (!method->isOneway()) {
990 out << "_hidl_err = _hidl_status.readFromParcel(_hidl_reply);\n";
991 out << "if (_hidl_err != ::android::OK) { goto _hidl_error; }\n\n";
992 out << "if (!_hidl_status.isOk()) { return _hidl_status; }\n\n";
993
994
995 // First DFS: write all buffers and resolve pointers for parent
996 for (const auto &arg : method->results()) {
997 emitCppReaderWriter(
998 out,
999 "_hidl_reply",
1000 false /* parcelObjIsPointer */,
1001 arg,
1002 true /* reader */,
1003 Type::ErrorMode_Goto,
1004 true /* addPrefixToName */);
1005 }
1006
1007 // Second DFS: resolve references.
1008 for (const auto &arg : method->results()) {
1009 emitCppResolveReferences(
1010 out,
1011 "_hidl_reply",
1012 false /* parcelObjIsPointer */,
1013 arg,
1014 true /* reader */,
1015 Type::ErrorMode_Goto,
1016 true /* addPrefixToName */);
1017 }
1018
1019 if (returnsValue && elidedReturn == nullptr) {
1020 out << "_hidl_cb(";
1021
1022 bool first = true;
1023 for (const auto &arg : method->results()) {
1024 if (!first) {
1025 out << ", ";
1026 }
1027
1028 if (arg->type().resultNeedsDeref()) {
1029 out << "*";
1030 }
1031 out << "_hidl_out_" << arg->name();
1032
1033 first = false;
1034 }
1035
1036 out << ");\n\n";
1037 }
1038 status_t status = generateCppInstrumentationCall(
1039 out,
1040 InstrumentationEvent::CLIENT_API_EXIT,
1041 superInterface,
1042 method);
1043 if (status != OK) {
1044 return status;
1045 }
1046 }
1047
1048 if (elidedReturn != nullptr) {
1049 std::string extra;
1050 out << "_hidl_status.setFromStatusT(_hidl_err);\n";
1051 out << "return ::android::hardware::Return<";
1052 out << elidedReturn->type().getCppResultType(&extra)
1053 << ">(_hidl_out_" << elidedReturn->name() << ");\n\n";
1054 } else {
1055 out << "_hidl_status.setFromStatusT(_hidl_err);\n";
1056 out << "return ::android::hardware::Return<void>();\n\n";
1057 }
1058
1059 out.unindent();
1060 out << "_hidl_error:\n";
1061 out.indent();
1062 out << "_hidl_status.setFromStatusT(_hidl_err);\n";
1063 out << "return ::android::hardware::Return<";
1064 if (elidedReturn != nullptr) {
1065 std::string extra;
1066 out << method->results().at(0)->type().getCppResultType(&extra);
1067 } else {
1068 out << "void";
1069 }
1070 out << ">(_hidl_status);\n";
1071
1072 out.unindent();
1073 out << "}\n\n";
1074 return OK;
1075}
1076
Andreas Huber881227d2016-08-02 14:20:21 -07001077status_t AST::generateProxySource(
1078 Formatter &out, const std::string &baseName) const {
1079 const std::string klassName = "Bp" + baseName;
1080
1081 out << klassName
1082 << "::"
1083 << klassName
Iliyan Malchev549e2592016-08-10 08:59:12 -07001084 << "(const ::android::sp<::android::hardware::IBinder> &_hidl_impl)\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001085
1086 out.indent();
1087 out.indent();
1088
1089 out << ": BpInterface"
Steven Moreland40786312016-08-16 10:29:40 -07001090 << "<IHw"
Andreas Huber881227d2016-08-02 14:20:21 -07001091 << baseName
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001092 << ">(_hidl_impl),\n"
1093 << " HidlInstrumentor(\""
1094 << mPackage.string()
1095 << "::I"
1096 << baseName
1097 << "\") {\n";
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001098
Andreas Huber881227d2016-08-02 14:20:21 -07001099 out.unindent();
1100 out.unindent();
1101 out << "}\n\n";
1102
Yifan Hong068c5522016-10-31 14:07:25 -07001103 status_t err = generateMethods(out, [&](const Method *method, const Interface *superInterface) {
1104 return generateProxyMethodSource(out, klassName, method, superInterface);
1105 });
Andreas Huber881227d2016-08-02 14:20:21 -07001106
Yifan Hong068c5522016-10-31 14:07:25 -07001107 return err;
Andreas Huber881227d2016-08-02 14:20:21 -07001108}
1109
1110status_t AST::generateStubSource(
1111 Formatter &out, const std::string &baseName) const {
1112 out << "IMPLEMENT_HWBINDER_META_INTERFACE("
1113 << baseName
Yifan Hong10fe0b52016-10-19 14:20:17 -07001114 << ", "
1115 << mPackage.cppNamespace()
Andreas Huber881227d2016-08-02 14:20:21 -07001116 << "::I"
1117 << baseName
Yifan Hong10fe0b52016-10-19 14:20:17 -07001118 << "::descriptor);\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001119
1120 const std::string klassName = "Bn" + baseName;
1121
Steven Moreland40786312016-08-16 10:29:40 -07001122 out << klassName
1123 << "::"
1124 << klassName
1125 << "(const ::android::sp<I" << baseName <<"> &_hidl_impl)\n";
1126
1127 out.indent();
1128 out.indent();
1129
1130 out << ": BnInterface"
1131 << "<I"
1132 << baseName
1133 << ", IHw"
1134 << baseName
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001135 << ">(_hidl_impl),\n"
1136 << " HidlInstrumentor(\""
1137 << mPackage.string()
1138 << "::I"
1139 << baseName
1140 << "\") {\n";
Steven Moreland40786312016-08-16 10:29:40 -07001141
1142 out.unindent();
1143 out.unindent();
1144 out << "}\n\n";
1145
Andreas Huber881227d2016-08-02 14:20:21 -07001146 out << "::android::status_t " << klassName << "::onTransact(\n";
1147
1148 out.indent();
1149 out.indent();
1150
Iliyan Malchev549e2592016-08-10 08:59:12 -07001151 out << "uint32_t _hidl_code,\n"
1152 << "const ::android::hardware::Parcel &_hidl_data,\n"
1153 << "::android::hardware::Parcel *_hidl_reply,\n"
1154 << "uint32_t _hidl_flags,\n"
1155 << "TransactCallback _hidl_cb) {\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001156
1157 out.unindent();
1158
Iliyan Malchev549e2592016-08-10 08:59:12 -07001159 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
Iliyan Malchev549e2592016-08-10 08:59:12 -07001160 out << "switch (_hidl_code) {\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001161 out.indent();
1162
1163 const Interface *iface = mRootScope->getInterface();
1164
Yifan Hong10fe0b52016-10-19 14:20:17 -07001165 for (const auto &tuple : iface->allMethodsFromRoot()) {
1166 const Method *method = tuple.method();
1167 const Interface *superInterface = tuple.interface();
1168 out << "case "
1169 << method->getSerialId()
1170 << " /* "
1171 << method->name()
1172 << " */:\n{\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001173
Yifan Hong10fe0b52016-10-19 14:20:17 -07001174 out.indent();
Andreas Huber881227d2016-08-02 14:20:21 -07001175
Yifan Hong10fe0b52016-10-19 14:20:17 -07001176 status_t err =
1177 generateStubSourceForMethod(out, superInterface, method);
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001178
Yifan Hong10fe0b52016-10-19 14:20:17 -07001179 if (err != OK) {
1180 return err;
Andreas Huber881227d2016-08-02 14:20:21 -07001181 }
Yifan Hong10fe0b52016-10-19 14:20:17 -07001182
1183 out.unindent();
1184 out << "}\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001185 }
1186
1187 out << "default:\n{\n";
1188 out.indent();
1189
Andreas Huber8a82ff72016-08-04 10:29:39 -07001190 out << "return ::android::hardware::BnInterface<I"
Steven Moreland40786312016-08-16 10:29:40 -07001191 << baseName << ", IHw" << baseName
Andreas Huber881227d2016-08-02 14:20:21 -07001192 << ">::onTransact(\n";
1193
1194 out.indent();
1195 out.indent();
1196
Iliyan Malchev549e2592016-08-10 08:59:12 -07001197 out << "_hidl_code, _hidl_data, _hidl_reply, "
1198 << "_hidl_flags, _hidl_cb);\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001199
1200 out.unindent();
1201 out.unindent();
1202
1203 out.unindent();
1204 out << "}\n";
1205
1206 out.unindent();
1207 out << "}\n\n";
1208
Iliyan Malchev549e2592016-08-10 08:59:12 -07001209 out << "if (_hidl_err == ::android::UNEXPECTED_NULL) {\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001210 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -07001211 out << "_hidl_err = ::android::hardware::Status::fromExceptionCode(\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001212 out.indent();
1213 out.indent();
Andreas Huber8a82ff72016-08-04 10:29:39 -07001214 out << "::android::hardware::Status::EX_NULL_POINTER)\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001215 out.indent();
1216 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -07001217 out << ".writeToParcel(_hidl_reply);\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001218 out.unindent();
1219 out.unindent();
1220 out.unindent();
1221 out.unindent();
1222
1223 out.unindent();
1224 out << "}\n\n";
1225
Iliyan Malchev549e2592016-08-10 08:59:12 -07001226 out << "return _hidl_err;\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001227
1228 out.unindent();
1229 out << "}\n\n";
1230
1231 return OK;
1232}
1233
1234status_t AST::generateStubSourceForMethod(
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001235 Formatter &out, const Interface *iface, const Method *method) const {
Yifan Hong10fe0b52016-10-19 14:20:17 -07001236 out << "if (!_hidl_data.enforceInterface(";
1237
1238 if (!method->isHidlReserved()) {
1239 out << iface->fqName().cppNamespace()
1240 << "::IHw"
1241 << iface->getBaseName();
1242 } else {
1243 out << "::android::hardware::IHidlInterfaceBase";
1244 }
1245
1246 out << "::descriptor)) {\n";
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001247
Andreas Huber881227d2016-08-02 14:20:21 -07001248 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -07001249 out << "_hidl_err = ::android::BAD_TYPE;\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001250 out << "break;\n";
1251 out.unindent();
1252 out << "}\n\n";
1253
Andreas Huber5e44a292016-09-27 14:52:39 -07001254 declareCppReaderLocals(out, method->args(), false /* forResults */);
Andreas Hubere7ff2282016-08-16 13:50:03 -07001255
Yifan Hongbf459bc2016-08-23 16:50:37 -07001256 // First DFS: write buffers
Andreas Huber881227d2016-08-02 14:20:21 -07001257 for (const auto &arg : method->args()) {
1258 emitCppReaderWriter(
1259 out,
Iliyan Malchev549e2592016-08-10 08:59:12 -07001260 "_hidl_data",
Andreas Huber881227d2016-08-02 14:20:21 -07001261 false /* parcelObjIsPointer */,
1262 arg,
1263 true /* reader */,
Andreas Huber5e44a292016-09-27 14:52:39 -07001264 Type::ErrorMode_Break,
1265 false /* addPrefixToName */);
Andreas Huber881227d2016-08-02 14:20:21 -07001266 }
1267
Yifan Hongbf459bc2016-08-23 16:50:37 -07001268 // Second DFS: resolve references
1269 for (const auto &arg : method->args()) {
1270 emitCppResolveReferences(
1271 out,
1272 "_hidl_data",
1273 false /* parcelObjIsPointer */,
1274 arg,
1275 true /* reader */,
1276 Type::ErrorMode_Break,
1277 false /* addPrefixToName */);
1278 }
1279
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001280 status_t status = generateCppInstrumentationCall(
1281 out,
1282 InstrumentationEvent::SERVER_API_ENTRY,
1283 iface,
1284 method);
1285 if (status != OK) {
1286 return status;
Zhuoyao Zhangde578002016-09-07 18:24:17 -07001287 }
1288
Andreas Huber881227d2016-08-02 14:20:21 -07001289 const bool returnsValue = !method->results().empty();
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001290 const TypedVar *elidedReturn = method->canElideCallback();
Andreas Huber881227d2016-08-02 14:20:21 -07001291
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001292 if (elidedReturn != nullptr) {
1293 std::string extra;
Andreas Huber881227d2016-08-02 14:20:21 -07001294
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001295 out << elidedReturn->type().getCppResultType(&extra) << " ";
1296 out << elidedReturn->name() << " = ";
1297 out << method->name() << "(";
Andreas Huber881227d2016-08-02 14:20:21 -07001298
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001299 bool first = true;
1300 for (const auto &arg : method->args()) {
Andreas Huber881227d2016-08-02 14:20:21 -07001301 if (!first) {
1302 out << ", ";
1303 }
1304
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001305 if (arg->type().resultNeedsDeref()) {
1306 out << "*";
1307 }
1308
1309 out << arg->name();
Andreas Huber881227d2016-08-02 14:20:21 -07001310
1311 first = false;
1312 }
1313
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001314 out << ");\n\n";
Andreas Huber8a82ff72016-08-04 10:29:39 -07001315 out << "::android::hardware::Status::ok()"
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001316 << ".writeToParcel(_hidl_reply);\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001317
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001318 elidedReturn->type().emitReaderWriter(
1319 out,
1320 elidedReturn->name(),
1321 "_hidl_reply",
1322 true, /* parcelObjIsPointer */
1323 false, /* isReader */
1324 Type::ErrorMode_Ignore);
Andreas Huber881227d2016-08-02 14:20:21 -07001325
Yifan Hongbf459bc2016-08-23 16:50:37 -07001326 emitCppResolveReferences(
1327 out,
1328 "_hidl_reply",
1329 true /* parcelObjIsPointer */,
1330 elidedReturn,
1331 false /* reader */,
1332 Type::ErrorMode_Ignore,
1333 false /* addPrefixToName */);
1334
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001335 status_t status = generateCppInstrumentationCall(
1336 out,
1337 InstrumentationEvent::SERVER_API_EXIT,
1338 iface,
1339 method);
1340 if (status != OK) {
1341 return status;
1342 }
Zhuoyao Zhangde578002016-09-07 18:24:17 -07001343
Iliyan Malchev549e2592016-08-10 08:59:12 -07001344 out << "_hidl_cb(*_hidl_reply);\n";
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001345 } else {
1346 if (returnsValue) {
1347 out << "bool _hidl_callbackCalled = false;\n\n";
1348 }
Andreas Huber881227d2016-08-02 14:20:21 -07001349
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001350 out << method->name() << "(";
Andreas Huber881227d2016-08-02 14:20:21 -07001351
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001352 bool first = true;
1353 for (const auto &arg : method->args()) {
1354 if (!first) {
1355 out << ", ";
1356 }
Andreas Huber881227d2016-08-02 14:20:21 -07001357
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001358 if (arg->type().resultNeedsDeref()) {
1359 out << "*";
1360 }
1361
1362 out << arg->name();
1363
1364 first = false;
1365 }
1366
1367 if (returnsValue) {
1368 if (!first) {
1369 out << ", ";
1370 }
1371
1372 out << "[&](";
1373
1374 first = true;
1375 for (const auto &arg : method->results()) {
1376 if (!first) {
1377 out << ", ";
1378 }
1379
1380 out << "const auto &" << arg->name();
1381
1382 first = false;
1383 }
1384
1385 out << ") {\n";
1386 out.indent();
1387 out << "_hidl_callbackCalled = true;\n\n";
1388
1389 out << "::android::hardware::Status::ok()"
1390 << ".writeToParcel(_hidl_reply);\n\n";
1391
Yifan Hongbf459bc2016-08-23 16:50:37 -07001392 // First DFS: buffers
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001393 for (const auto &arg : method->results()) {
1394 emitCppReaderWriter(
1395 out,
1396 "_hidl_reply",
1397 true /* parcelObjIsPointer */,
1398 arg,
1399 false /* reader */,
Andreas Huber5e44a292016-09-27 14:52:39 -07001400 Type::ErrorMode_Ignore,
1401 false /* addPrefixToName */);
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001402 }
1403
Yifan Hongbf459bc2016-08-23 16:50:37 -07001404 // Second DFS: resolve references
1405 for (const auto &arg : method->results()) {
1406 emitCppResolveReferences(
1407 out,
1408 "_hidl_reply",
1409 true /* parcelObjIsPointer */,
1410 arg,
1411 false /* reader */,
1412 Type::ErrorMode_Ignore,
1413 false /* addPrefixToName */);
1414 }
1415
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001416 status_t status = generateCppInstrumentationCall(
1417 out,
1418 InstrumentationEvent::SERVER_API_EXIT,
1419 iface,
1420 method);
1421 if (status != OK) {
1422 return status;
Zhuoyao Zhangde578002016-09-07 18:24:17 -07001423 }
1424
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001425 out << "_hidl_cb(*_hidl_reply);\n";
1426
1427 out.unindent();
1428 out << "}\n";
1429 }
1430
Iliyan Malchevd57066f2016-09-08 13:59:38 -07001431 out << ");\n\n";
1432
1433 // What to do if the stub implementation has a synchronous callback
1434 // which does not get invoked? This is not a transport error but a
1435 // service error of sorts. For now, return OK to the caller, as this is
1436 // not a transport error.
1437 //
1438 // TODO(b/31365311) Figure out how to deal with this later.
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001439
1440 if (returnsValue) {
1441 out << "if (!_hidl_callbackCalled) {\n";
1442 out.indent();
1443 }
1444
Iliyan Malchevd57066f2016-09-08 13:59:38 -07001445 out << "::android::hardware::Status::ok()"
1446 << ".writeToParcel(_hidl_reply);\n";
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001447
1448 if (returnsValue) {
1449 out.unindent();
1450 out << "}\n\n";
1451 }
Andreas Huber881227d2016-08-02 14:20:21 -07001452 }
1453
1454 out << "break;\n";
1455
1456 return OK;
1457}
1458
Steven Moreland69e7c702016-09-09 11:16:32 -07001459status_t AST::generatePassthroughHeader(const std::string &outputPath) const {
1460 std::string ifaceName;
1461 if (!AST::isInterface(&ifaceName)) {
1462 // types.hal does not get a stub header.
1463 return OK;
1464 }
1465
1466 const Interface *iface = mRootScope->getInterface();
1467
1468 const std::string baseName = iface->getBaseName();
1469 const std::string klassName = "Bs" + baseName;
1470
1471 bool supportOneway = iface->hasOnewayMethods();
1472
1473 std::string path = outputPath;
1474 path.append(mCoordinator->convertPackageRootToPath(mPackage));
1475 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
1476 path.append(klassName);
1477 path.append(".h");
1478
1479 CHECK(Coordinator::MakeParentHierarchy(path));
1480 FILE *file = fopen(path.c_str(), "w");
1481
1482 if (file == NULL) {
1483 return -errno;
1484 }
1485
1486 Formatter out(file);
1487
1488 const std::string guard = makeHeaderGuard(klassName);
1489
1490 out << "#ifndef " << guard << "\n";
1491 out << "#define " << guard << "\n\n";
1492
1493 std::vector<std::string> packageComponents;
1494 getPackageAndVersionComponents(
1495 &packageComponents, false /* cpp_compatible */);
1496
1497 out << "#include <future>\n";
1498 out << "#include <";
1499 for (const auto &component : packageComponents) {
1500 out << component << "/";
1501 }
1502 out << ifaceName << ".h>\n\n";
1503
1504 if (supportOneway) {
Yifan Hong2cbc1472016-10-25 19:02:40 -07001505 out << "#include <hidl/TaskRunner.h>\n";
Steven Moreland69e7c702016-09-09 11:16:32 -07001506 }
1507
1508 enterLeaveNamespace(out, true /* enter */);
1509 out << "\n";
1510
1511 out << "struct "
1512 << klassName
1513 << " : " << ifaceName
1514 << " {\n";
1515
1516 out.indent();
1517 out << "explicit "
1518 << klassName
1519 << "(const sp<"
1520 << ifaceName
1521 << "> impl);\n";
1522
Yifan Hong068c5522016-10-31 14:07:25 -07001523 status_t err = generateMethods(out, [&](const Method *method, const Interface *) {
1524 return generatePassthroughMethod(out, method);
1525 });
Steven Moreland69e7c702016-09-09 11:16:32 -07001526
1527 if (err != OK) {
1528 return err;
1529 }
1530
1531 out.unindent();
1532 out << "private:\n";
1533 out.indent();
1534 out << "const sp<" << ifaceName << "> mImpl;\n";
1535
1536 if (supportOneway) {
Yifan Hong2cbc1472016-10-25 19:02:40 -07001537 out << "::android::hardware::TaskRunner mOnewayQueue;\n";
Steven Moreland69e7c702016-09-09 11:16:32 -07001538
1539 out << "\n";
1540
1541 out << "::android::hardware::Return<void> addOnewayTask("
1542 "std::function<void(void)>);\n\n";
Steven Moreland69e7c702016-09-09 11:16:32 -07001543 }
1544
1545 out.unindent();
1546
1547 out << "};\n\n";
1548
1549 enterLeaveNamespace(out, false /* enter */);
1550
1551 out << "\n#endif // " << guard << "\n";
1552
1553 return OK;
1554}
1555
Yifan Hongfe95aa22016-10-19 17:26:45 -07001556status_t AST::generateInterfaceSource(Formatter &out) const {
1557 const Interface *iface = mRootScope->getInterface();
1558
Yifan Hong2d7126b2016-10-20 15:12:57 -07001559
1560 // generate toBinder functions
1561 out << "::android::sp<::android::hardware::IBinder> I"
1562 << iface->getBaseName()
1563 << "::toBinder() {\n";
1564 out.indent();
1565 out << "if (isRemote()) {\n";
1566 out.indent();
1567 out << "return ::android::hardware::IInterface::asBinder("
1568 << "static_cast<IHw"
1569 << iface->getBaseName()
1570 << " *>(this));\n";
1571 out.unindent();
1572 out << "} else {\n";
1573 out.indent();
1574 out << "return new Bn" << iface->getBaseName() << "(this);\n";
1575 out.unindent();
1576 out << "}\n";
1577 out.unindent();
1578 out << "}\n\n";
1579
1580 // generate castFrom functions
Yifan Hongfe95aa22016-10-19 17:26:45 -07001581 if (!iface->isRootType()) {
1582 std::string childTypeExtra;
1583 std::string childTypeResult = iface->getCppResultType(&childTypeExtra);
1584 childTypeResult += childTypeExtra;
1585
1586 for (const Interface *superType : iface->superTypeChain()) {
1587 std::string superTypeExtra;
1588 out << "// static \n"
1589 << childTypeResult
1590 << " I"
1591 << iface->getBaseName()
1592 << "::castFrom("
1593 << superType->getCppArgumentType(&superTypeExtra)
1594 << " parent"
1595 << superTypeExtra
1596 << ")";
1597 out << " {\n";
1598 out.indent();
1599 out << "return ::android::hardware::castInterface<";
1600 out << "I" << iface->getBaseName() << ", "
1601 << superType->fqName().cppName() << ", "
1602 << "Bp" << iface->getBaseName()
1603 << ">(\n";
1604 out.indent();
1605 out.indent();
1606 out << "parent, \""
1607 << iface->fqName().string()
1608 << "\");\n";
1609 out.unindent();
1610 out.unindent();
1611 out.unindent();
1612 out << "}\n\n";
1613 }
1614 }
1615
1616 return OK;
1617}
1618
Steven Moreland69e7c702016-09-09 11:16:32 -07001619status_t AST::generatePassthroughSource(Formatter &out) const {
1620 const Interface *iface = mRootScope->getInterface();
1621
1622 const std::string baseName = iface->getBaseName();
1623 const std::string klassName = "Bs" + baseName;
1624
1625 out << klassName
1626 << "::"
1627 << klassName
1628 << "(const sp<"
1629 << iface->fullName()
Yifan Hong2cbc1472016-10-25 19:02:40 -07001630 << "> impl) : mImpl(impl) {";
1631 if (iface->hasOnewayMethods()) {
1632 out << "\n";
1633 out.indentBlock([&] {
1634 out << "mOnewayQueue.setLimit(3000 /* similar limit to binderized */);\n";
1635 });
1636 }
1637 out << "}\n\n";
Steven Moreland69e7c702016-09-09 11:16:32 -07001638
1639 if (iface->hasOnewayMethods()) {
1640 out << "::android::hardware::Return<void> "
1641 << klassName
1642 << "::addOnewayTask(std::function<void(void)> fun) {\n";
1643 out.indent();
Yifan Hong2cbc1472016-10-25 19:02:40 -07001644 out << "if (!mOnewayQueue.push(fun)) {\n";
Steven Moreland69e7c702016-09-09 11:16:32 -07001645 out.indent();
Steven Moreland67f67b42016-09-29 08:59:02 -07001646 out << "return ::android::hardware::Status::fromExceptionCode(\n";
1647 out.indent();
1648 out.indent();
1649 out << "::android::hardware::Status::EX_TRANSACTION_FAILED);\n";
1650 out.unindent();
1651 out.unindent();
Steven Moreland69e7c702016-09-09 11:16:32 -07001652 out.unindent();
Steven Moreland69e7c702016-09-09 11:16:32 -07001653 out << "}\n";
1654
Steven Morelandd366c262016-10-11 15:29:10 -07001655 out << "return ::android::hardware::Status();\n";
Steven Moreland69e7c702016-09-09 11:16:32 -07001656
1657 out.unindent();
1658 out << "}\n\n";
1659
1660
1661 }
1662
1663 return OK;
1664}
1665
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001666status_t AST::generateCppInstrumentationCall(
1667 Formatter &out,
1668 InstrumentationEvent event,
1669 const Interface *iface, const Method *method) const {
1670 out << "if (UNLIKELY(mEnableInstrumentation)) {\n";
1671 out.indent();
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001672 out << "std::vector<void *> _hidl_args;\n";
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001673 std::string event_str = "";
1674 switch (event) {
1675 case SERVER_API_ENTRY:
1676 {
1677 event_str = "InstrumentationEvent::SERVER_API_ENTRY";
1678 for (const auto &arg : method->args()) {
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001679 out << "_hidl_args.push_back((void *)"
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001680 << (arg->type().resultNeedsDeref() ? "" : "&")
1681 << arg->name()
1682 << ");\n";
1683 }
1684 break;
1685 }
1686 case SERVER_API_EXIT:
1687 {
1688 event_str = "InstrumentationEvent::SERVER_API_EXIT";
1689 const TypedVar *elidedReturn = method->canElideCallback();
1690 if (elidedReturn != nullptr) {
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001691 out << "_hidl_args.push_back((void *)&"
1692 << elidedReturn->name()
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001693 << ");\n";
1694 } else {
1695 for (const auto &arg : method->results()) {
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001696 out << "_hidl_args.push_back((void *)&"
1697 << arg->name()
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001698 << ");\n";
1699 }
1700 }
1701 break;
1702 }
1703 case CLIENT_API_ENTRY:
1704 {
1705 event_str = "InstrumentationEvent::CLIENT_API_ENTRY";
1706 for (const auto &arg : method->args()) {
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001707 out << "_hidl_args.push_back((void *)&"
1708 << arg->name()
1709 << ");\n";
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001710 }
1711 break;
1712 }
1713 case CLIENT_API_EXIT:
1714 {
1715 event_str = "InstrumentationEvent::CLIENT_API_EXIT";
1716 for (const auto &arg : method->results()) {
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001717 out << "_hidl_args.push_back((void *)"
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001718 << (arg->type().resultNeedsDeref() ? "" : "&")
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001719 << "_hidl_out_"
1720 << arg->name()
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001721 << ");\n";
1722 }
1723 break;
1724 }
1725 case SYNC_CALLBACK_ENTRY:
1726 case SYNC_CALLBACK_EXIT:
1727 case ASYNC_CALLBACK_ENTRY:
1728 case ASYNC_CALLBACK_EXIT:
1729 {
1730 LOG(ERROR) << "Not supported instrumentation event: " << event;
1731 return UNKNOWN_ERROR;
1732 }
1733 }
1734
1735 out << "for (auto callback: mInstrumentationCallbacks) {\n";
1736 out.indent();
1737 out << "callback("
1738 << event_str
1739 << ", \""
1740 << mPackage.package()
1741 << "\", \""
1742 << mPackage.getPackageFullVersion()
1743 << "\", \""
1744 << iface->localName()
1745 << "\", \""
1746 << method->name()
Zhuoyao Zhang964f72f2016-10-21 11:12:03 -07001747 << "\", &_hidl_args);\n";
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001748 out.unindent();
1749 out << "}\n";
1750 out.unindent();
1751 out << "}\n\n";
1752
1753 return OK;
1754}
1755
Andreas Huber881227d2016-08-02 14:20:21 -07001756} // namespace android
1757