blob: f9b11897d9968bdd531111523655db2c8b4bcba0 [file] [log] [blame]
Andreas Huber881227d2016-08-02 14:20:21 -07001#include "AST.h"
2
3#include "Coordinator.h"
4#include "Formatter.h"
5#include "Interface.h"
6#include "Method.h"
7#include "Scope.h"
8
9#include <android-base/logging.h>
10#include <sys/stat.h>
11#include <vector>
12
13namespace android {
14
15static bool MakeParentHierarchy(const std::string &path) {
16 static const mode_t kMode = 0755;
17
18 size_t start = 1; // Ignore leading '/'
19 size_t slashPos;
20 while ((slashPos = path.find("/", start)) != std::string::npos) {
21 std::string partial = path.substr(0, slashPos);
22
23 struct stat st;
24 if (stat(partial.c_str(), &st) < 0) {
25 if (errno != ENOENT) {
26 return false;
27 }
28
29 int res = mkdir(partial.c_str(), kMode);
30 if (res < 0) {
31 return false;
32 }
33 } else if (!S_ISDIR(st.st_mode)) {
34 return false;
35 }
36
37 start = slashPos + 1;
38 }
39
40 return true;
41}
42
43static void SplitString(
44 const std::string &s, char c, std::vector<std::string> *components) {
45 components->clear();
46
47 size_t startPos = 0;
48 size_t matchPos;
49 while ((matchPos = s.find(c, startPos)) != std::string::npos) {
50 components->push_back(s.substr(startPos, matchPos - startPos));
51 startPos = matchPos + 1;
52 }
53
54 if (startPos + 1 < s.length()) {
55 components->push_back(s.substr(startPos));
56 }
57}
58
59static std::string upcase(const std::string in) {
60 std::string out{in};
61
62 for (auto &ch : out) {
63 ch = toupper(ch);
64 }
65
66 return out;
67}
68
69status_t AST::generateCpp() const {
70 status_t err = generateInterfaceHeader();
71
72 if (err == OK) {
73 err = generateStubHeader();
74 }
75
76 if (err == OK) {
77 err = generateProxyHeader();
78 }
79
80 if (err == OK) {
81 err = generateAllSource();
82 }
83
84 return err;
85}
86
87void AST::getPackageComponents(
88 std::vector<std::string> *components) const {
89 SplitString(mPackage.package(), '.', components);
90}
91
92void AST::getPackageAndVersionComponents(
93 std::vector<std::string> *components, bool cpp_compatible) const {
94 getPackageComponents(components);
95
96 const std::string packageVersion = mPackage.version();
97 CHECK(packageVersion[0] == '@');
98
99 if (!cpp_compatible) {
100 components->push_back(packageVersion.substr(1));
101 return;
102 }
103
104 const size_t dotPos = packageVersion.find('.');
105
106 // Form "Vmajor_minor".
107 std::string versionString = "V";
108 versionString.append(packageVersion.substr(1, dotPos - 1));
109 versionString.append("_");
110 versionString.append(packageVersion.substr(dotPos + 1));
111
112 components->push_back(versionString);
113}
114
115std::string AST::makeHeaderGuard(const std::string &baseName) const {
116 std::vector<std::string> packageComponents;
117 getPackageAndVersionComponents(
118 &packageComponents, true /* cpp_compatible */);
119
120 std::string guard = "HIDL_GENERATED";
121 for (const auto &component : packageComponents) {
122 guard += "_";
123 guard += component;
124 }
125
126 guard += "_";
127 guard += baseName;
128 guard += "_H_";
129
130 return guard;
131}
132
133void AST::enterLeaveNamespace(Formatter &out, bool enter) const {
134 std::vector<std::string> packageComponents;
135 getPackageAndVersionComponents(
136 &packageComponents, true /* cpp_compatible */);
137
138 if (enter) {
139 for (const auto &component : packageComponents) {
140 out << "namespace " << component << " {\n";
141 }
142 } else {
143 for (auto it = packageComponents.rbegin();
144 it != packageComponents.rend();
145 ++it) {
146 out << "} // namespace " << *it << "\n";
147 }
148 }
149}
150
151status_t AST::generateInterfaceHeader() const {
152 const std::string packagePath =
153 mCoordinator->getPackagePath(mPackage, true /* relative */);
154
155 std::string path = "/tmp/android/hardware/";
156 path.append(packagePath);
157
158 std::string ifaceName;
159 bool isInterface = true;
160 if (!AST::isInterface(&ifaceName)) {
161 ifaceName = "types";
162 isInterface = false;
163 }
164 path.append(ifaceName);
165 path.append(".h");
166
167 CHECK(MakeParentHierarchy(path));
168 FILE *file = fopen(path.c_str(), "w");
169
170 if (file == NULL) {
171 return -errno;
172 }
173
174 Formatter out(file);
175
176 const std::string guard = makeHeaderGuard(ifaceName);
177
178 out << "#ifndef " << guard << "\n";
179 out << "#define " << guard << "\n\n";
180
181 out << "#include <hwbinder/HidlSupport.h>\n";
182
183 if (isInterface) {
184 out << "#include <hwbinder/IBinder.h>\n";
185 out << "#include <hwbinder/IInterface.h>\n";
186 out << "#include <hwbinder/Status.h>\n";
187 }
188
189 out << "#include <utils/NativeHandle.h>\n\n";
190
191 enterLeaveNamespace(out, true /* enter */);
192 out << "\n";
193
194 if (isInterface) {
195 out << "struct "
196 << ifaceName
197 << " : public ::android::hidl::IInterface {\n";
198
199 out.indent();
200
201 out << "DECLARE_HWBINDER_META_INTERFACE(" << ifaceName << ");\n\n";
202 }
203
204 status_t err = emitTypeDeclarations(out);
205
206 if (err != OK) {
207 return err;
208 }
209
210 if (isInterface) {
211 const Interface *iface = mRootScope->getInterface();
212
213 out << "enum Call {\n";
214 out.indent();
215
216 bool first = true;
217 for (const auto &method : iface->methods()) {
218 out << upcase(method->name());
219
220 if (first) {
221 out << " = ::android::hidl::IBinder::FIRST_CALL_TRANSACTION";
222 first = false;
223 }
224
225 out << ",\n";
226 }
227
228 out.unindent();
229 out << "};\n\n";
230
231 bool haveCallbacks = false;
232 for (const auto &method : iface->methods()) {
233 const bool returnsValue = !method->results().empty();
234
235 if (!returnsValue) {
236 continue;
237 }
238
239 haveCallbacks = true;
240
241 out << "using "
242 << method->name()
243 << "_cb = std::function<void("
244 << Method::GetSignature(method->results())
245 << ")>;\n";
246 }
247
248 if (haveCallbacks) {
249 out << "\n";
250 }
251
252 for (const auto &method : iface->methods()) {
253 const bool returnsValue = !method->results().empty();
254
255 out << "virtual ::android::hidl::binder::Status "
256 << method->name()
257 << "("
258 << Method::GetSignature(method->args());
259
260 if (returnsValue) {
261 if (!method->args().empty()) {
262 out << ", ";
263 }
264
265 out << method->name() << "_cb _aidl_cb = nullptr";
266 }
267
268 out << ") = 0;\n";
269 }
270 }
271
272 if (isInterface) {
273 out.unindent();
274
275 out << "};\n";
276 }
277
278 out << "\n";
279 enterLeaveNamespace(out, false /* enter */);
280
281 out << "\n#endif // " << guard << "\n";
282
283 return OK;
284}
285
286status_t AST::emitTypeDeclarations(Formatter &out) const {
287 return mRootScope->emitTypeDeclarations(out);
288}
289
290status_t AST::generateStubHeader() const {
291 std::string ifaceName;
292 if (!AST::isInterface(&ifaceName)) {
293 // types.hal does not get a stub header.
294 return OK;
295 }
296
297 const std::string packagePath =
298 mCoordinator->getPackagePath(mPackage, true /* relative */);
299
300 // cut off the leading 'I'.
301 const std::string baseName = ifaceName.substr(1);
302
303 std::string path = "/tmp/android/hardware/";
304 path.append(packagePath);
305 path.append("Bn");
306 path.append(baseName);
307 path.append(".h");
308
309 CHECK(MakeParentHierarchy(path));
310 FILE *file = fopen(path.c_str(), "w");
311
312 if (file == NULL) {
313 return -errno;
314 }
315
316 Formatter out(file);
317
318 const std::string guard = makeHeaderGuard("Bn" + baseName);
319
320 out << "#ifndef " << guard << "\n";
321 out << "#define " << guard << "\n\n";
322
323 std::vector<std::string> packageComponents;
324 getPackageAndVersionComponents(
325 &packageComponents, false /* cpp_compatible */);
326
327 out << "#include <";
328 for (const auto &component : packageComponents) {
329 out << component << "/";
330 }
331 out << ifaceName << ".h>\n\n";
332
333 enterLeaveNamespace(out, true /* enter */);
334 out << "\n";
335
336 out << "struct "
337 << "Bn"
338 << baseName
339 << " : public ::android::hidl::BnInterface<"
340 << ifaceName
341 << "> {\n";
342
343 out.indent();
344
345 out << "::android::status_t onTransact(\n";
346 out.indent();
347 out.indent();
348 out << "uint32_t _aidl_code,\n";
349 out << "const ::android::hidl::Parcel &_aidl_data,\n";
350 out << "::android::hidl::Parcel *_aidl_reply,\n";
351 out << "uint32_t _aidl_flags = 0,\n";
352 out << "TransactCallback _aidl_cb = nullptr) override;\n";
353 out.unindent();
354 out.unindent();
355
356 out.unindent();
357
358 out << "};\n\n";
359
360 enterLeaveNamespace(out, false /* enter */);
361
362 out << "\n#endif // " << guard << "\n";
363
364 return OK;
365}
366
367status_t AST::generateProxyHeader() const {
368 std::string ifaceName;
369 if (!AST::isInterface(&ifaceName)) {
370 // types.hal does not get a proxy header.
371 return OK;
372 }
373
374 const std::string packagePath =
375 mCoordinator->getPackagePath(mPackage, true /* relative */);
376
377 // cut off the leading 'I'.
378 const std::string baseName = ifaceName.substr(1);
379
380 std::string path = "/tmp/android/hardware/";
381 path.append(packagePath);
382 path.append("Bp");
383 path.append(baseName);
384 path.append(".h");
385
386 CHECK(MakeParentHierarchy(path));
387 FILE *file = fopen(path.c_str(), "w");
388
389 if (file == NULL) {
390 return -errno;
391 }
392
393 Formatter out(file);
394
395 const std::string guard = makeHeaderGuard("Bp" + baseName);
396
397 out << "#ifndef " << guard << "\n";
398 out << "#define " << guard << "\n\n";
399
400 std::vector<std::string> packageComponents;
401 getPackageAndVersionComponents(
402 &packageComponents, false /* cpp_compatible */);
403
404 out << "#include <";
405 for (const auto &component : packageComponents) {
406 out << component << "/";
407 }
408 out << ifaceName << ".h>\n\n";
409
410 enterLeaveNamespace(out, true /* enter */);
411 out << "\n";
412
413 out << "struct "
414 << "Bp"
415 << baseName
416 << " : public ::android::hidl::BpInterface<"
417 << ifaceName
418 << "> {\n";
419
420 out.indent();
421
422 out << "explicit Bp"
423 << baseName
424 << "(const ::android::sp<::android::hidl::IBinder> &_aidl_impl);"
425 << "\n\n";
426
427 const Interface *iface = mRootScope->getInterface();
428
429 for (const auto &method : iface->methods()) {
430 const bool returnsValue = !method->results().empty();
431
432 out << "::android::hidl::binder::Status "
433 << method->name()
434 << "("
435 << Method::GetSignature(method->args());
436
437 if (returnsValue) {
438 if (!method->args().empty()) {
439 out << ", ";
440 }
441
442 out << method->name() << "_cb _aidl_cb";
443 }
444
445 out << ") override;\n";
446 }
447
448 out.unindent();
449
450 out << "};\n\n";
451
452 enterLeaveNamespace(out, false /* enter */);
453
454 out << "\n#endif // " << guard << "\n";
455
456 return OK;
457}
458
459status_t AST::generateAllSource() const {
460 const std::string packagePath =
461 mCoordinator->getPackagePath(mPackage, true /* relative */);
462
463 std::string path = "/tmp/android/hardware/";
464 path.append(packagePath);
465
466 std::string ifaceName;
467 std::string baseName;
468
469 bool isInterface = true;
470 if (!AST::isInterface(&ifaceName)) {
471 baseName = "types";
472 isInterface = false;
473 } else {
474 baseName = ifaceName.substr(1); // cut off the leading 'I'.
475 }
476
477 path.append(baseName);
478
479 if (baseName != "types") {
480 path.append("All");
481 }
482
483 path.append(".cpp");
484
485 CHECK(MakeParentHierarchy(path));
486 FILE *file = fopen(path.c_str(), "w");
487
488 if (file == NULL) {
489 return -errno;
490 }
491
492 Formatter out(file);
493
494 std::vector<std::string> packageComponents;
495 getPackageAndVersionComponents(
496 &packageComponents, false /* cpp_compatible */);
497
498 std::string prefix;
499 for (const auto &component : packageComponents) {
500 prefix += component;
501 prefix += "/";
502 }
503
504 if (isInterface) {
505 out << "#include <" << prefix << "/Bp" << baseName << ".h>\n";
506 out << "#include <" << prefix << "/Bn" << baseName << ".h>\n";
507 } else {
508 out << "#include <" << prefix << "types.h>\n";
509 }
510
511 out << "\n";
512
513 enterLeaveNamespace(out, true /* enter */);
514 out << "\n";
515
516 status_t err = generateTypeSource(out, ifaceName);
517
518 if (err == OK && isInterface) {
519 err = generateProxySource(out, baseName);
520 }
521
522 if (err == OK && isInterface) {
523 err = generateStubSource(out, baseName);
524 }
525
526 enterLeaveNamespace(out, false /* enter */);
527
528 return err;
529}
530
531status_t AST::generateTypeSource(
532 Formatter &out, const std::string &ifaceName) const {
533 return mRootScope->emitTypeDefinitions(out, ifaceName);
534}
535
536void AST::emitCppReaderWriter(
537 Formatter &out,
538 const std::string &parcelObj,
539 bool parcelObjIsPointer,
540 const TypedVar *arg,
541 bool isReader,
542 Type::ErrorMode mode) const {
543 const Type &type = arg->type();
544
545 if (isReader) {
546 std::string extra;
547 out << type.getCppResultType(&extra)
548 << " "
549 << arg->name()
550 << extra
551 << ";\n";
552 }
553
554 type.emitReaderWriter(
555 out,
556 arg->name(),
557 parcelObj,
558 parcelObjIsPointer,
559 isReader,
560 mode);
561}
562
563status_t AST::generateProxySource(
564 Formatter &out, const std::string &baseName) const {
565 const std::string klassName = "Bp" + baseName;
566
567 out << klassName
568 << "::"
569 << klassName
570 << "(const ::android::sp<::android::hidl::IBinder> &_aidl_impl)\n";
571
572 out.indent();
573 out.indent();
574
575 out << ": BpInterface"
576 << "<I"
577 << baseName
578 << ">(_aidl_impl) {\n";
579
580 out.unindent();
581 out.unindent();
582 out << "}\n\n";
583
584 const Interface *iface = mRootScope->getInterface();
585
586 for (const auto &method : iface->methods()) {
587 const bool returnsValue = !method->results().empty();
588
589 out << "::android::hidl::binder::Status "
590 << klassName
591 << "::"
592 << method->name()
593 << "("
594 << Method::GetSignature(method->args());
595
596 if (returnsValue) {
597 if (!method->args().empty()) {
598 out << ", ";
599 }
600
601 out << method->name() << "_cb _aidl_cb";
602 }
603
604 out << ") {\n";
605
606 out.indent();
607
608 out << "::android::hidl::Parcel _aidl_data;\n";
609 out << "::android::hidl::Parcel _aidl_reply;\n";
610 out << "::android::status_t _aidl_err;\n\n";
611 out << "::android::hidl::binder::Status _aidl_status;\n";
612
613 out << "_aidl_err = _aidl_data.writeInterfaceToken("
614 "getInterfaceDescriptor());\n";
615
616 out << "if (_aidl_err != ::android::OK) { goto _aidl_error; }\n\n";
617
618 for (const auto &arg : method->args()) {
619 emitCppReaderWriter(
620 out,
621 "_aidl_data",
622 false /* parcelObjIsPointer */,
623 arg,
624 false /* reader */,
625 Type::ErrorMode_Goto);
626 }
627
628 out << "_aidl_err = remote()->transact(I"
629 << baseName
630 << "::"
631 << upcase(method->name())
632 << ", _aidl_data, &_aidl_reply);\n";
633
634 out << "if (_aidl_err != ::android::OK) { goto _aidl_error; }\n\n";
635
636 out << "_aidl_err = _aidl_status.readFromParcel(_aidl_reply);\n";
637 out << "if (_aidl_err != ::android::OK) { goto _aidl_error; }\n\n";
638
639 out << "if (!_aidl_status.isOk()) { return _aidl_status; }\n\n";
640
641 for (const auto &arg : method->results()) {
642 emitCppReaderWriter(
643 out,
644 "_aidl_reply",
645 false /* parcelObjIsPointer */,
646 arg,
647 true /* reader */,
648 Type::ErrorMode_Goto);
649 }
650
651 if (returnsValue) {
652 out << "if (_aidl_cb != nullptr) {\n";
653 out.indent();
654 out << "_aidl_cb(";
655
656 bool first = true;
657 for (const auto &arg : method->results()) {
658 if (!first) {
659 out << ", ";
660 }
661
662 if (arg->type().resultNeedsDeref()) {
663 out << "*";
664 }
665 out << arg->name();
666
667 first = false;
668 }
669
670 out << ");\n";
671 out.unindent();
672 out << "}\n\n";
673 }
674
675 out.unindent();
676 out << "_aidl_error:\n";
677 out.indent();
678 out << "_aidl_status.setFromStatusT(_aidl_err);\n"
679 << "return _aidl_status;\n";
680
681 out.unindent();
682 out << "}\n\n";
683 }
684
685 return OK;
686}
687
688status_t AST::generateStubSource(
689 Formatter &out, const std::string &baseName) const {
690 out << "IMPLEMENT_HWBINDER_META_INTERFACE("
691 << baseName
692 << ", \""
693 << mPackage.string()
694 << "::I"
695 << baseName
696 << "\");\n\n";
697
698 const std::string klassName = "Bn" + baseName;
699
700 out << "::android::status_t " << klassName << "::onTransact(\n";
701
702 out.indent();
703 out.indent();
704
705 out << "uint32_t _aidl_code,\n"
706 << "const ::android::hidl::Parcel &_aidl_data,\n"
707 << "::android::hidl::Parcel *_aidl_reply,\n"
708 << "uint32_t _aidl_flags,\n"
709 << "TransactCallback _aidl_cb) {\n";
710
711 out.unindent();
712
713 out << "::android::status_t _aidl_err = ::android::OK;\n\n";
714
715 out << "switch (_aidl_code) {\n";
716 out.indent();
717
718 const Interface *iface = mRootScope->getInterface();
719
720 for (const auto &method : iface->methods()) {
721 out << "case Call::" << upcase(method->name()) << ":\n{\n";
722 out.indent();
723
724 status_t err = generateStubSourceForMethod(out, method);
725
726 if (err != OK) {
727 return err;
728 }
729
730 out.unindent();
731 out << "}\n\n";
732 }
733
734 out << "default:\n{\n";
735 out.indent();
736
737 out << "return ::android::hidl::BnInterface<I"
738 << baseName
739 << ">::onTransact(\n";
740
741 out.indent();
742 out.indent();
743
744 out << "_aidl_code, _aidl_data, _aidl_reply, "
745 << "_aidl_flags, _aidl_cb);\n";
746
747 out.unindent();
748 out.unindent();
749
750 out.unindent();
751 out << "}\n";
752
753 out.unindent();
754 out << "}\n\n";
755
756 out << "if (_aidl_err == ::android::UNEXPECTED_NULL) {\n";
757 out.indent();
758 out << "_aidl_err = ::android::hidl::binder::Status::fromExceptionCode(\n";
759 out.indent();
760 out.indent();
761 out << "::android::hidl::binder::Status::EX_NULL_POINTER)\n";
762 out.indent();
763 out.indent();
764 out << ".writeToParcel(_aidl_reply);\n";
765 out.unindent();
766 out.unindent();
767 out.unindent();
768 out.unindent();
769
770 out.unindent();
771 out << "}\n\n";
772
773 out << "return _aidl_err;\n";
774
775 out.unindent();
776 out << "}\n\n";
777
778 return OK;
779}
780
781status_t AST::generateStubSourceForMethod(
782 Formatter &out, const Method *method) const {
783 out << "if (!_aidl_data.checkInterface(this)) {\n";
784 out.indent();
785 out << "_aidl_err = ::android::BAD_TYPE;\n";
786 out << "break;\n";
787 out.unindent();
788 out << "}\n\n";
789
790 for (const auto &arg : method->args()) {
791 emitCppReaderWriter(
792 out,
793 "_aidl_data",
794 false /* parcelObjIsPointer */,
795 arg,
796 true /* reader */,
797 Type::ErrorMode_Break);
798 }
799
800 const bool returnsValue = !method->results().empty();
801
802 if (returnsValue) {
803 out << "bool _aidl_callbackCalled = false;\n\n";
804 }
805
806 out << "::android::hidl::binder::Status _aidl_status(\n";
807 out.indent();
808 out.indent();
809 out << method->name() << "(";
810
811 bool first = true;
812 for (const auto &arg : method->args()) {
813 if (!first) {
814 out << ", ";
815 }
816
817 if (arg->type().resultNeedsDeref()) {
818 out << "*";
819 }
820
821 out << arg->name();
822
823 first = false;
824 }
825
826 if (returnsValue) {
827 if (!first) {
828 out << ", ";
829 }
830
831 out << "[&](";
832
833 first = true;
834 for (const auto &arg : method->results()) {
835 if (!first) {
836 out << ", ";
837 }
838
839 out << "const auto &" << arg->name();
840
841 first = false;
842 }
843
844 out << ") {\n";
845 out.indent();
846 out << "_aidl_callbackCalled = true;\n\n";
847
848 out << "::android::hidl::binder::Status::ok()"
849 << ".writeToParcel(_aidl_reply);\n\n";
850
851 for (const auto &arg : method->results()) {
852 emitCppReaderWriter(
853 out,
854 "_aidl_reply",
855 true /* parcelObjIsPointer */,
856 arg,
857 false /* reader */,
858 Type::ErrorMode_Ignore);
859 }
860
861 out << "_aidl_cb(*_aidl_reply);\n";
862
863 out.unindent();
864 out << "}\n";
865 }
866
867 out.unindent();
868 out.unindent();
869 out << "));\n\n";
870
871 if (returnsValue) {
872 out << "if (!_aidl_callbackCalled) {\n";
873 out.indent();
874 }
875
876 out << "_aidl_err = _aidl_status.writeToParcel(_aidl_reply);\n";
877
878 if (returnsValue) {
879 out.unindent();
880 out << "}\n\n";
881 }
882
883 out << "break;\n";
884
885 return OK;
886}
887
888} // namespace android
889