1 /* 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 17 #include "CompoundType.h" 18 19 #include "ArrayType.h" 20 #include "VectorType.h" 21 #include <hidl-util/Formatter.h> 22 #include <android-base/logging.h> 23 24 namespace android { 25 26 CompoundType::CompoundType(Style style, const char* localName, const Location& location, 27 Scope* parent) 28 : Scope(localName, location, parent), mStyle(style), mFields(NULL) {} 29 30 CompoundType::Style CompoundType::style() const { 31 return mStyle; 32 } 33 34 bool CompoundType::setFields( 35 std::vector<CompoundField *> *fields, std::string *errorMsg) { 36 mFields = fields; 37 38 for (const auto &field : *fields) { 39 const Type &type = field->type(); 40 41 if (type.isBinder() 42 || (type.isVector() 43 && static_cast<const VectorType *>( 44 &type)->isVectorOfBinders())) { 45 *errorMsg = 46 "Structs/Unions must not contain references to interfaces."; 47 48 return false; 49 } 50 51 if (mStyle == STYLE_UNION) { 52 if (type.needsEmbeddedReadWrite()) { 53 // Can't have those in a union. 54 55 *errorMsg = 56 "Unions must not contain any types that need fixup."; 57 58 return false; 59 } 60 } 61 } 62 63 return true; 64 } 65 66 bool CompoundType::isCompoundType() const { 67 return true; 68 } 69 70 bool CompoundType::canCheckEquality() const { 71 if (mStyle == STYLE_UNION) { 72 return false; 73 } 74 for (const auto &field : *mFields) { 75 if (!field->type().canCheckEquality()) { 76 return false; 77 } 78 } 79 return true; 80 } 81 82 std::string CompoundType::typeName() const { 83 switch (mStyle) { 84 case STYLE_STRUCT: { 85 return "struct " + localName(); 86 } 87 case STYLE_UNION: { 88 return "union " + localName(); 89 } 90 } 91 CHECK(!"Should not be here"); 92 } 93 94 std::string CompoundType::getCppType( 95 StorageMode mode, 96 bool /* specifyNamespaces */) const { 97 const std::string base = fullName(); 98 99 switch (mode) { 100 case StorageMode_Stack: 101 return base; 102 103 case StorageMode_Argument: 104 return "const " + base + "&"; 105 106 case StorageMode_Result: 107 return "const " + base + "*"; 108 } 109 } 110 111 std::string CompoundType::getJavaType(bool /* forInitializer */) const { 112 return fullJavaName(); 113 } 114 115 std::string CompoundType::getVtsType() const { 116 switch (mStyle) { 117 case STYLE_STRUCT: 118 { 119 return "TYPE_STRUCT"; 120 } 121 case STYLE_UNION: 122 { 123 return "TYPE_UNION"; 124 } 125 } 126 CHECK(!"Should not be here"); 127 } 128 129 void CompoundType::emitReaderWriter( 130 Formatter &out, 131 const std::string &name, 132 const std::string &parcelObj, 133 bool parcelObjIsPointer, 134 bool isReader, 135 ErrorMode mode) const { 136 const std::string parentName = "_hidl_" + name + "_parent"; 137 138 out << "size_t " << parentName << ";\n\n"; 139 140 const std::string parcelObjDeref = 141 parcelObj + (parcelObjIsPointer ? "->" : "."); 142 143 if (isReader) { 144 out << "_hidl_err = " 145 << parcelObjDeref 146 << "readBuffer(" 147 << "sizeof(*" 148 << name 149 << "), &" 150 << parentName 151 << ", " 152 << " reinterpret_cast<const void **>(" 153 << "&" << name 154 << "));\n"; 155 156 handleError(out, mode); 157 } else { 158 out << "_hidl_err = " 159 << parcelObjDeref 160 << "writeBuffer(&" 161 << name 162 << ", sizeof(" 163 << name 164 << "), &" 165 << parentName 166 << ");\n"; 167 168 handleError(out, mode); 169 } 170 171 if (mStyle != STYLE_STRUCT || !needsEmbeddedReadWrite()) { 172 return; 173 } 174 175 emitReaderWriterEmbedded( 176 out, 177 0 /* depth */, 178 name, 179 name, /* sanitizedName */ 180 isReader /* nameIsPointer */, 181 parcelObj, 182 parcelObjIsPointer, 183 isReader, 184 mode, 185 parentName, 186 "0 /* parentOffset */"); 187 } 188 189 void CompoundType::emitReaderWriterEmbedded( 190 Formatter &out, 191 size_t /* depth */, 192 const std::string &name, 193 const std::string & /*sanitizedName */, 194 bool nameIsPointer, 195 const std::string &parcelObj, 196 bool parcelObjIsPointer, 197 bool isReader, 198 ErrorMode mode, 199 const std::string &parentName, 200 const std::string &offsetText) const { 201 emitReaderWriterEmbeddedForTypeName( 202 out, 203 name, 204 nameIsPointer, 205 parcelObj, 206 parcelObjIsPointer, 207 isReader, 208 mode, 209 parentName, 210 offsetText, 211 fullName(), 212 "" /* childName */, 213 "" /* namespace */); 214 } 215 216 void CompoundType::emitJavaReaderWriter( 217 Formatter &out, 218 const std::string &parcelObj, 219 const std::string &argName, 220 bool isReader) const { 221 if (isReader) { 222 out << "new " << fullJavaName() << "();\n"; 223 } 224 225 out << argName 226 << "." 227 << (isReader ? "readFromParcel" : "writeToParcel") 228 << "(" 229 << parcelObj 230 << ");\n"; 231 } 232 233 void CompoundType::emitJavaFieldInitializer( 234 Formatter &out, const std::string &fieldName) const { 235 out << "final " 236 << fullJavaName() 237 << " " 238 << fieldName 239 << " = new " 240 << fullJavaName() 241 << "();\n"; 242 } 243 244 void CompoundType::emitJavaFieldReaderWriter( 245 Formatter &out, 246 size_t /* depth */, 247 const std::string &parcelName, 248 const std::string &blobName, 249 const std::string &fieldName, 250 const std::string &offset, 251 bool isReader) const { 252 if (isReader) { 253 out << fieldName 254 << ".readEmbeddedFromParcel(" 255 << parcelName 256 << ", " 257 << blobName 258 << ", " 259 << offset 260 << ");\n"; 261 262 return; 263 } 264 265 out << fieldName 266 << ".writeEmbeddedToBlob(" 267 << blobName 268 << ", " 269 << offset 270 << ");\n"; 271 } 272 void CompoundType::emitResolveReferences( 273 Formatter &out, 274 const std::string &name, 275 bool nameIsPointer, 276 const std::string &parcelObj, 277 bool parcelObjIsPointer, 278 bool isReader, 279 ErrorMode mode) const { 280 emitResolveReferencesEmbedded( 281 out, 282 0 /* depth */, 283 name, 284 name /* sanitizedName */, 285 nameIsPointer, 286 parcelObj, 287 parcelObjIsPointer, 288 isReader, 289 mode, 290 "_hidl_" + name + "_parent", 291 "0 /* parentOffset */"); 292 } 293 294 void CompoundType::emitResolveReferencesEmbedded( 295 Formatter &out, 296 size_t /* depth */, 297 const std::string &name, 298 const std::string &/* sanitizedName */, 299 bool nameIsPointer, 300 const std::string &parcelObj, 301 bool parcelObjIsPointer, 302 bool isReader, 303 ErrorMode mode, 304 const std::string &parentName, 305 const std::string &offsetText) const { 306 CHECK(needsResolveReferences()); 307 308 const std::string parcelObjDeref = 309 parcelObjIsPointer ? ("*" + parcelObj) : parcelObj; 310 311 const std::string parcelObjPointer = 312 parcelObjIsPointer ? parcelObj : ("&" + parcelObj); 313 314 const std::string nameDerefed = nameIsPointer ? ("*" + name) : name; 315 const std::string namePointer = nameIsPointer ? name : ("&" + name); 316 317 out << "_hidl_err = "; 318 319 if (isReader) { 320 out << "readEmbeddedReferenceFromParcel(\n"; 321 } else { 322 out << "writeEmbeddedReferenceToParcel(\n"; 323 } 324 325 out.indent(2, [&]{ 326 if (isReader) { 327 out << "const_cast<" 328 << fullName() 329 << " *" 330 << ">(" 331 << namePointer 332 << "),\n" 333 << parcelObjDeref; 334 } else { 335 out << nameDerefed 336 << ",\n" 337 << parcelObjPointer; 338 } 339 340 out << ",\n" 341 << parentName 342 << ",\n" 343 << offsetText 344 << ");\n\n"; 345 }); 346 347 handleError(out, mode); 348 } 349 350 status_t CompoundType::emitTypeDeclarations(Formatter &out) const { 351 out << ((mStyle == STYLE_STRUCT) ? "struct" : "union") 352 << " " 353 << localName() 354 << " final {\n"; 355 356 out.indent(); 357 358 Scope::emitTypeDeclarations(out); 359 360 if (containsPointer()) { 361 for (const auto &field : *mFields) { 362 out << field->type().getCppStackType() 363 << " " 364 << field->name() 365 << ";\n"; 366 } 367 368 out.unindent(); 369 out << "};\n\n"; 370 371 return OK; 372 } 373 374 for (int pass = 0; pass < 2; ++pass) { 375 size_t offset = 0; 376 for (const auto &field : *mFields) { 377 size_t fieldAlign, fieldSize; 378 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize); 379 380 size_t pad = offset % fieldAlign; 381 if (pad > 0) { 382 offset += fieldAlign - pad; 383 } 384 385 if (pass == 0) { 386 out << field->type().getCppStackType() 387 << " " 388 << field->name() 389 << " __attribute__ ((aligned(" 390 << fieldAlign 391 << ")));\n"; 392 } else { 393 out << "static_assert(offsetof(" 394 << fullName() 395 << ", " 396 << field->name() 397 << ") == " 398 << offset 399 << ", \"wrong offset\");\n"; 400 } 401 402 if (mStyle == STYLE_STRUCT) { 403 offset += fieldSize; 404 } 405 } 406 407 if (pass == 0) { 408 out.unindent(); 409 out << "};\n\n"; 410 } 411 } 412 413 size_t structAlign, structSize; 414 getAlignmentAndSize(&structAlign, &structSize); 415 416 out << "static_assert(sizeof(" 417 << fullName() 418 << ") == " 419 << structSize 420 << ", \"wrong size\");\n"; 421 422 out << "static_assert(__alignof(" 423 << fullName() 424 << ") == " 425 << structAlign 426 << ", \"wrong alignment\");\n\n"; 427 428 return OK; 429 } 430 431 432 status_t CompoundType::emitGlobalTypeDeclarations(Formatter &out) const { 433 Scope::emitGlobalTypeDeclarations(out); 434 435 out << "std::string toString(" 436 << getCppArgumentType() 437 << ");\n\n"; 438 439 if (canCheckEquality()) { 440 out << "bool operator==(" 441 << getCppArgumentType() << ", " << getCppArgumentType() << ");\n\n"; 442 443 out << "bool operator!=(" 444 << getCppArgumentType() << ", " << getCppArgumentType() << ");\n\n"; 445 } else { 446 out << "// operator== and operator!= are not generated for " << localName() << "\n\n"; 447 } 448 449 return OK; 450 } 451 452 status_t CompoundType::emitGlobalHwDeclarations(Formatter &out) const { 453 if (needsEmbeddedReadWrite()) { 454 out << "::android::status_t readEmbeddedFromParcel(\n"; 455 456 out.indent(2); 457 458 out << "const " << fullName() << " &obj,\n" 459 << "const ::android::hardware::Parcel &parcel,\n" 460 << "size_t parentHandle,\n" 461 << "size_t parentOffset);\n\n"; 462 463 out.unindent(2); 464 465 out << "::android::status_t writeEmbeddedToParcel(\n"; 466 467 out.indent(2); 468 469 out << "const " << fullName() << " &obj,\n" 470 << "::android::hardware::Parcel *parcel,\n" 471 << "size_t parentHandle,\n" 472 << "size_t parentOffset);\n\n"; 473 474 out.unindent(2); 475 } 476 477 if(needsResolveReferences()) { 478 out << "::android::status_t readEmbeddedReferenceFromParcel(\n"; 479 out.indent(2); 480 out << fullName() << " *obj,\n" 481 << "const ::android::hardware::Parcel &parcel,\n" 482 << "size_t parentHandle, size_t parentOffset);\n\n"; 483 out.unindent(2); 484 out << "::android::status_t writeEmbeddedReferenceToParcel(\n"; 485 out.indent(2); 486 out << "const " << fullName() << " &obj,\n" 487 << "::android::hardware::Parcel *,\n" 488 << "size_t parentHandle, size_t parentOffset);\n\n"; 489 out.unindent(2); 490 } 491 492 return OK; 493 } 494 495 status_t CompoundType::emitTypeDefinitions( 496 Formatter &out, const std::string prefix) const { 497 std::string space = prefix.empty() ? "" : (prefix + "::"); 498 status_t err = Scope::emitTypeDefinitions(out, space + localName()); 499 500 if (err != OK) { 501 return err; 502 } 503 504 if (needsEmbeddedReadWrite()) { 505 emitStructReaderWriter(out, prefix, true /* isReader */); 506 emitStructReaderWriter(out, prefix, false /* isReader */); 507 } 508 509 if (needsResolveReferences()) { 510 emitResolveReferenceDef(out, prefix, true /* isReader */); 511 emitResolveReferenceDef(out, prefix, false /* isReader */); 512 } 513 514 out << "std::string toString(" 515 << getCppArgumentType() 516 << (mFields->empty() ? "" : " o") 517 << ") "; 518 519 out.block([&] { 520 // include toString for scalar types 521 out << "using ::android::hardware::toString;\n" 522 << "std::string os;\n"; 523 out << "os += \"{\";\n"; 524 525 for (const CompoundField *field : *mFields) { 526 out << "os += \""; 527 if (field != *(mFields->begin())) { 528 out << ", "; 529 } 530 out << "." << field->name() << " = \";\n"; 531 field->type().emitDump(out, "os", "o." + field->name()); 532 } 533 534 out << "os += \"}\"; return os;\n"; 535 }).endl().endl(); 536 537 if (canCheckEquality()) { 538 out << "bool operator==(" 539 << getCppArgumentType() << " " << (mFields->empty() ? "/* lhs */" : "lhs") << ", " 540 << getCppArgumentType() << " " << (mFields->empty() ? "/* rhs */" : "rhs") << ") "; 541 out.block([&] { 542 for (const auto &field : *mFields) { 543 out.sIf("lhs." + field->name() + " != rhs." + field->name(), [&] { 544 out << "return false;\n"; 545 }).endl(); 546 } 547 out << "return true;\n"; 548 }).endl().endl(); 549 550 out << "bool operator!=(" 551 << getCppArgumentType() << " lhs," << getCppArgumentType() << " rhs)"; 552 out.block([&] { 553 out << "return !(lhs == rhs);\n"; 554 }).endl().endl(); 555 } else { 556 out << "// operator== and operator!= are not generated for " << localName() << "\n"; 557 } 558 559 return OK; 560 } 561 562 status_t CompoundType::emitJavaTypeDeclarations( 563 Formatter &out, bool atTopLevel) const { 564 out << "public final "; 565 566 if (!atTopLevel) { 567 out << "static "; 568 } 569 570 out << "class " 571 << localName() 572 << " {\n"; 573 574 out.indent(); 575 576 Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */); 577 578 for (const auto &field : *mFields) { 579 out << "public "; 580 581 field->type().emitJavaFieldInitializer(out, field->name()); 582 } 583 584 if (!mFields->empty()) { 585 out << "\n"; 586 } 587 588 //////////////////////////////////////////////////////////////////////////// 589 590 if (canCheckEquality()) { 591 out << "@Override\npublic final boolean equals(Object otherObject) "; 592 out.block([&] { 593 out.sIf("this == otherObject", [&] { 594 out << "return true;\n"; 595 }).endl(); 596 out.sIf("otherObject == null", [&] { 597 out << "return false;\n"; 598 }).endl(); 599 // Though class is final, we use getClass instead of instanceof to be explicit. 600 out.sIf("otherObject.getClass() != " + fullJavaName() + ".class", [&] { 601 out << "return false;\n"; 602 }).endl(); 603 out << fullJavaName() << " other = (" << fullJavaName() << ")otherObject;\n"; 604 for (const auto &field : *mFields) { 605 std::string condition = (field->type().isScalar() || field->type().isEnum()) 606 ? "this." + field->name() + " != other." + field->name() 607 : ("!android.os.HidlSupport.deepEquals(this." + field->name() 608 + ", other." + field->name() + ")"); 609 out.sIf(condition, [&] { 610 out << "return false;\n"; 611 }).endl(); 612 } 613 out << "return true;\n"; 614 }).endl().endl(); 615 616 out << "@Override\npublic final int hashCode() "; 617 out.block([&] { 618 out << "return java.util.Objects.hash(\n"; 619 out.indent(2, [&] { 620 out.join(mFields->begin(), mFields->end(), ", \n", [&] (const auto &field) { 621 out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")"; 622 }); 623 }); 624 out << ");\n"; 625 }).endl().endl(); 626 } else { 627 out << "// equals() is not generated for " << localName() << "\n"; 628 } 629 630 //////////////////////////////////////////////////////////////////////////// 631 632 out << "@Override\npublic final String toString() "; 633 out.block([&] { 634 out << "java.lang.StringBuilder builder = new java.lang.StringBuilder();\n" 635 << "builder.append(\"{\");\n"; 636 for (const auto &field : *mFields) { 637 out << "builder.append(\""; 638 if (field != *(mFields->begin())) { 639 out << ", "; 640 } 641 out << "." << field->name() << " = \");\n"; 642 field->type().emitJavaDump(out, "builder", "this." + field->name()); 643 } 644 out << "builder.append(\"}\");\nreturn builder.toString();\n"; 645 }).endl().endl(); 646 647 size_t structAlign, structSize; 648 getAlignmentAndSize(&structAlign, &structSize); 649 650 //////////////////////////////////////////////////////////////////////////// 651 652 out << "public final void readFromParcel(android.os.HwParcel parcel) {\n"; 653 out.indent(); 654 out << "android.os.HwBlob blob = parcel.readBuffer("; 655 out << structSize << "/* size */);\n"; 656 out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n"; 657 out.unindent(); 658 out << "}\n\n"; 659 660 //////////////////////////////////////////////////////////////////////////// 661 662 size_t vecAlign, vecSize; 663 VectorType::getAlignmentAndSizeStatic(&vecAlign, &vecSize); 664 665 out << "public static final java.util.ArrayList<" 666 << localName() 667 << "> readVectorFromParcel(android.os.HwParcel parcel) {\n"; 668 out.indent(); 669 670 out << "java.util.ArrayList<" 671 << localName() 672 << "> _hidl_vec = new java.util.ArrayList();\n"; 673 674 out << "android.os.HwBlob _hidl_blob = parcel.readBuffer("; 675 out << vecSize << " /* sizeof hidl_vec<T> */);\n\n"; 676 677 VectorType::EmitJavaFieldReaderWriterForElementType( 678 out, 679 0 /* depth */, 680 this, 681 "parcel", 682 "_hidl_blob", 683 "_hidl_vec", 684 "0", 685 true /* isReader */); 686 687 out << "\nreturn _hidl_vec;\n"; 688 689 out.unindent(); 690 out << "}\n\n"; 691 692 //////////////////////////////////////////////////////////////////////////// 693 694 out << "public final void readEmbeddedFromParcel(\n"; 695 out.indent(2); 696 out << "android.os.HwParcel parcel, android.os.HwBlob _hidl_blob, long _hidl_offset) {\n"; 697 out.unindent(); 698 699 size_t offset = 0; 700 for (const auto &field : *mFields) { 701 size_t fieldAlign, fieldSize; 702 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize); 703 704 size_t pad = offset % fieldAlign; 705 if (pad > 0) { 706 offset += fieldAlign - pad; 707 } 708 709 field->type().emitJavaFieldReaderWriter( 710 out, 711 0 /* depth */, 712 "parcel", 713 "_hidl_blob", 714 field->name(), 715 "_hidl_offset + " + std::to_string(offset), 716 true /* isReader */); 717 718 offset += fieldSize; 719 } 720 721 out.unindent(); 722 out << "}\n\n"; 723 724 //////////////////////////////////////////////////////////////////////////// 725 726 out << "public final void writeToParcel(android.os.HwParcel parcel) {\n"; 727 out.indent(); 728 729 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" 730 << structSize 731 << " /* size */);\n"; 732 733 out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n" 734 << "parcel.writeBuffer(_hidl_blob);\n"; 735 736 out.unindent(); 737 out << "}\n\n"; 738 739 //////////////////////////////////////////////////////////////////////////// 740 741 out << "public static final void writeVectorToParcel(\n"; 742 out.indent(2); 743 out << "android.os.HwParcel parcel, java.util.ArrayList<" 744 << localName() 745 << "> _hidl_vec) {\n"; 746 out.unindent(); 747 748 out << "android.os.HwBlob _hidl_blob = new android.os.HwBlob(" 749 << vecSize << " /* sizeof(hidl_vec<T>) */);\n"; 750 751 VectorType::EmitJavaFieldReaderWriterForElementType( 752 out, 753 0 /* depth */, 754 this, 755 "parcel", 756 "_hidl_blob", 757 "_hidl_vec", 758 "0", 759 false /* isReader */); 760 761 out << "\nparcel.writeBuffer(_hidl_blob);\n"; 762 763 out.unindent(); 764 out << "}\n\n"; 765 766 //////////////////////////////////////////////////////////////////////////// 767 768 out << "public final void writeEmbeddedToBlob(\n"; 769 out.indent(2); 770 out << "android.os.HwBlob _hidl_blob, long _hidl_offset) {\n"; 771 out.unindent(); 772 773 offset = 0; 774 for (const auto &field : *mFields) { 775 size_t fieldAlign, fieldSize; 776 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize); 777 778 size_t pad = offset % fieldAlign; 779 if (pad > 0) { 780 offset += fieldAlign - pad; 781 } 782 783 field->type().emitJavaFieldReaderWriter( 784 out, 785 0 /* depth */, 786 "parcel", 787 "_hidl_blob", 788 field->name(), 789 "_hidl_offset + " + std::to_string(offset), 790 false /* isReader */); 791 792 offset += fieldSize; 793 } 794 795 out.unindent(); 796 out << "}\n"; 797 798 out.unindent(); 799 out << "};\n\n"; 800 801 return OK; 802 } 803 804 void CompoundType::emitStructReaderWriter( 805 Formatter &out, const std::string &prefix, bool isReader) const { 806 807 std::string space = prefix.empty() ? "" : (prefix + "::"); 808 809 out << "::android::status_t " 810 << (isReader ? "readEmbeddedFromParcel" 811 : "writeEmbeddedToParcel") 812 << "(\n"; 813 814 out.indent(2); 815 816 bool useName = false; 817 for (const auto &field : *mFields) { 818 if (field->type().useNameInEmitReaderWriterEmbedded(isReader)) { 819 useName = true; 820 break; 821 } 822 } 823 std::string name = useName ? "obj" : "/* obj */"; 824 // if not useName, then obj should not be used at all, 825 // then the #error should not be emitted. 826 std::string error = useName ? "" : "\n#error\n"; 827 828 if (isReader) { 829 out << "const " << space << localName() << " &" << name << ",\n"; 830 out << "const ::android::hardware::Parcel &parcel,\n"; 831 } else { 832 out << "const " << space << localName() << " &" << name << ",\n"; 833 out << "::android::hardware::Parcel *parcel,\n"; 834 } 835 836 out << "size_t parentHandle,\n" 837 << "size_t parentOffset)"; 838 839 out << " {\n"; 840 841 out.unindent(2); 842 out.indent(); 843 844 out << "::android::status_t _hidl_err = ::android::OK;\n\n"; 845 846 for (const auto &field : *mFields) { 847 if (!field->type().needsEmbeddedReadWrite()) { 848 continue; 849 } 850 851 field->type().emitReaderWriterEmbedded( 852 out, 853 0 /* depth */, 854 name + "." + field->name() + error, 855 field->name() /* sanitizedName */, 856 false /* nameIsPointer */, 857 "parcel", 858 !isReader /* parcelObjIsPointer */, 859 isReader, 860 ErrorMode_Return, 861 "parentHandle", 862 "parentOffset + offsetof(" 863 + fullName() 864 + ", " 865 + field->name() 866 + ")"); 867 } 868 869 out << "return _hidl_err;\n"; 870 871 out.unindent(); 872 out << "}\n\n"; 873 } 874 875 void CompoundType::emitResolveReferenceDef( 876 Formatter &out, const std::string prefix, bool isReader) const { 877 out << "::android::status_t "; 878 const std::string space(prefix.empty() ? "" : (prefix + "::")); 879 880 bool useParent = false; 881 for (const auto &field : *mFields) { 882 if (field->type().useParentInEmitResolveReferencesEmbedded()) { 883 useParent = true; 884 break; 885 } 886 } 887 888 std::string parentHandleName = useParent ? "parentHandle" : "/* parentHandle */"; 889 std::string parentOffsetName = useParent ? "parentOffset" : "/* parentOffset */"; 890 891 if (isReader) { 892 out << "readEmbeddedReferenceFromParcel(\n"; 893 out.indent(2); 894 out << space + localName() + " *obj,\n" 895 << "const ::android::hardware::Parcel &parcel,\n" 896 << "size_t " << parentHandleName << ", " 897 << "size_t " << parentOffsetName << ")\n"; 898 out.unindent(2); 899 } else { 900 out << "writeEmbeddedReferenceToParcel(\n"; 901 out.indent(2); 902 out << "const " << space + localName() + " &obj,\n" 903 << "::android::hardware::Parcel *parcel,\n" 904 << "size_t " << parentHandleName << ", " 905 << "size_t " << parentOffsetName << ")\n"; 906 out.unindent(2); 907 } 908 909 out << " {\n"; 910 911 out.indent(); 912 913 out << "::android::status_t _hidl_err = ::android::OK;\n\n"; 914 915 const std::string nameDeref(isReader ? "obj->" : "obj."); 916 // if not useParent, then parentName and offsetText 917 // should not be used at all, then the #error should not be emitted. 918 std::string error = useParent ? "" : "\n#error\n"; 919 920 for (const auto &field : *mFields) { 921 if (!field->type().needsResolveReferences()) { 922 continue; 923 } 924 925 field->type().emitResolveReferencesEmbedded( 926 out, 927 0 /* depth */, 928 nameDeref + field->name(), 929 field->name() /* sanitizedName */, 930 false, // nameIsPointer 931 "parcel", // const std::string &parcelObj, 932 !isReader, // bool parcelObjIsPointer, 933 isReader, // bool isReader, 934 ErrorMode_Return, 935 parentHandleName + error, 936 parentOffsetName 937 + " + offsetof(" 938 + fullName() 939 + ", " 940 + field->name() 941 + ")" 942 + error); 943 } 944 945 out << "return _hidl_err;\n"; 946 947 out.unindent(); 948 out << "}\n\n"; 949 } 950 951 bool CompoundType::needsEmbeddedReadWrite() const { 952 if (mStyle != STYLE_STRUCT) { 953 return false; 954 } 955 956 for (const auto &field : *mFields) { 957 if (field->type().needsEmbeddedReadWrite()) { 958 return true; 959 } 960 } 961 962 return false; 963 } 964 965 bool CompoundType::needsResolveReferences() const { 966 if (mStyle != STYLE_STRUCT) { 967 return false; 968 } 969 970 for (const auto &field : *mFields) { 971 if (field->type().needsResolveReferences()) { 972 return true; 973 } 974 } 975 976 return false; 977 } 978 979 bool CompoundType::resultNeedsDeref() const { 980 return true; 981 } 982 983 status_t CompoundType::emitVtsTypeDeclarations(Formatter &out) const { 984 out << "name: \"" << fullName() << "\"\n"; 985 out << "type: " << getVtsType() << "\n"; 986 987 // Emit declaration for each subtype. 988 for (const auto &type : getSubTypes()) { 989 switch (mStyle) { 990 case STYLE_STRUCT: 991 { 992 out << "sub_struct: {\n"; 993 break; 994 } 995 case STYLE_UNION: 996 { 997 out << "sub_union: {\n"; 998 break; 999 } 1000 } 1001 out.indent(); 1002 status_t status(type->emitVtsTypeDeclarations(out)); 1003 if (status != OK) { 1004 return status; 1005 } 1006 out.unindent(); 1007 out << "}\n"; 1008 } 1009 1010 // Emit declaration for each field. 1011 for (const auto &field : *mFields) { 1012 switch (mStyle) { 1013 case STYLE_STRUCT: 1014 { 1015 out << "struct_value: {\n"; 1016 break; 1017 } 1018 case STYLE_UNION: 1019 { 1020 out << "union_value: {\n"; 1021 break; 1022 } 1023 } 1024 out.indent(); 1025 out << "name: \"" << field->name() << "\"\n"; 1026 status_t status = field->type().emitVtsAttributeType(out); 1027 if (status != OK) { 1028 return status; 1029 } 1030 out.unindent(); 1031 out << "}\n"; 1032 } 1033 1034 return OK; 1035 } 1036 1037 status_t CompoundType::emitVtsAttributeType(Formatter &out) const { 1038 out << "type: " << getVtsType() << "\n"; 1039 out << "predefined_type: \"" << fullName() << "\"\n"; 1040 return OK; 1041 } 1042 1043 bool CompoundType::isJavaCompatible() const { 1044 if (mStyle != STYLE_STRUCT || !Scope::isJavaCompatible()) { 1045 return false; 1046 } 1047 1048 for (const auto &field : *mFields) { 1049 if (!field->type().isJavaCompatible()) { 1050 return false; 1051 } 1052 } 1053 1054 return true; 1055 } 1056 1057 bool CompoundType::containsPointer() const { 1058 if (Scope::containsPointer()) { 1059 return true; 1060 } 1061 1062 for (const auto &field : *mFields) { 1063 if (field->type().containsPointer()) { 1064 return true; 1065 } 1066 } 1067 1068 return false; 1069 } 1070 1071 void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const { 1072 *align = 1; 1073 *size = 0; 1074 1075 size_t offset = 0; 1076 for (const auto &field : *mFields) { 1077 // Each field is aligned according to its alignment requirement. 1078 // The surrounding structure's alignment is the maximum of its 1079 // fields' aligments. 1080 1081 size_t fieldAlign, fieldSize; 1082 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize); 1083 1084 size_t pad = offset % fieldAlign; 1085 if (pad > 0) { 1086 offset += fieldAlign - pad; 1087 } 1088 1089 if (mStyle == STYLE_STRUCT) { 1090 offset += fieldSize; 1091 } else { 1092 *size = std::max(*size, fieldSize); 1093 } 1094 1095 if (fieldAlign > (*align)) { 1096 *align = fieldAlign; 1097 } 1098 } 1099 1100 if (mStyle == STYLE_STRUCT) { 1101 *size = offset; 1102 } 1103 1104 // Final padding to account for the structure's alignment. 1105 size_t pad = (*size) % (*align); 1106 if (pad > 0) { 1107 (*size) += (*align) - pad; 1108 } 1109 1110 if (*size == 0) { 1111 // An empty struct still occupies a byte of space in C++. 1112 *size = 1; 1113 } 1114 } 1115 1116 //////////////////////////////////////////////////////////////////////////////// 1117 1118 CompoundField::CompoundField(const char *name, Type *type) 1119 : mName(name), 1120 mType(type) { 1121 } 1122 1123 std::string CompoundField::name() const { 1124 return mName; 1125 } 1126 1127 const Type &CompoundField::type() const { 1128 return *mType; 1129 } 1130 1131 } // namespace android 1132 1133