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 "ArrayType.h" 18 19 #include <hidl-util/Formatter.h> 20 #include <android-base/logging.h> 21 22 #include "ConstantExpression.h" 23 24 namespace android { 25 26 ArrayType::ArrayType(ArrayType *srcArray, ConstantExpression *size) 27 : mElementType(srcArray->mElementType), 28 mSizes(srcArray->mSizes) { 29 prependDimension(size); 30 } 31 32 ArrayType::ArrayType(Type *elementType, ConstantExpression *size) 33 : mElementType(elementType) { 34 prependDimension(size); 35 } 36 37 void ArrayType::prependDimension(ConstantExpression *size) { 38 mSizes.insert(mSizes.begin(), size); 39 } 40 41 void ArrayType::appendDimension(ConstantExpression *size) { 42 mSizes.push_back(size); 43 } 44 45 size_t ArrayType::countDimensions() const { 46 return mSizes.size(); 47 } 48 49 void ArrayType::addNamedTypesToSet(std::set<const FQName> &set) const { 50 mElementType->addNamedTypesToSet(set); 51 } 52 53 bool ArrayType::isArray() const { 54 return true; 55 } 56 57 bool ArrayType::canCheckEquality() const { 58 return mElementType->canCheckEquality(); 59 } 60 61 Type *ArrayType::getElementType() const { 62 return mElementType; 63 } 64 65 std::string ArrayType::getCppType(StorageMode mode, 66 bool specifyNamespaces) const { 67 const std::string base = mElementType->getCppStackType(specifyNamespaces); 68 69 std::string space = specifyNamespaces ? "::android::hardware::" : ""; 70 std::string arrayType = space + "hidl_array<" + base; 71 72 for (size_t i = 0; i < mSizes.size(); ++i) { 73 arrayType += ", "; 74 arrayType += mSizes[i]->cppValue(); 75 76 if (!mSizes[i]->descriptionIsTrivial()) { 77 arrayType += " /* "; 78 arrayType += mSizes[i]->description(); 79 arrayType += " */"; 80 } 81 } 82 83 arrayType += ">"; 84 85 switch (mode) { 86 case StorageMode_Stack: 87 return arrayType; 88 89 case StorageMode_Argument: 90 return "const " + arrayType + "&"; 91 92 case StorageMode_Result: 93 return "const " + arrayType + "*"; 94 } 95 96 CHECK(!"Should not be here"); 97 } 98 99 std::string ArrayType::getInternalDataCppType() const { 100 std::string result = mElementType->getCppStackType(); 101 for (size_t i = 0; i < mSizes.size(); ++i) { 102 result += "["; 103 result += mSizes[i]->cppValue(); 104 result += "]"; 105 } 106 return result; 107 } 108 109 std::string ArrayType::getJavaType(bool forInitializer) const { 110 std::string base = 111 mElementType->getJavaType(forInitializer); 112 113 for (size_t i = 0; i < mSizes.size(); ++i) { 114 base += "["; 115 116 if (forInitializer) { 117 base += mSizes[i]->javaValue(); 118 } 119 120 if (!forInitializer || !mSizes[i]->descriptionIsTrivial()) { 121 if (forInitializer) 122 base += " "; 123 base += "/* " + mSizes[i]->description() + " */"; 124 } 125 126 base += "]"; 127 } 128 129 return base; 130 } 131 132 std::string ArrayType::getJavaWrapperType() const { 133 return mElementType->getJavaWrapperType(); 134 } 135 136 std::string ArrayType::getVtsType() const { 137 return "TYPE_ARRAY"; 138 } 139 140 void ArrayType::emitReaderWriter( 141 Formatter &out, 142 const std::string &name, 143 const std::string &parcelObj, 144 bool parcelObjIsPointer, 145 bool isReader, 146 ErrorMode mode) const { 147 std::string baseType = mElementType->getCppStackType(); 148 149 const std::string parentName = "_hidl_" + name + "_parent"; 150 151 out << "size_t " << parentName << ";\n\n"; 152 153 const std::string parcelObjDeref = 154 parcelObj + (parcelObjIsPointer ? "->" : "."); 155 156 size_t numArrayElements = 1; 157 for (auto size : mSizes) { 158 numArrayElements *= size->castSizeT(); 159 } 160 if (isReader) { 161 out << "_hidl_err = " 162 << parcelObjDeref 163 << "readBuffer(" 164 << numArrayElements 165 << " * sizeof(" 166 << baseType 167 << "), &" 168 << parentName 169 << ", " 170 << " reinterpret_cast<const void **>(" 171 << "&" << name 172 << "));\n\n"; 173 174 handleError(out, mode); 175 } else { 176 177 out << "_hidl_err = " 178 << parcelObjDeref 179 << "writeBuffer(" 180 << name 181 << ".data(), " 182 << numArrayElements 183 << " * sizeof(" 184 << baseType 185 << "), &" 186 << parentName 187 << ");\n"; 188 189 handleError(out, mode); 190 } 191 192 emitReaderWriterEmbedded( 193 out, 194 0 /* depth */, 195 name, 196 name /* sanitizedName */, 197 isReader /* nameIsPointer */, 198 parcelObj, 199 parcelObjIsPointer, 200 isReader, 201 mode, 202 parentName, 203 "0 /* parentOffset */"); 204 } 205 206 void ArrayType::emitReaderWriterEmbedded( 207 Formatter &out, 208 size_t depth, 209 const std::string &name, 210 const std::string &sanitizedName, 211 bool nameIsPointer, 212 const std::string &parcelObj, 213 bool parcelObjIsPointer, 214 bool isReader, 215 ErrorMode mode, 216 const std::string &parentName, 217 const std::string &offsetText) const { 218 if (!mElementType->needsEmbeddedReadWrite()) { 219 return; 220 } 221 222 const std::string nameDeref = name + (nameIsPointer ? "->" : "."); 223 224 std::string baseType = mElementType->getCppStackType(); 225 226 std::string iteratorName = "_hidl_index_" + std::to_string(depth); 227 228 out << "for (size_t " 229 << iteratorName 230 << " = 0; " 231 << iteratorName 232 << " < " 233 << dimension() 234 << "; ++" 235 << iteratorName 236 << ") {\n"; 237 238 out.indent(); 239 240 mElementType->emitReaderWriterEmbedded( 241 out, 242 depth + 1, 243 nameDeref + "data()[" + iteratorName + "]", 244 sanitizedName + "_indexed", 245 false /* nameIsPointer */, 246 parcelObj, 247 parcelObjIsPointer, 248 isReader, 249 mode, 250 parentName, 251 offsetText 252 + " + " + iteratorName + " * sizeof(" 253 + baseType 254 + ")"); 255 256 out.unindent(); 257 258 out << "}\n\n"; 259 } 260 261 void ArrayType::emitResolveReferences( 262 Formatter &out, 263 const std::string &name, 264 bool nameIsPointer, 265 const std::string &parcelObj, 266 bool parcelObjIsPointer, 267 bool isReader, 268 ErrorMode mode) const { 269 emitResolveReferencesEmbedded( 270 out, 271 0 /* depth */, 272 name, 273 name /* sanitizedName */, 274 nameIsPointer, 275 parcelObj, 276 parcelObjIsPointer, 277 isReader, 278 mode, 279 "_hidl_" + name + "_parent", 280 "0 /* parentOffset */"); 281 } 282 283 void ArrayType::emitResolveReferencesEmbedded( 284 Formatter &out, 285 size_t depth, 286 const std::string &name, 287 const std::string &sanitizedName, 288 bool nameIsPointer, 289 const std::string &parcelObj, 290 bool parcelObjIsPointer, 291 bool isReader, 292 ErrorMode mode, 293 const std::string &parentName, 294 const std::string &offsetText) const { 295 CHECK(needsResolveReferences() && mElementType->needsResolveReferences()); 296 297 const std::string nameDeref = name + (nameIsPointer ? "->" : "."); 298 299 std::string baseType = mElementType->getCppStackType(); 300 301 std::string iteratorName = "_hidl_index_" + std::to_string(depth); 302 303 out << "for (size_t " 304 << iteratorName 305 << " = 0; " 306 << iteratorName 307 << " < " 308 << dimension() 309 << "; ++" 310 << iteratorName 311 << ") {\n"; 312 313 out.indent(); 314 315 mElementType->emitResolveReferencesEmbedded( 316 out, 317 depth + 1, 318 nameDeref + "data()[" + iteratorName + "]", 319 sanitizedName + "_indexed", 320 false /* nameIsPointer */, 321 parcelObj, 322 parcelObjIsPointer, 323 isReader, 324 mode, 325 parentName, 326 offsetText + " + " + iteratorName + " * sizeof(" 327 + baseType 328 + ")"); 329 330 out.unindent(); 331 332 out << "}\n\n"; 333 } 334 335 void ArrayType::emitJavaDump( 336 Formatter &out, 337 const std::string &streamName, 338 const std::string &name) const { 339 out << streamName << ".append(java.util.Arrays." 340 << (countDimensions() > 1 ? "deepToString" : "toString") 341 << "(" 342 << name << "));\n"; 343 } 344 345 346 bool ArrayType::needsEmbeddedReadWrite() const { 347 return mElementType->needsEmbeddedReadWrite(); 348 } 349 350 bool ArrayType::needsResolveReferences() const { 351 return mElementType->needsResolveReferences(); 352 } 353 354 bool ArrayType::resultNeedsDeref() const { 355 return true; 356 } 357 358 void ArrayType::emitJavaReaderWriter( 359 Formatter &out, 360 const std::string &parcelObj, 361 const std::string &argName, 362 bool isReader) const { 363 size_t align, size; 364 getAlignmentAndSize(&align, &size); 365 366 if (isReader) { 367 out << "new " 368 << getJavaType(true /* forInitializer */) 369 << ";\n"; 370 } 371 372 out << "{\n"; 373 out.indent(); 374 375 out << "android.os.HwBlob _hidl_blob = "; 376 377 if (isReader) { 378 out << parcelObj 379 << ".readBuffer(" 380 << size 381 << " /* size */);\n"; 382 } else { 383 out << "new android.os.HwBlob(" 384 << size 385 << " /* size */);\n"; 386 } 387 388 emitJavaFieldReaderWriter( 389 out, 390 0 /* depth */, 391 parcelObj, 392 "_hidl_blob", 393 argName, 394 "0 /* offset */", 395 isReader); 396 397 if (!isReader) { 398 out << parcelObj << ".writeBuffer(_hidl_blob);\n"; 399 } 400 401 out.unindent(); 402 out << "}\n"; 403 } 404 405 void ArrayType::emitJavaFieldInitializer( 406 Formatter &out, const std::string &fieldName) const { 407 std::string typeName = getJavaType(false /* forInitializer */); 408 std::string initName = getJavaType(true /* forInitializer */); 409 410 out << "final " 411 << typeName 412 << " " 413 << fieldName 414 << " = new " 415 << initName 416 << ";\n"; 417 } 418 419 void ArrayType::emitJavaFieldReaderWriter( 420 Formatter &out, 421 size_t depth, 422 const std::string &parcelName, 423 const std::string &blobName, 424 const std::string &fieldName, 425 const std::string &offset, 426 bool isReader) const { 427 out << "{\n"; 428 out.indent(); 429 430 std::string offsetName = "_hidl_array_offset_" + std::to_string(depth); 431 out << "long " << offsetName << " = " << offset << ";\n"; 432 433 std::string indexString; 434 for (size_t dim = 0; dim < mSizes.size(); ++dim) { 435 std::string iteratorName = 436 "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim); 437 438 out << "for (int " 439 << iteratorName 440 << " = 0; " 441 << iteratorName 442 << " < " 443 << mSizes[dim]->javaValue() 444 << "; ++" 445 << iteratorName 446 << ") {\n"; 447 448 out.indent(); 449 450 indexString += "[" + iteratorName + "]"; 451 } 452 453 if (isReader && mElementType->isCompoundType()) { 454 std::string typeName = 455 mElementType->getJavaType(false /* forInitializer */); 456 457 out << fieldName 458 << indexString 459 << " = new " 460 << typeName 461 << "();\n"; 462 } 463 464 mElementType->emitJavaFieldReaderWriter( 465 out, 466 depth + 1, 467 parcelName, 468 blobName, 469 fieldName + indexString, 470 offsetName, 471 isReader); 472 473 size_t elementAlign, elementSize; 474 mElementType->getAlignmentAndSize(&elementAlign, &elementSize); 475 476 out << offsetName << " += " << std::to_string(elementSize) << ";\n"; 477 478 for (size_t dim = 0; dim < mSizes.size(); ++dim) { 479 out.unindent(); 480 out << "}\n"; 481 } 482 483 out.unindent(); 484 out << "}\n"; 485 } 486 487 status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const { 488 out << "type: " << getVtsType() << "\n"; 489 out << "vector_size: " << mSizes[0]->value() << "\n"; 490 out << "vector_value: {\n"; 491 out.indent(); 492 // Simple array case. 493 if (mSizes.size() == 1) { 494 status_t err = mElementType->emitVtsTypeDeclarations(out); 495 if (err != OK) { 496 return err; 497 } 498 } else { // Multi-dimension array case. 499 for (size_t index = 1; index < mSizes.size(); index++) { 500 out << "type: " << getVtsType() << "\n"; 501 out << "vector_size: " << mSizes[index]->value() << "\n"; 502 out << "vector_value: {\n"; 503 out.indent(); 504 if (index == mSizes.size() - 1) { 505 status_t err = mElementType->emitVtsTypeDeclarations(out); 506 if (err != OK) { 507 return err; 508 } 509 } 510 } 511 } 512 for (size_t index = 0; index < mSizes.size(); index++) { 513 out.unindent(); 514 out << "}\n"; 515 } 516 return OK; 517 } 518 519 bool ArrayType::isJavaCompatible() const { 520 return mElementType->isJavaCompatible(); 521 } 522 523 bool ArrayType::containsPointer() const { 524 return mElementType->containsPointer(); 525 } 526 527 void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const { 528 mElementType->getAlignmentAndSize(align, size); 529 530 for (auto sizeInDimension : mSizes) { 531 (*size) *= sizeInDimension->castSizeT(); 532 } 533 } 534 535 size_t ArrayType::dimension() const { 536 size_t numArrayElements = 1; 537 for (auto size : mSizes) { 538 numArrayElements *= size->castSizeT(); 539 } 540 return numArrayElements; 541 } 542 543 } // namespace android 544 545