blob: c514714c46e3828561887110ad5aca51d1becb41 [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) {
172 out << " : virtual public RefBase";
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700173 } else {
Steven Moreland40786312016-08-16 10:29:40 -0700174 out << " : public "
175 << 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";
Iliyan Malchev795dd432016-09-02 11:48:26 -0700202 out << "virtual bool isRemote() const { return false; }\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700203 bool haveCallbacks = false;
204 for (const auto &method : iface->methods()) {
205 const bool returnsValue = !method->results().empty();
206
207 if (!returnsValue) {
208 continue;
209 }
210
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700211 if (method->canElideCallback() != nullptr) {
212 continue;
213 }
214
Andreas Huber881227d2016-08-02 14:20:21 -0700215 haveCallbacks = true;
216
217 out << "using "
218 << method->name()
219 << "_cb = std::function<void("
Steven Moreland979e0992016-09-07 09:18:08 -0700220 << Method::GetArgSignature(method->results(),
221 true /* specify namespaces */)
Andreas Huber881227d2016-08-02 14:20:21 -0700222 << ")>;\n";
223 }
224
225 if (haveCallbacks) {
226 out << "\n";
227 }
228
229 for (const auto &method : iface->methods()) {
230 const bool returnsValue = !method->results().empty();
231
Andreas Huber3599d922016-08-09 10:42:57 -0700232 method->dumpAnnotations(out);
233
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700234 const TypedVar *elidedReturn = method->canElideCallback();
235 if (elidedReturn) {
236 std::string extra;
Iliyan Malchev2b6591b2016-08-18 19:15:19 -0700237 out << "virtual ::android::hardware::Return<";
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700238 out << elidedReturn->type().getCppResultType(&extra) << "> ";
239 } else {
Iliyan Malchevd57066f2016-09-08 13:59:38 -0700240 out << "virtual ::android::hardware::Return<void> ";
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700241 }
242
243 out << method->name()
Andreas Huber881227d2016-08-02 14:20:21 -0700244 << "("
Steven Moreland979e0992016-09-07 09:18:08 -0700245 << Method::GetArgSignature(method->args(),
246 true /* specify namespaces */);
Andreas Huber881227d2016-08-02 14:20:21 -0700247
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700248 if (returnsValue && elidedReturn == nullptr) {
Andreas Huber881227d2016-08-02 14:20:21 -0700249 if (!method->args().empty()) {
250 out << ", ";
251 }
252
Steven Moreland67f67b42016-09-29 08:59:02 -0700253 out << method->name() << "_cb _hidl_cb";
Andreas Huber881227d2016-08-02 14:20:21 -0700254 }
255
256 out << ") = 0;\n";
257 }
Steven Moreland40786312016-08-16 10:29:40 -0700258
259 out << "DECLARE_REGISTER_AND_GET_SERVICE(" << baseName << ")\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700260 }
261
262 if (isInterface) {
263 out.unindent();
264
Andreas Hubere3f769a2016-10-10 10:54:44 -0700265 out << "};\n\n";
266 }
267
268 err = mRootScope->emitGlobalTypeDeclarations(out);
269
270 if (err != OK) {
271 return err;
Andreas Huber881227d2016-08-02 14:20:21 -0700272 }
273
274 out << "\n";
275 enterLeaveNamespace(out, false /* enter */);
276
277 out << "\n#endif // " << guard << "\n";
278
279 return OK;
280}
281
Steven Moreland40786312016-08-16 10:29:40 -0700282status_t AST::generateHwBinderHeader(const std::string &outputPath) const {
283 std::string ifaceName;
284 if(!AST::isInterface(&ifaceName)) {
285 // types.hal does not get an HwBinder header.
286 return OK;
287 }
288
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700289 const Interface *iface = mRootScope->getInterface();
290 const std::string baseName = iface->getBaseName();
Steven Moreland40786312016-08-16 10:29:40 -0700291
292 const std::string klassName = "IHw" + baseName;
293
294 std::string path = outputPath;
295 path.append(mCoordinator->convertPackageRootToPath(mPackage));
296 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
297 path.append(klassName + ".h");
298
299 FILE* file = fopen(path.c_str(), "w");
300
301 if (file == NULL) {
302 return -errno;
303 }
304
305 Formatter out(file);
306
307 const std::string guard = makeHeaderGuard(klassName);
308
309 out << "#ifndef " << guard << "\n";
310 out << "#define " << guard << "\n\n";
311
312 std::vector<std::string> packageComponents;
313 getPackageAndVersionComponents(
314 &packageComponents, false /* cpp_compatible */);
315
316 out << "#include <";
317 for (const auto &component : packageComponents) {
318 out << component << "/";
319 }
320 out << ifaceName << ".h>\n\n";
321
322 for (const auto &item : mImportedNames) {
323 if (item.name() == "types") {
324 continue;
325 }
326
327 out << "#include <";
328
329 std::vector<std::string> components;
330 item.getPackageAndVersionComponents(
331 &components, false /* cpp_compatible */);
332
333 for (const auto &component : components) {
334 out << component << "/";
335 }
336
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700337 const std::string itemBaseName = item.getInterfaceBaseName();
Steven Moreland40786312016-08-16 10:29:40 -0700338
339 out << "Bn"
340 << itemBaseName
341 << ".h>\n";
342 }
343
344 out << "\n";
345
346 out << "#include <hidl/HidlSupport.h>\n";
Martijn Coenen93915102016-09-01 01:35:52 +0200347 out << "#include <hidl/Status.h>\n";
Steven Moreland40786312016-08-16 10:29:40 -0700348 out << "#include <hwbinder/IBinder.h>\n";
349 out << "#include <hwbinder/IInterface.h>\n";
Steven Moreland40786312016-08-16 10:29:40 -0700350
351 out << "\n";
352
353 enterLeaveNamespace(out, true /* enter */);
354 out << "\n";
355
356 out << "struct "
357 << klassName
358 << " : public "
359 << ifaceName;
360
Steven Moreland40786312016-08-16 10:29:40 -0700361 const Interface *superType = iface->superType();
362
363 out << ", public ::android::hardware::IInterface";
364
365 out << " {\n";
366
367 out.indent();
368
369 out << "DECLARE_HWBINDER_META_INTERFACE(" << baseName << ");\n\n";
370
Steven Moreland40786312016-08-16 10:29:40 -0700371 out.unindent();
372
373 out << "};\n\n";
374
375 enterLeaveNamespace(out, false /* enter */);
376
377 out << "\n#endif // " << guard << "\n";
378
379 return OK;
380}
381
Andreas Huber881227d2016-08-02 14:20:21 -0700382status_t AST::emitTypeDeclarations(Formatter &out) const {
383 return mRootScope->emitTypeDeclarations(out);
384}
385
Steven Morelanda7a421a2016-09-07 08:35:18 -0700386status_t AST::generateStubMethod(Formatter &out,
387 const std::string &className,
Steven Moreland979e0992016-09-07 09:18:08 -0700388 const Method *method,
389 bool specifyNamespaces) const {
Steven Morelanda7a421a2016-09-07 08:35:18 -0700390 out << "inline ";
391
Steven Moreland979e0992016-09-07 09:18:08 -0700392 method->generateCppSignature(out,
393 className,
394 specifyNamespaces);
Steven Morelanda7a421a2016-09-07 08:35:18 -0700395
396 const bool returnsValue = !method->results().empty();
397 const TypedVar *elidedReturn = method->canElideCallback();
398 out << " {\n";
399 out.indent();
400 out << "return mImpl->"
401 << method->name()
402 << "(";
403 bool first = true;
404 for (const auto &arg : method->args()) {
405 if (!first) {
406 out << ", ";
407 }
408 first = false;
409 out << arg->name();
410 }
411 if (returnsValue && elidedReturn == nullptr) {
412 if (!method->args().empty()) {
413 out << ", ";
414 }
415
416 out << "_hidl_cb";
417 }
418 out << ");\n";
419 out.unindent();
420 out << "}";
421
422 out << ";\n";
423
424 return OK;
425}
426
Steven Moreland9c387612016-09-07 09:54:26 -0700427status_t AST::generateProxyDeclaration(Formatter &out,
428 const std::string &className,
429 const Method *method,
430 bool specifyNamespaces) const {
Steven Morelanda7a421a2016-09-07 08:35:18 -0700431
Steven Moreland979e0992016-09-07 09:18:08 -0700432 method->generateCppSignature(out,
433 className,
434 specifyNamespaces);
Steven Morelanda7a421a2016-09-07 08:35:18 -0700435 out << " override;\n";
436
437 return OK;
438}
439
Steven Moreland69e7c702016-09-09 11:16:32 -0700440
441status_t AST::generatePassthroughMethod(Formatter &out,
442 const std::string &className,
443 const Method *method,
444 bool specifyNamespaces) const {
445 method->generateCppSignature(out, className, specifyNamespaces);
446
447 out << " {\n";
448 out.indent();
449
450 const bool returnsValue = !method->results().empty();
451 const TypedVar *elidedReturn = method->canElideCallback();
452
Steven Moreland67f67b42016-09-29 08:59:02 -0700453 if (returnsValue && elidedReturn == nullptr) {
454 generateCheckNonNull(out, "_hidl_cb");
455 }
456
Steven Moreland69e7c702016-09-09 11:16:32 -0700457 out << "return ";
458
459 if (method->isOneway()) {
460 out << "addOnewayTask([this";
461 for (const auto &arg : method->args()) {
462 out << ", " << arg->name();
463 }
464 out << "] {this->";
465 }
466
467 out << "mImpl->"
468 << method->name()
469 << "(";
470
471 bool first = true;
472 for (const auto &arg : method->args()) {
473 if (!first) {
474 out << ", ";
475 }
476 first = false;
477 out << arg->name();
478 }
479 if (returnsValue && elidedReturn == nullptr) {
480 if (!method->args().empty()) {
481 out << ", ";
482 }
483
484 out << "_hidl_cb";
485 }
486 out << ")";
487
488 if (method->isOneway()) {
489 out << ";})";
490 }
491 out << ";\n";
492
493 out.unindent();
494 out << "}\n";
495
496 return OK;
497}
498
Steven Morelanda7a421a2016-09-07 08:35:18 -0700499status_t AST::generateMethods(
500 Formatter &out,
501 const std::string &className,
Steven Moreland979e0992016-09-07 09:18:08 -0700502 MethodLocation type,
503 bool specifyNamespaces) const {
Steven Morelanda7a421a2016-09-07 08:35:18 -0700504
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700505 const Interface *iface = mRootScope->getInterface();
506
507 std::vector<const Interface *> chain;
508 while (iface != NULL) {
509 chain.push_back(iface);
510 iface = iface->superType();
511 }
512
513 for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
514 const Interface *superInterface = *it;
515
516 out << "// Methods from "
517 << superInterface->fullName()
518 << " follow.\n";
519
520 for (const auto &method : superInterface->methods()) {
Steven Morelanda7a421a2016-09-07 08:35:18 -0700521 status_t err;
522 switch(type) {
523 case STUB_HEADER:
524 err = generateStubMethod(out,
525 className,
Steven Moreland979e0992016-09-07 09:18:08 -0700526 method,
527 specifyNamespaces);
Steven Morelanda7a421a2016-09-07 08:35:18 -0700528 break;
529 case PROXY_HEADER:
Steven Moreland9c387612016-09-07 09:54:26 -0700530 err = generateProxyDeclaration(out,
531 className,
532 method,
533 specifyNamespaces);
534 break;
535 case IMPL_HEADER:
536 err = generateStubImplDeclaration(out,
537 className,
538 method,
539 specifyNamespaces);
540 break;
541 case IMPL_SOURCE:
542 err = generateStubImplMethod(out,
543 className,
544 method,
545 specifyNamespaces);
Steven Morelanda7a421a2016-09-07 08:35:18 -0700546 break;
Steven Moreland69e7c702016-09-09 11:16:32 -0700547 case PASSTHROUGH_HEADER:
548 err = generatePassthroughMethod(out,
549 className,
550 method,
551 specifyNamespaces);
552 break;
Steven Morelanda7a421a2016-09-07 08:35:18 -0700553 default:
Steven Moreland9c387612016-09-07 09:54:26 -0700554 LOG(ERROR) << "Unkown method type: " << type;
Steven Morelanda7a421a2016-09-07 08:35:18 -0700555 err = UNKNOWN_ERROR;
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700556 }
557
Steven Morelanda7a421a2016-09-07 08:35:18 -0700558 if (err != OK) {
559 return err;
Steven Moreland40786312016-08-16 10:29:40 -0700560 }
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700561 }
562
563 out << "\n";
564 }
565
566 return OK;
567}
568
Andreas Huberb82318c2016-08-02 14:45:54 -0700569status_t AST::generateStubHeader(const std::string &outputPath) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700570 std::string ifaceName;
571 if (!AST::isInterface(&ifaceName)) {
572 // types.hal does not get a stub header.
573 return OK;
574 }
575
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700576 const Interface *iface = mRootScope->getInterface();
577 const std::string baseName = iface->getBaseName();
Steven Moreland40786312016-08-16 10:29:40 -0700578 const std::string klassName = "Bn" + baseName;
Andreas Huber881227d2016-08-02 14:20:21 -0700579
Andreas Huberb82318c2016-08-02 14:45:54 -0700580 std::string path = outputPath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700581 path.append(mCoordinator->convertPackageRootToPath(mPackage));
Andreas Huberdca261f2016-08-04 13:47:51 -0700582 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
Steven Moreland40786312016-08-16 10:29:40 -0700583 path.append(klassName);
Andreas Huber881227d2016-08-02 14:20:21 -0700584 path.append(".h");
585
Andreas Huberd2943e12016-08-05 11:59:31 -0700586 CHECK(Coordinator::MakeParentHierarchy(path));
Andreas Huber881227d2016-08-02 14:20:21 -0700587 FILE *file = fopen(path.c_str(), "w");
588
589 if (file == NULL) {
590 return -errno;
591 }
592
593 Formatter out(file);
594
Steven Moreland40786312016-08-16 10:29:40 -0700595 const std::string guard = makeHeaderGuard(klassName);
Andreas Huber881227d2016-08-02 14:20:21 -0700596
597 out << "#ifndef " << guard << "\n";
598 out << "#define " << guard << "\n\n";
599
600 std::vector<std::string> packageComponents;
601 getPackageAndVersionComponents(
602 &packageComponents, false /* cpp_compatible */);
603
604 out << "#include <";
605 for (const auto &component : packageComponents) {
606 out << component << "/";
607 }
Steven Moreland40786312016-08-16 10:29:40 -0700608 out << "IHw" << baseName << ".h>\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700609
610 enterLeaveNamespace(out, true /* enter */);
611 out << "\n";
612
613 out << "struct "
614 << "Bn"
615 << baseName
Steven Moreland40786312016-08-16 10:29:40 -0700616 << " : public ::android::hardware::BnInterface<I"
617 << baseName << ", IHw" << baseName
Andreas Huber881227d2016-08-02 14:20:21 -0700618 << "> {\n";
619
620 out.indent();
Steven Moreland40786312016-08-16 10:29:40 -0700621 out << "explicit Bn"
622 << baseName
623 << "(const ::android::sp<" << ifaceName << "> &_hidl_impl);"
624 << "\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700625 out << "::android::status_t onTransact(\n";
626 out.indent();
627 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -0700628 out << "uint32_t _hidl_code,\n";
629 out << "const ::android::hardware::Parcel &_hidl_data,\n";
630 out << "::android::hardware::Parcel *_hidl_reply,\n";
631 out << "uint32_t _hidl_flags = 0,\n";
Iliyan Malchev62c3d182016-08-16 20:33:39 -0700632 out << "TransactCallback _hidl_cb = nullptr) override;\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700633 out.unindent();
634 out.unindent();
635
Steven Moreland9c387612016-09-07 09:54:26 -0700636 status_t err = generateMethods(out,
637 "" /* class name */,
638 MethodLocation::STUB_HEADER,
639 true /* specify namespaces */);
640
641 if (err != OK) {
642 return err;
643 }
644
Zhuoyao Zhangde578002016-09-07 18:24:17 -0700645
Andreas Huber881227d2016-08-02 14:20:21 -0700646 out.unindent();
Zhuoyao Zhang8f492942016-09-28 14:27:56 -0700647 out << "private:\n";
648
649 out.indent();
650 emitCppInstrumentationDecl(out);
651 out.unindent();
Andreas Huber881227d2016-08-02 14:20:21 -0700652
653 out << "};\n\n";
654
655 enterLeaveNamespace(out, false /* enter */);
656
657 out << "\n#endif // " << guard << "\n";
658
659 return OK;
660}
661
Andreas Huberb82318c2016-08-02 14:45:54 -0700662status_t AST::generateProxyHeader(const std::string &outputPath) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700663 std::string ifaceName;
664 if (!AST::isInterface(&ifaceName)) {
665 // types.hal does not get a proxy header.
666 return OK;
667 }
668
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700669 const Interface *iface = mRootScope->getInterface();
670 const std::string baseName = iface->getBaseName();
Andreas Huber881227d2016-08-02 14:20:21 -0700671
Andreas Huberb82318c2016-08-02 14:45:54 -0700672 std::string path = outputPath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700673 path.append(mCoordinator->convertPackageRootToPath(mPackage));
Andreas Huberdca261f2016-08-04 13:47:51 -0700674 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
Andreas Huber881227d2016-08-02 14:20:21 -0700675 path.append("Bp");
676 path.append(baseName);
677 path.append(".h");
678
Andreas Huberd2943e12016-08-05 11:59:31 -0700679 CHECK(Coordinator::MakeParentHierarchy(path));
Andreas Huber881227d2016-08-02 14:20:21 -0700680 FILE *file = fopen(path.c_str(), "w");
681
682 if (file == NULL) {
683 return -errno;
684 }
685
686 Formatter out(file);
687
688 const std::string guard = makeHeaderGuard("Bp" + baseName);
689
690 out << "#ifndef " << guard << "\n";
691 out << "#define " << guard << "\n\n";
692
693 std::vector<std::string> packageComponents;
694 getPackageAndVersionComponents(
695 &packageComponents, false /* cpp_compatible */);
696
697 out << "#include <";
698 for (const auto &component : packageComponents) {
699 out << component << "/";
700 }
Steven Moreland40786312016-08-16 10:29:40 -0700701 out << "IHw" << baseName << ".h>\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700702
703 enterLeaveNamespace(out, true /* enter */);
704 out << "\n";
705
706 out << "struct "
707 << "Bp"
708 << baseName
Steven Moreland40786312016-08-16 10:29:40 -0700709 << " : public ::android::hardware::BpInterface<IHw"
710 << baseName
Andreas Huber881227d2016-08-02 14:20:21 -0700711 << "> {\n";
712
713 out.indent();
714
715 out << "explicit Bp"
716 << baseName
Iliyan Malchev549e2592016-08-10 08:59:12 -0700717 << "(const ::android::sp<::android::hardware::IBinder> &_hidl_impl);"
Andreas Huber881227d2016-08-02 14:20:21 -0700718 << "\n\n";
719
Iliyan Malchev795dd432016-09-02 11:48:26 -0700720 out << "virtual bool isRemote() const { return true; }\n\n";
Steven Moreland40786312016-08-16 10:29:40 -0700721
Steven Moreland9c387612016-09-07 09:54:26 -0700722 status_t err = generateMethods(out,
723 "" /* class name */,
724 MethodLocation::PROXY_HEADER,
725 true /* generate specify namespaces */);
726
727 if (err != OK) {
728 return err;
729 }
Andreas Huber881227d2016-08-02 14:20:21 -0700730
731 out.unindent();
Zhuoyao Zhang8f492942016-09-28 14:27:56 -0700732 out << "private:\n";
733
734 out.indent();
735 emitCppInstrumentationDecl(out);
736
737 out.unindent();
Andreas Huber881227d2016-08-02 14:20:21 -0700738
739 out << "};\n\n";
740
741 enterLeaveNamespace(out, false /* enter */);
742
743 out << "\n#endif // " << guard << "\n";
744
745 return OK;
746}
747
Andreas Huberb82318c2016-08-02 14:45:54 -0700748status_t AST::generateAllSource(const std::string &outputPath) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700749
Andreas Huberb82318c2016-08-02 14:45:54 -0700750 std::string path = outputPath;
Andreas Huberd2943e12016-08-05 11:59:31 -0700751 path.append(mCoordinator->convertPackageRootToPath(mPackage));
Andreas Huberdca261f2016-08-04 13:47:51 -0700752 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
Andreas Huber881227d2016-08-02 14:20:21 -0700753
754 std::string ifaceName;
755 std::string baseName;
756
757 bool isInterface = true;
758 if (!AST::isInterface(&ifaceName)) {
759 baseName = "types";
760 isInterface = false;
761 } else {
Jayant Chowdhary3f32c1f2016-09-15 16:53:56 -0700762 const Interface *iface = mRootScope->getInterface();
763 baseName = iface->getBaseName();
Andreas Huber881227d2016-08-02 14:20:21 -0700764 }
765
766 path.append(baseName);
767
768 if (baseName != "types") {
769 path.append("All");
770 }
771
772 path.append(".cpp");
773
Andreas Huberd2943e12016-08-05 11:59:31 -0700774 CHECK(Coordinator::MakeParentHierarchy(path));
Andreas Huber881227d2016-08-02 14:20:21 -0700775 FILE *file = fopen(path.c_str(), "w");
776
777 if (file == NULL) {
778 return -errno;
779 }
780
781 Formatter out(file);
782
783 std::vector<std::string> packageComponents;
784 getPackageAndVersionComponents(
785 &packageComponents, false /* cpp_compatible */);
786
787 std::string prefix;
788 for (const auto &component : packageComponents) {
789 prefix += component;
790 prefix += "/";
791 }
792
793 if (isInterface) {
794 out << "#include <" << prefix << "/Bp" << baseName << ".h>\n";
795 out << "#include <" << prefix << "/Bn" << baseName << ".h>\n";
Steven Moreland69e7c702016-09-09 11:16:32 -0700796 out << "#include <" << prefix << "/Bs" << baseName << ".h>\n";
Zhuoyao Zhangde578002016-09-07 18:24:17 -0700797 out << "#include <cutils/properties.h>\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700798 } else {
799 out << "#include <" << prefix << "types.h>\n";
800 }
801
802 out << "\n";
803
804 enterLeaveNamespace(out, true /* enter */);
805 out << "\n";
806
807 status_t err = generateTypeSource(out, ifaceName);
808
809 if (err == OK && isInterface) {
Martijn Coenena21f1492016-09-08 15:55:14 +0200810 out << "constexpr hidl_version " << ifaceName << "::version;\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700811 err = generateProxySource(out, baseName);
812 }
813
814 if (err == OK && isInterface) {
815 err = generateStubSource(out, baseName);
816 }
817
Steven Moreland40786312016-08-16 10:29:40 -0700818 if (err == OK && isInterface) {
Steven Moreland69e7c702016-09-09 11:16:32 -0700819 err = generatePassthroughSource(out);
820 }
821
822 if (err == OK && isInterface) {
Steven Moreland9c387612016-09-07 09:54:26 -0700823 const Interface *iface = mRootScope->getInterface();
824
825 out << "IMPLEMENT_REGISTER_AND_GET_SERVICE("
826 << baseName << ", "
827 << "\"" << iface->fqName().package()
Iliyan Malchev4923f932016-09-09 13:04:59 -0700828 << iface->fqName().version() << "-impl.so\""
Steven Moreland9c387612016-09-07 09:54:26 -0700829 << ")\n";
Steven Moreland40786312016-08-16 10:29:40 -0700830 }
831
Andreas Huber881227d2016-08-02 14:20:21 -0700832 enterLeaveNamespace(out, false /* enter */);
833
834 return err;
835}
836
Steven Moreland67f67b42016-09-29 08:59:02 -0700837// static
838void AST::generateCheckNonNull(Formatter &out, const std::string &nonNull) {
839 out << "if (" << nonNull << " == nullptr) {\n";
840 out.indent();
841 out << "return ::android::hardware::Status::fromExceptionCode(\n";
842 out.indent();
843 out.indent();
844 out << "::android::hardware::Status::EX_ILLEGAL_ARGUMENT);\n";
845 out.unindent();
846 out.unindent();
847 out.unindent();
848 out << "}\n\n";
849}
850
Andreas Huber881227d2016-08-02 14:20:21 -0700851status_t AST::generateTypeSource(
852 Formatter &out, const std::string &ifaceName) const {
853 return mRootScope->emitTypeDefinitions(out, ifaceName);
854}
855
Andreas Hubere7ff2282016-08-16 13:50:03 -0700856void AST::declareCppReaderLocals(
Andreas Huber5e44a292016-09-27 14:52:39 -0700857 Formatter &out,
858 const std::vector<TypedVar *> &args,
859 bool forResults) const {
Andreas Hubere7ff2282016-08-16 13:50:03 -0700860 if (args.empty()) {
861 return;
862 }
863
864 for (const auto &arg : args) {
865 const Type &type = arg->type();
866
867 std::string extra;
868 out << type.getCppResultType(&extra)
869 << " "
Andreas Huber5e44a292016-09-27 14:52:39 -0700870 << (forResults ? "_hidl_out_" : "")
Andreas Hubere7ff2282016-08-16 13:50:03 -0700871 << arg->name()
872 << extra
873 << ";\n";
874 }
875
876 out << "\n";
877}
878
Andreas Huber881227d2016-08-02 14:20:21 -0700879void AST::emitCppReaderWriter(
880 Formatter &out,
881 const std::string &parcelObj,
882 bool parcelObjIsPointer,
883 const TypedVar *arg,
884 bool isReader,
Andreas Huber5e44a292016-09-27 14:52:39 -0700885 Type::ErrorMode mode,
886 bool addPrefixToName) const {
Andreas Huber881227d2016-08-02 14:20:21 -0700887 const Type &type = arg->type();
888
Andreas Huber881227d2016-08-02 14:20:21 -0700889 type.emitReaderWriter(
890 out,
Andreas Huber5e44a292016-09-27 14:52:39 -0700891 addPrefixToName ? ("_hidl_out_" + arg->name()) : arg->name(),
Andreas Huber881227d2016-08-02 14:20:21 -0700892 parcelObj,
893 parcelObjIsPointer,
894 isReader,
895 mode);
896}
897
Yifan Hongbf459bc2016-08-23 16:50:37 -0700898void AST::emitCppResolveReferences(
899 Formatter &out,
900 const std::string &parcelObj,
901 bool parcelObjIsPointer,
902 const TypedVar *arg,
903 bool isReader,
904 Type::ErrorMode mode,
905 bool addPrefixToName) const {
906 const Type &type = arg->type();
907 if(type.needsResolveReferences()) {
908 type.emitResolveReferences(
909 out,
910 addPrefixToName ? ("_hidl_out_" + arg->name()) : arg->name(),
911 isReader, // nameIsPointer
912 parcelObj,
913 parcelObjIsPointer,
914 isReader,
915 mode);
916 }
917}
918
Andreas Huber881227d2016-08-02 14:20:21 -0700919status_t AST::generateProxySource(
920 Formatter &out, const std::string &baseName) const {
921 const std::string klassName = "Bp" + baseName;
922
923 out << klassName
924 << "::"
925 << klassName
Iliyan Malchev549e2592016-08-10 08:59:12 -0700926 << "(const ::android::sp<::android::hardware::IBinder> &_hidl_impl)\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700927
928 out.indent();
929 out.indent();
930
931 out << ": BpInterface"
Steven Moreland40786312016-08-16 10:29:40 -0700932 << "<IHw"
Andreas Huber881227d2016-08-02 14:20:21 -0700933 << baseName
Iliyan Malchev549e2592016-08-10 08:59:12 -0700934 << ">(_hidl_impl) {\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700935
Zhuoyao Zhang8f492942016-09-28 14:27:56 -0700936 emitCppInstrumentationInit(out, baseName);
937
Andreas Huber881227d2016-08-02 14:20:21 -0700938 out.unindent();
939 out.unindent();
940 out << "}\n\n";
941
942 const Interface *iface = mRootScope->getInterface();
943
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700944 std::vector<const Interface *> chain;
945 while (iface != NULL) {
946 chain.push_back(iface);
947 iface = iface->superType();
948 }
Andreas Huber881227d2016-08-02 14:20:21 -0700949
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700950 for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
951 const Interface *superInterface = *it;
Andreas Huber881227d2016-08-02 14:20:21 -0700952
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700953 for (const auto &method : superInterface->methods()) {
Steven Moreland979e0992016-09-07 09:18:08 -0700954 method->generateCppSignature(out,
955 klassName,
956 true /* specify namespaces */);
Steven Morelanda7a421a2016-09-07 08:35:18 -0700957
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700958 const bool returnsValue = !method->results().empty();
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700959 const TypedVar *elidedReturn = method->canElideCallback();
Iliyan Malchev40d474a2016-08-16 06:20:17 -0700960
Steven Morelanda7a421a2016-09-07 08:35:18 -0700961 out << "{\n";
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700962
963 out.indent();
964
Steven Moreland67f67b42016-09-29 08:59:02 -0700965 if (returnsValue && elidedReturn == nullptr) {
966 generateCheckNonNull(out, "_hidl_cb");
967 }
968
Zhuoyao Zhang8f492942016-09-28 14:27:56 -0700969 status_t status = generateCppInstrumentationCall(
970 out,
971 InstrumentationEvent::CLIENT_API_ENTRY,
972 superInterface,
973 method);
974 if (status != OK) {
975 return status;
976 }
977
Iliyan Malchev549e2592016-08-10 08:59:12 -0700978 out << "::android::hardware::Parcel _hidl_data;\n";
979 out << "::android::hardware::Parcel _hidl_reply;\n";
Andreas Hubere7ff2282016-08-16 13:50:03 -0700980 out << "::android::status_t _hidl_err;\n";
981 out << "::android::hardware::Status _hidl_status;\n\n";
Andreas Huber5e44a292016-09-27 14:52:39 -0700982
983 declareCppReaderLocals(
984 out, method->results(), true /* forResults */);
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700985
Iliyan Malchev549e2592016-08-10 08:59:12 -0700986 out << "_hidl_err = _hidl_data.writeInterfaceToken("
Steven Moreland40786312016-08-16 10:29:40 -0700987 << superInterface->fqName().cppNamespace()
988 << "::IHw"
989 << superInterface->getBaseName()
990 << "::descriptor);\n";
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700991
Iliyan Malchev549e2592016-08-10 08:59:12 -0700992 out << "if (_hidl_err != ::android::OK) { goto _hidl_error; }\n\n";
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700993
Yifan Hongbf459bc2016-08-23 16:50:37 -0700994 // First DFS: write all buffers and resolve pointers for parent
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700995 for (const auto &arg : method->args()) {
996 emitCppReaderWriter(
997 out,
Iliyan Malchev549e2592016-08-10 08:59:12 -0700998 "_hidl_data",
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700999 false /* parcelObjIsPointer */,
1000 arg,
1001 false /* reader */,
Andreas Huber5e44a292016-09-27 14:52:39 -07001002 Type::ErrorMode_Goto,
1003 false /* addPrefixToName */);
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001004 }
1005
Yifan Hongbf459bc2016-08-23 16:50:37 -07001006 // Second DFS: resolve references.
1007 for (const auto &arg : method->args()) {
1008 emitCppResolveReferences(
1009 out,
1010 "_hidl_data",
1011 false /* parcelObjIsPointer */,
1012 arg,
1013 false /* reader */,
1014 Type::ErrorMode_Goto,
1015 false /* addPrefixToName */);
1016 }
1017
Steven Moreland40786312016-08-16 10:29:40 -07001018 out << "_hidl_err = remote()->transact("
Steven Morelandef1a9fe2016-10-06 17:19:09 -07001019 << method->getSerialId()
1020 << " /* "
1021 << method->name()
1022 << " */, _hidl_data, &_hidl_reply";
1023
Iliyan Malchev639bff82016-08-13 14:24:11 -07001024 if (method->isOneway()) {
1025 out << ", ::android::hardware::IBinder::FLAG_ONEWAY";
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001026 }
Iliyan Malchev639bff82016-08-13 14:24:11 -07001027 out << ");\n";
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001028
Iliyan Malchev639bff82016-08-13 14:24:11 -07001029 out << "if (_hidl_err != ::android::OK) { goto _hidl_error; }\n\n";
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001030
Iliyan Malchev639bff82016-08-13 14:24:11 -07001031 if (!method->isOneway()) {
1032 out << "_hidl_err = _hidl_status.readFromParcel(_hidl_reply);\n";
1033 out << "if (_hidl_err != ::android::OK) { goto _hidl_error; }\n\n";
Iliyan Malchev639bff82016-08-13 14:24:11 -07001034 out << "if (!_hidl_status.isOk()) { return _hidl_status; }\n\n";
1035
Yifan Hongbf459bc2016-08-23 16:50:37 -07001036
1037 // First DFS: write all buffers and resolve pointers for parent
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001038 for (const auto &arg : method->results()) {
Iliyan Malchev639bff82016-08-13 14:24:11 -07001039 emitCppReaderWriter(
1040 out,
1041 "_hidl_reply",
1042 false /* parcelObjIsPointer */,
1043 arg,
1044 true /* reader */,
Andreas Huber5e44a292016-09-27 14:52:39 -07001045 Type::ErrorMode_Goto,
1046 true /* addPrefixToName */);
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001047 }
1048
Yifan Hongbf459bc2016-08-23 16:50:37 -07001049 // Second DFS: resolve references.
1050 for (const auto &arg : method->results()) {
1051 emitCppResolveReferences(
1052 out,
1053 "_hidl_reply",
1054 false /* parcelObjIsPointer */,
1055 arg,
1056 true /* reader */,
1057 Type::ErrorMode_Goto,
1058 true /* addPrefixToName */);
1059 }
1060
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001061 if (returnsValue && elidedReturn == nullptr) {
Iliyan Malchev639bff82016-08-13 14:24:11 -07001062 out << "_hidl_cb(";
1063
1064 bool first = true;
1065 for (const auto &arg : method->results()) {
1066 if (!first) {
1067 out << ", ";
1068 }
1069
1070 if (arg->type().resultNeedsDeref()) {
1071 out << "*";
1072 }
Andreas Huber5e44a292016-09-27 14:52:39 -07001073 out << "_hidl_out_" << arg->name();
Iliyan Malchev639bff82016-08-13 14:24:11 -07001074
1075 first = false;
1076 }
1077
Steven Moreland67f67b42016-09-29 08:59:02 -07001078 out << ");\n\n";
Iliyan Malchev639bff82016-08-13 14:24:11 -07001079 }
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001080 status_t status = generateCppInstrumentationCall(
1081 out,
1082 InstrumentationEvent::CLIENT_API_EXIT,
1083 superInterface,
1084 method);
1085 if (status != OK) {
1086 return status;
1087 }
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001088 }
1089
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001090 if (elidedReturn != nullptr) {
1091 std::string extra;
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001092 out << "_hidl_status.setFromStatusT(_hidl_err);\n";
Iliyan Malchev2b6591b2016-08-18 19:15:19 -07001093 out << "return ::android::hardware::Return<";
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001094 out << elidedReturn->type().getCppResultType(&extra)
Andreas Huber5e44a292016-09-27 14:52:39 -07001095 << ">(_hidl_out_" << elidedReturn->name() << ");\n\n";
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001096 } else {
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001097 out << "_hidl_status.setFromStatusT(_hidl_err);\n";
Iliyan Malchevd57066f2016-09-08 13:59:38 -07001098 out << "return ::android::hardware::Return<void>();\n\n";
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001099 }
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001100
Andreas Huber881227d2016-08-02 14:20:21 -07001101 out.unindent();
Iliyan Malchevd57066f2016-09-08 13:59:38 -07001102 out << "_hidl_error:\n";
1103 out.indent();
1104 out << "_hidl_status.setFromStatusT(_hidl_err);\n";
1105 out << "return ::android::hardware::Return<";
1106 if (elidedReturn != nullptr) {
1107 std::string extra;
1108 out << method->results().at(0)->type().getCppResultType(&extra);
1109 } else {
1110 out << "void";
1111 }
1112 out << ">(_hidl_status);\n";
1113
1114 out.unindent();
Andreas Huber881227d2016-08-02 14:20:21 -07001115 out << "}\n\n";
1116 }
Andreas Huber881227d2016-08-02 14:20:21 -07001117 }
1118
1119 return OK;
1120}
1121
1122status_t AST::generateStubSource(
1123 Formatter &out, const std::string &baseName) const {
1124 out << "IMPLEMENT_HWBINDER_META_INTERFACE("
1125 << baseName
1126 << ", \""
1127 << mPackage.string()
1128 << "::I"
1129 << baseName
1130 << "\");\n\n";
1131
1132 const std::string klassName = "Bn" + baseName;
1133
Steven Moreland40786312016-08-16 10:29:40 -07001134 out << klassName
1135 << "::"
1136 << klassName
1137 << "(const ::android::sp<I" << baseName <<"> &_hidl_impl)\n";
1138
1139 out.indent();
1140 out.indent();
1141
1142 out << ": BnInterface"
1143 << "<I"
1144 << baseName
1145 << ", IHw"
1146 << baseName
1147 << ">(_hidl_impl) {\n";
1148
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001149 emitCppInstrumentationInit(out, baseName);
Steven Moreland40786312016-08-16 10:29:40 -07001150 out.unindent();
1151 out.unindent();
1152 out << "}\n\n";
1153
Andreas Huber881227d2016-08-02 14:20:21 -07001154 out << "::android::status_t " << klassName << "::onTransact(\n";
1155
1156 out.indent();
1157 out.indent();
1158
Iliyan Malchev549e2592016-08-10 08:59:12 -07001159 out << "uint32_t _hidl_code,\n"
1160 << "const ::android::hardware::Parcel &_hidl_data,\n"
1161 << "::android::hardware::Parcel *_hidl_reply,\n"
1162 << "uint32_t _hidl_flags,\n"
1163 << "TransactCallback _hidl_cb) {\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001164
1165 out.unindent();
1166
Iliyan Malchev549e2592016-08-10 08:59:12 -07001167 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
Iliyan Malchev549e2592016-08-10 08:59:12 -07001168 out << "switch (_hidl_code) {\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001169 out.indent();
1170
1171 const Interface *iface = mRootScope->getInterface();
1172
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001173 std::vector<const Interface *> chain;
1174 while (iface != NULL) {
1175 chain.push_back(iface);
1176 iface = iface->superType();
1177 }
Andreas Huber881227d2016-08-02 14:20:21 -07001178
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001179 for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
1180 const Interface *superInterface = *it;
Andreas Huber881227d2016-08-02 14:20:21 -07001181
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001182 for (const auto &method : superInterface->methods()) {
1183 out << "case "
Steven Morelandef1a9fe2016-10-06 17:19:09 -07001184 << method->getSerialId()
1185 << " /* "
1186 << method->name()
1187 << " */:\n{\n";
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001188
1189 out.indent();
1190
1191 status_t err =
1192 generateStubSourceForMethod(out, superInterface, method);
1193
1194 if (err != OK) {
1195 return err;
1196 }
1197
1198 out.unindent();
1199 out << "}\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001200 }
Andreas Huber881227d2016-08-02 14:20:21 -07001201 }
1202
1203 out << "default:\n{\n";
1204 out.indent();
1205
Andreas Huber8a82ff72016-08-04 10:29:39 -07001206 out << "return ::android::hardware::BnInterface<I"
Steven Moreland40786312016-08-16 10:29:40 -07001207 << baseName << ", IHw" << baseName
Andreas Huber881227d2016-08-02 14:20:21 -07001208 << ">::onTransact(\n";
1209
1210 out.indent();
1211 out.indent();
1212
Iliyan Malchev549e2592016-08-10 08:59:12 -07001213 out << "_hidl_code, _hidl_data, _hidl_reply, "
1214 << "_hidl_flags, _hidl_cb);\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001215
1216 out.unindent();
1217 out.unindent();
1218
1219 out.unindent();
1220 out << "}\n";
1221
1222 out.unindent();
1223 out << "}\n\n";
1224
Iliyan Malchev549e2592016-08-10 08:59:12 -07001225 out << "if (_hidl_err == ::android::UNEXPECTED_NULL) {\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001226 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -07001227 out << "_hidl_err = ::android::hardware::Status::fromExceptionCode(\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001228 out.indent();
1229 out.indent();
Andreas Huber8a82ff72016-08-04 10:29:39 -07001230 out << "::android::hardware::Status::EX_NULL_POINTER)\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001231 out.indent();
1232 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -07001233 out << ".writeToParcel(_hidl_reply);\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001234 out.unindent();
1235 out.unindent();
1236 out.unindent();
1237 out.unindent();
1238
1239 out.unindent();
1240 out << "}\n\n";
1241
Iliyan Malchev549e2592016-08-10 08:59:12 -07001242 out << "return _hidl_err;\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001243
1244 out.unindent();
1245 out << "}\n\n";
1246
1247 return OK;
1248}
1249
1250status_t AST::generateStubSourceForMethod(
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001251 Formatter &out, const Interface *iface, const Method *method) const {
Iliyan Malchev549e2592016-08-10 08:59:12 -07001252 out << "if (!_hidl_data.enforceInterface("
Steven Moreland40786312016-08-16 10:29:40 -07001253 << iface->fqName().cppNamespace()
1254 << "::IHw"
1255 << iface->getBaseName()
1256 << "::descriptor)) {\n";
Andreas Huber6cb08cf2016-08-03 15:44:51 -07001257
Andreas Huber881227d2016-08-02 14:20:21 -07001258 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -07001259 out << "_hidl_err = ::android::BAD_TYPE;\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001260 out << "break;\n";
1261 out.unindent();
1262 out << "}\n\n";
1263
Andreas Huber5e44a292016-09-27 14:52:39 -07001264 declareCppReaderLocals(out, method->args(), false /* forResults */);
Andreas Hubere7ff2282016-08-16 13:50:03 -07001265
Yifan Hongbf459bc2016-08-23 16:50:37 -07001266 // First DFS: write buffers
Andreas Huber881227d2016-08-02 14:20:21 -07001267 for (const auto &arg : method->args()) {
1268 emitCppReaderWriter(
1269 out,
Iliyan Malchev549e2592016-08-10 08:59:12 -07001270 "_hidl_data",
Andreas Huber881227d2016-08-02 14:20:21 -07001271 false /* parcelObjIsPointer */,
1272 arg,
1273 true /* reader */,
Andreas Huber5e44a292016-09-27 14:52:39 -07001274 Type::ErrorMode_Break,
1275 false /* addPrefixToName */);
Andreas Huber881227d2016-08-02 14:20:21 -07001276 }
1277
Yifan Hongbf459bc2016-08-23 16:50:37 -07001278 // Second DFS: resolve references
1279 for (const auto &arg : method->args()) {
1280 emitCppResolveReferences(
1281 out,
1282 "_hidl_data",
1283 false /* parcelObjIsPointer */,
1284 arg,
1285 true /* reader */,
1286 Type::ErrorMode_Break,
1287 false /* addPrefixToName */);
1288 }
1289
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001290 status_t status = generateCppInstrumentationCall(
1291 out,
1292 InstrumentationEvent::SERVER_API_ENTRY,
1293 iface,
1294 method);
1295 if (status != OK) {
1296 return status;
Zhuoyao Zhangde578002016-09-07 18:24:17 -07001297 }
1298
Andreas Huber881227d2016-08-02 14:20:21 -07001299 const bool returnsValue = !method->results().empty();
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001300 const TypedVar *elidedReturn = method->canElideCallback();
Andreas Huber881227d2016-08-02 14:20:21 -07001301
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001302 if (elidedReturn != nullptr) {
1303 std::string extra;
Andreas Huber881227d2016-08-02 14:20:21 -07001304
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001305 out << elidedReturn->type().getCppResultType(&extra) << " ";
1306 out << elidedReturn->name() << " = ";
1307 out << method->name() << "(";
Andreas Huber881227d2016-08-02 14:20:21 -07001308
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001309 bool first = true;
1310 for (const auto &arg : method->args()) {
Andreas Huber881227d2016-08-02 14:20:21 -07001311 if (!first) {
1312 out << ", ";
1313 }
1314
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001315 if (arg->type().resultNeedsDeref()) {
1316 out << "*";
1317 }
1318
1319 out << arg->name();
Andreas Huber881227d2016-08-02 14:20:21 -07001320
1321 first = false;
1322 }
1323
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001324 out << ");\n\n";
Andreas Huber8a82ff72016-08-04 10:29:39 -07001325 out << "::android::hardware::Status::ok()"
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001326 << ".writeToParcel(_hidl_reply);\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -07001327
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001328 elidedReturn->type().emitReaderWriter(
1329 out,
1330 elidedReturn->name(),
1331 "_hidl_reply",
1332 true, /* parcelObjIsPointer */
1333 false, /* isReader */
1334 Type::ErrorMode_Ignore);
Andreas Huber881227d2016-08-02 14:20:21 -07001335
Yifan Hongbf459bc2016-08-23 16:50:37 -07001336 emitCppResolveReferences(
1337 out,
1338 "_hidl_reply",
1339 true /* parcelObjIsPointer */,
1340 elidedReturn,
1341 false /* reader */,
1342 Type::ErrorMode_Ignore,
1343 false /* addPrefixToName */);
1344
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001345 status_t status = generateCppInstrumentationCall(
1346 out,
1347 InstrumentationEvent::SERVER_API_EXIT,
1348 iface,
1349 method);
1350 if (status != OK) {
1351 return status;
1352 }
Zhuoyao Zhangde578002016-09-07 18:24:17 -07001353
Iliyan Malchev549e2592016-08-10 08:59:12 -07001354 out << "_hidl_cb(*_hidl_reply);\n";
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001355 } else {
1356 if (returnsValue) {
1357 out << "bool _hidl_callbackCalled = false;\n\n";
1358 }
Andreas Huber881227d2016-08-02 14:20:21 -07001359
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001360 out << method->name() << "(";
Andreas Huber881227d2016-08-02 14:20:21 -07001361
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001362 bool first = true;
1363 for (const auto &arg : method->args()) {
1364 if (!first) {
1365 out << ", ";
1366 }
Andreas Huber881227d2016-08-02 14:20:21 -07001367
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001368 if (arg->type().resultNeedsDeref()) {
1369 out << "*";
1370 }
1371
1372 out << arg->name();
1373
1374 first = false;
1375 }
1376
1377 if (returnsValue) {
1378 if (!first) {
1379 out << ", ";
1380 }
1381
1382 out << "[&](";
1383
1384 first = true;
1385 for (const auto &arg : method->results()) {
1386 if (!first) {
1387 out << ", ";
1388 }
1389
1390 out << "const auto &" << arg->name();
1391
1392 first = false;
1393 }
1394
1395 out << ") {\n";
1396 out.indent();
1397 out << "_hidl_callbackCalled = true;\n\n";
1398
1399 out << "::android::hardware::Status::ok()"
1400 << ".writeToParcel(_hidl_reply);\n\n";
1401
Yifan Hongbf459bc2016-08-23 16:50:37 -07001402 // First DFS: buffers
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001403 for (const auto &arg : method->results()) {
1404 emitCppReaderWriter(
1405 out,
1406 "_hidl_reply",
1407 true /* parcelObjIsPointer */,
1408 arg,
1409 false /* reader */,
Andreas Huber5e44a292016-09-27 14:52:39 -07001410 Type::ErrorMode_Ignore,
1411 false /* addPrefixToName */);
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001412 }
1413
Yifan Hongbf459bc2016-08-23 16:50:37 -07001414 // Second DFS: resolve references
1415 for (const auto &arg : method->results()) {
1416 emitCppResolveReferences(
1417 out,
1418 "_hidl_reply",
1419 true /* parcelObjIsPointer */,
1420 arg,
1421 false /* reader */,
1422 Type::ErrorMode_Ignore,
1423 false /* addPrefixToName */);
1424 }
1425
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001426 status_t status = generateCppInstrumentationCall(
1427 out,
1428 InstrumentationEvent::SERVER_API_EXIT,
1429 iface,
1430 method);
1431 if (status != OK) {
1432 return status;
Zhuoyao Zhangde578002016-09-07 18:24:17 -07001433 }
1434
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001435 out << "_hidl_cb(*_hidl_reply);\n";
1436
1437 out.unindent();
1438 out << "}\n";
1439 }
1440
Iliyan Malchevd57066f2016-09-08 13:59:38 -07001441 out << ");\n\n";
1442
1443 // What to do if the stub implementation has a synchronous callback
1444 // which does not get invoked? This is not a transport error but a
1445 // service error of sorts. For now, return OK to the caller, as this is
1446 // not a transport error.
1447 //
1448 // TODO(b/31365311) Figure out how to deal with this later.
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001449
1450 if (returnsValue) {
1451 out << "if (!_hidl_callbackCalled) {\n";
1452 out.indent();
1453 }
1454
Iliyan Malchevd57066f2016-09-08 13:59:38 -07001455 out << "::android::hardware::Status::ok()"
1456 << ".writeToParcel(_hidl_reply);\n";
Iliyan Malchev40d474a2016-08-16 06:20:17 -07001457
1458 if (returnsValue) {
1459 out.unindent();
1460 out << "}\n\n";
1461 }
Andreas Huber881227d2016-08-02 14:20:21 -07001462 }
1463
1464 out << "break;\n";
1465
1466 return OK;
1467}
1468
Steven Moreland69e7c702016-09-09 11:16:32 -07001469status_t AST::generatePassthroughHeader(const std::string &outputPath) const {
1470 std::string ifaceName;
1471 if (!AST::isInterface(&ifaceName)) {
1472 // types.hal does not get a stub header.
1473 return OK;
1474 }
1475
1476 const Interface *iface = mRootScope->getInterface();
1477
1478 const std::string baseName = iface->getBaseName();
1479 const std::string klassName = "Bs" + baseName;
1480
1481 bool supportOneway = iface->hasOnewayMethods();
1482
1483 std::string path = outputPath;
1484 path.append(mCoordinator->convertPackageRootToPath(mPackage));
1485 path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
1486 path.append(klassName);
1487 path.append(".h");
1488
1489 CHECK(Coordinator::MakeParentHierarchy(path));
1490 FILE *file = fopen(path.c_str(), "w");
1491
1492 if (file == NULL) {
1493 return -errno;
1494 }
1495
1496 Formatter out(file);
1497
1498 const std::string guard = makeHeaderGuard(klassName);
1499
1500 out << "#ifndef " << guard << "\n";
1501 out << "#define " << guard << "\n\n";
1502
1503 std::vector<std::string> packageComponents;
1504 getPackageAndVersionComponents(
1505 &packageComponents, false /* cpp_compatible */);
1506
1507 out << "#include <future>\n";
1508 out << "#include <";
1509 for (const auto &component : packageComponents) {
1510 out << component << "/";
1511 }
1512 out << ifaceName << ".h>\n\n";
1513
1514 if (supportOneway) {
1515 out << "#include <hidl/SynchronizedQueue.h>\n";
1516 }
1517
1518 enterLeaveNamespace(out, true /* enter */);
1519 out << "\n";
1520
1521 out << "struct "
1522 << klassName
1523 << " : " << ifaceName
1524 << " {\n";
1525
1526 out.indent();
1527 out << "explicit "
1528 << klassName
1529 << "(const sp<"
1530 << ifaceName
1531 << "> impl);\n";
1532
1533 status_t err = generateMethods(out,
1534 "" /* class name */,
1535 MethodLocation::PASSTHROUGH_HEADER,
1536 true /* specify namespaces */);
1537
1538 if (err != OK) {
1539 return err;
1540 }
1541
1542 out.unindent();
1543 out << "private:\n";
1544 out.indent();
1545 out << "const sp<" << ifaceName << "> mImpl;\n";
1546
1547 if (supportOneway) {
1548 out << "SynchronizedQueue<std::function<void(void)>> mOnewayQueue;\n";
1549 out << "std::thread *mOnewayThread = nullptr;\n";
1550
1551 out << "\n";
1552
1553 out << "::android::hardware::Return<void> addOnewayTask("
1554 "std::function<void(void)>);\n\n";
1555
1556 out << "static const int kOnewayQueueMaxSize = 3000;\n";
1557 }
1558
1559 out.unindent();
1560
1561 out << "};\n\n";
1562
1563 enterLeaveNamespace(out, false /* enter */);
1564
1565 out << "\n#endif // " << guard << "\n";
1566
1567 return OK;
1568}
1569
1570
1571status_t AST::generatePassthroughSource(Formatter &out) const {
1572 const Interface *iface = mRootScope->getInterface();
1573
1574 const std::string baseName = iface->getBaseName();
1575 const std::string klassName = "Bs" + baseName;
1576
1577 out << klassName
1578 << "::"
1579 << klassName
1580 << "(const sp<"
1581 << iface->fullName()
1582 << "> impl) : mImpl(impl) {}\n\n";
1583
1584 if (iface->hasOnewayMethods()) {
1585 out << "::android::hardware::Return<void> "
1586 << klassName
1587 << "::addOnewayTask(std::function<void(void)> fun) {\n";
1588 out.indent();
1589 out << "if (mOnewayThread == nullptr) {\n";
1590 out.indent();
1591 out << "mOnewayThread = new std::thread([this]() {\n";
1592 out.indent();
1593 out << "while(true) { (this->mOnewayQueue.wait_pop())(); }";
1594 out.unindent();
1595 out << "});\n";
1596 out.unindent();
1597 out << "}\n\n";
1598
1599 out << "if (mOnewayQueue.size() > kOnewayQueueMaxSize) {\n";
1600 out.indent();
Steven Moreland67f67b42016-09-29 08:59:02 -07001601 out << "return ::android::hardware::Status::fromExceptionCode(\n";
1602 out.indent();
1603 out.indent();
1604 out << "::android::hardware::Status::EX_TRANSACTION_FAILED);\n";
1605 out.unindent();
1606 out.unindent();
Steven Moreland69e7c702016-09-09 11:16:32 -07001607 out.unindent();
1608 out << "} else {\n";
1609 out.indent();
1610 out << "mOnewayQueue.push(fun);\n";
1611 out.unindent();
1612 out << "}\n";
1613
Steven Morelandd366c262016-10-11 15:29:10 -07001614 out << "return ::android::hardware::Status();\n";
Steven Moreland69e7c702016-09-09 11:16:32 -07001615
1616 out.unindent();
1617 out << "}\n\n";
1618
1619
1620 }
1621
1622 return OK;
1623}
1624
Zhuoyao Zhang8f492942016-09-28 14:27:56 -07001625status_t AST::generateCppInstrumentationCall(
1626 Formatter &out,
1627 InstrumentationEvent event,
1628 const Interface *iface, const Method *method) const {
1629 out << "if (UNLIKELY(mEnableInstrumentation)) {\n";
1630 out.indent();
1631 out << "std::vector<void *> args;\n";
1632 std::string event_str = "";
1633 switch (event) {
1634 case SERVER_API_ENTRY:
1635 {
1636 event_str = "InstrumentationEvent::SERVER_API_ENTRY";
1637 for (const auto &arg : method->args()) {
1638 out << "args.push_back((void *)"
1639 << (arg->type().resultNeedsDeref() ? "" : "&")
1640 << arg->name()
1641 << ");\n";
1642 }
1643 break;
1644 }
1645 case SERVER_API_EXIT:
1646 {
1647 event_str = "InstrumentationEvent::SERVER_API_EXIT";
1648 const TypedVar *elidedReturn = method->canElideCallback();
1649 if (elidedReturn != nullptr) {
1650 out << "args.push_back((void *)&" << elidedReturn->name()
1651 << ");\n";
1652 } else {
1653 for (const auto &arg : method->results()) {
1654 out << "args.push_back((void *)&" << arg->name()
1655 << ");\n";
1656 }
1657 }
1658 break;
1659 }
1660 case CLIENT_API_ENTRY:
1661 {
1662 event_str = "InstrumentationEvent::CLIENT_API_ENTRY";
1663 for (const auto &arg : method->args()) {
1664 out << "args.push_back((void *)&" << arg->name() << ");\n";
1665 }
1666 break;
1667 }
1668 case CLIENT_API_EXIT:
1669 {
1670 event_str = "InstrumentationEvent::CLIENT_API_EXIT";
1671 for (const auto &arg : method->results()) {
1672 out << "args.push_back((void *)"
1673 << (arg->type().resultNeedsDeref() ? "" : "&")
1674 << "_hidl_out_" << arg->name()
1675 << ");\n";
1676 }
1677 break;
1678 }
1679 case SYNC_CALLBACK_ENTRY:
1680 case SYNC_CALLBACK_EXIT:
1681 case ASYNC_CALLBACK_ENTRY:
1682 case ASYNC_CALLBACK_EXIT:
1683 {
1684 LOG(ERROR) << "Not supported instrumentation event: " << event;
1685 return UNKNOWN_ERROR;
1686 }
1687 }
1688
1689 out << "for (auto callback: mInstrumentationCallbacks) {\n";
1690 out.indent();
1691 out << "callback("
1692 << event_str
1693 << ", \""
1694 << mPackage.package()
1695 << "\", \""
1696 << mPackage.getPackageFullVersion()
1697 << "\", \""
1698 << iface->localName()
1699 << "\", \""
1700 << method->name()
1701 << "\", &args);\n";
1702 out.unindent();
1703 out << "}\n";
1704 out.unindent();
1705 out << "}\n\n";
1706
1707 return OK;
1708}
1709
1710void AST::emitCppInstrumentationDecl(
1711 Formatter &out) const {
1712 out << "// for hidl instrumentation.\n";
1713 out << "std::vector<InstrumentationCallback> mInstrumentationCallbacks;\n";
1714 out << "bool mEnableInstrumentation;\n";
1715}
1716
1717void AST::emitCppInstrumentationInit(
1718 Formatter &out, const std::string &baseName) const {
1719 out << "mEnableInstrumentation = "
1720 "property_get_bool(\"hal.instrumentation.enable\", false);\n";
1721 out << "registerInstrumentationCallbacks(\""
1722 << mPackage.string()
1723 << "::I"
1724 << baseName
1725 << "\", &mInstrumentationCallbacks);\n";
1726}
1727
Andreas Huber881227d2016-08-02 14:20:21 -07001728} // namespace android
1729