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