1 #include "rsCpuExecutable.h" 2 #include "rsCppUtils.h" 3 4 #include <fstream> 5 #include <set> 6 #include <memory> 7 8 #include <sys/stat.h> 9 10 #ifdef RS_COMPATIBILITY_LIB 11 #include <stdio.h> 12 #include <unistd.h> 13 #else 14 #include "bcc/Config.h" 15 #endif 16 17 #include <dlfcn.h> 18 #include <sys/stat.h> 19 20 namespace android { 21 namespace renderscript { 22 23 namespace { 24 25 // Check if a path exists and attempt to create it if it doesn't. 26 static bool ensureCacheDirExists(const char *path) { 27 if (access(path, R_OK | W_OK | X_OK) == 0) { 28 // Done if we can rwx the directory 29 return true; 30 } 31 if (mkdir(path, 0700) == 0) { 32 return true; 33 } 34 return false; 35 } 36 37 // Copy the file named \p srcFile to \p dstFile. 38 // Return 0 on success and -1 if anything wasn't copied. 39 static int copyFile(const char *dstFile, const char *srcFile) { 40 std::ifstream srcStream(srcFile); 41 if (!srcStream) { 42 ALOGE("Could not verify or read source file: %s", srcFile); 43 return -1; 44 } 45 std::ofstream dstStream(dstFile); 46 if (!dstStream) { 47 ALOGE("Could not verify or write destination file: %s", dstFile); 48 return -1; 49 } 50 dstStream << srcStream.rdbuf(); 51 if (!dstStream) { 52 ALOGE("Could not write destination file: %s", dstFile); 53 return -1; 54 } 55 56 srcStream.close(); 57 dstStream.close(); 58 59 return 0; 60 } 61 62 static std::string findSharedObjectName(const char *cacheDir, 63 const char *resName, 64 const bool reuse = true) { 65 std::string scriptSOName(cacheDir); 66 #if defined(RS_COMPATIBILITY_LIB) && !defined(__LP64__) 67 size_t cutPos = scriptSOName.rfind("cache"); 68 if (cutPos != std::string::npos) { 69 scriptSOName.erase(cutPos); 70 } else { 71 ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir); 72 } 73 scriptSOName.append("/lib/librs."); 74 #else 75 scriptSOName.append("/librs."); 76 #endif // RS_COMPATIBILITY_LIB 77 scriptSOName.append(resName); 78 if (!reuse) { 79 // If the generated shared library is not reused, e.g., with a debug 80 // context or forced by a system property, multiple threads may read 81 // and write the shared library at the same time. To avoid the race 82 // on the generated shared library, delete it before finishing script 83 // initialization. To avoid deleting a file generated by a regular 84 // context, use a special suffix here. 85 // Because the script initialization is guarded by a lock from the Java 86 // API, it is safe to name this file with a consistent name and suffix 87 // and delete it after loading. The same lock has also prevented write- 88 // write races on the .so during script initialization even if reuse is 89 // true. 90 scriptSOName.append("#delete_after_load"); 91 } 92 scriptSOName.append(".so"); 93 94 return scriptSOName; 95 } 96 97 } // anonymous namespace 98 99 const char* SharedLibraryUtils::LD_EXE_PATH = "/system/bin/ld.mc"; 100 const char* SharedLibraryUtils::RS_CACHE_DIR = "com.android.renderscript.cache"; 101 102 #ifndef RS_COMPATIBILITY_LIB 103 104 bool SharedLibraryUtils::createSharedLibrary(const char *driverName, 105 const char *cacheDir, 106 const char *resName, 107 const bool reuse, 108 std::string *fullPath) { 109 std::string sharedLibName = findSharedObjectName(cacheDir, resName, reuse); 110 if (fullPath) { 111 *fullPath = sharedLibName; 112 } 113 std::string objFileName = cacheDir; 114 objFileName.append("/"); 115 objFileName.append(resName); 116 objFileName.append(".o"); 117 // Should be something like "libRSDriver.so". 118 std::string linkDriverName = driverName; 119 // Remove ".so" and replace "lib" with "-l". 120 // This will leave us with "-lRSDriver" instead. 121 linkDriverName.erase(linkDriverName.length() - 3); 122 linkDriverName.replace(0, 3, "-l"); 123 124 const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so"; 125 const char *mTriple = "-mtriple=" DEFAULT_TARGET_TRIPLE_STRING; 126 const char *libPath = "--library-path=" SYSLIBPATH; 127 const char *vendorLibPath = "--library-path=" SYSLIBPATH_VENDOR; 128 129 std::vector<const char *> args = { 130 LD_EXE_PATH, 131 "-shared", 132 "-nostdlib", 133 compiler_rt, mTriple, vendorLibPath, libPath, 134 linkDriverName.c_str(), "-lm", "-lc", 135 objFileName.c_str(), 136 "-o", sharedLibName.c_str(), 137 nullptr 138 }; 139 140 return rsuExecuteCommand(LD_EXE_PATH, args.size()-1, args.data()); 141 142 } 143 144 #endif // RS_COMPATIBILITY_LIB 145 146 const char* RsdCpuScriptImpl::BCC_EXE_PATH = "/system/bin/bcc"; 147 148 void* SharedLibraryUtils::loadAndDeleteSharedLibrary(const char *fullPath) { 149 void *loaded = dlopen(fullPath, RTLD_NOW | RTLD_LOCAL); 150 if (loaded == nullptr) { 151 ALOGE("Unable to open shared library (%s): %s", fullPath, dlerror()); 152 return nullptr; 153 } 154 155 int r = unlink(fullPath); 156 if (r != 0) { 157 ALOGE("Could not unlink copy %s", fullPath); 158 return nullptr; 159 } 160 return loaded; 161 } 162 163 void* SharedLibraryUtils::loadSharedLibrary(const char *cacheDir, 164 const char *resName, 165 const char *nativeLibDir, 166 bool* alreadyLoaded) { 167 void *loaded = nullptr; 168 169 #if defined(RS_COMPATIBILITY_LIB) && defined(__LP64__) 170 std::string scriptSOName = findSharedObjectName(nativeLibDir, resName); 171 #else 172 std::string scriptSOName = findSharedObjectName(cacheDir, resName); 173 #endif 174 175 // We should check if we can load the library from the standard app 176 // location for shared libraries first. 177 loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName, alreadyLoaded); 178 179 if (loaded == nullptr) { 180 ALOGE("Unable to open shared library (%s): %s", 181 scriptSOName.c_str(), dlerror()); 182 183 #ifdef RS_COMPATIBILITY_LIB 184 // One final attempt to find the library in "/system/lib". 185 // We do this to allow bundled applications to use the compatibility 186 // library fallback path. Those applications don't have a private 187 // library path, so they need to install to the system directly. 188 // Note that this is really just a testing path. 189 std::string scriptSONameSystem("/system/lib/librs."); 190 scriptSONameSystem.append(resName); 191 scriptSONameSystem.append(".so"); 192 loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir, 193 resName); 194 if (loaded == nullptr) { 195 ALOGE("Unable to open system shared library (%s): %s", 196 scriptSONameSystem.c_str(), dlerror()); 197 } 198 #endif 199 } 200 201 return loaded; 202 } 203 204 std::string SharedLibraryUtils::getRandomString(size_t len) { 205 char buf[len + 1]; 206 for (size_t i = 0; i < len; i++) { 207 uint32_t r = arc4random() & 0xffff; 208 r %= 62; 209 if (r < 26) { 210 // lowercase 211 buf[i] = 'a' + r; 212 } else if (r < 52) { 213 // uppercase 214 buf[i] = 'A' + (r - 26); 215 } else { 216 // Use a number 217 buf[i] = '0' + (r - 52); 218 } 219 } 220 buf[len] = '\0'; 221 return std::string(buf); 222 } 223 224 void* SharedLibraryUtils::loadSOHelper(const char *origName, const char *cacheDir, 225 const char *resName, bool *alreadyLoaded) { 226 // Keep track of which .so libraries have been loaded. Once a library is 227 // in the set (per-process granularity), we must instead make a copy of 228 // the original shared object (randomly named .so file) and load that one 229 // instead. If we don't do this, we end up aliasing global data between 230 // the various Script instances (which are supposed to be completely 231 // independent). 232 static std::set<std::string> LoadedLibraries; 233 234 void *loaded = nullptr; 235 236 // Skip everything if we don't even have the original library available. 237 if (access(origName, F_OK) != 0) { 238 return nullptr; 239 } 240 241 // Common path is that we have not loaded this Script/library before. 242 if (LoadedLibraries.find(origName) == LoadedLibraries.end()) { 243 if (alreadyLoaded != nullptr) { 244 *alreadyLoaded = false; 245 } 246 loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL); 247 if (loaded) { 248 LoadedLibraries.insert(origName); 249 } 250 return loaded; 251 } 252 253 if (alreadyLoaded != nullptr) { 254 *alreadyLoaded = true; 255 } 256 257 std::string newName(cacheDir); 258 259 // Append RS_CACHE_DIR only if it is not found in cacheDir 260 // In driver mode, RS_CACHE_DIR is already appended to cacheDir. 261 if (newName.find(RS_CACHE_DIR) == std::string::npos) { 262 newName.append("/"); 263 newName.append(RS_CACHE_DIR); 264 newName.append("/"); 265 } 266 267 if (!ensureCacheDirExists(newName.c_str())) { 268 ALOGE("Could not verify or create cache dir: %s", cacheDir); 269 return nullptr; 270 } 271 272 // Construct an appropriately randomized filename for the copy. 273 newName.append("librs."); 274 newName.append(resName); 275 newName.append("#"); 276 newName.append(getRandomString(6).c_str()); // 62^6 potential filename variants. 277 newName.append(".so"); 278 279 int r = copyFile(newName.c_str(), origName); 280 if (r != 0) { 281 ALOGE("Could not create copy %s -> %s", origName, newName.c_str()); 282 return nullptr; 283 } 284 loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL); 285 r = unlink(newName.c_str()); 286 if (r != 0) { 287 ALOGE("Could not unlink copy %s", newName.c_str()); 288 } 289 if (loaded) { 290 LoadedLibraries.insert(newName.c_str()); 291 } 292 293 return loaded; 294 } 295 296 // MAXLINESTR must be compatible with operator '#' in C macro. 297 #define MAXLINESTR 499 298 // MAXLINE must be (MAXLINESTR + 1), representing the size of a C string 299 // containing MAXLINESTR non-null chars plus a null. 300 #define MAXLINE (MAXLINESTR + 1) 301 #define MAKE_STR_HELPER(S) #S 302 #define MAKE_STR(S) MAKE_STR_HELPER(S) 303 #define EXPORT_VAR_STR "exportVarCount: " 304 #define EXPORT_FUNC_STR "exportFuncCount: " 305 #define EXPORT_FOREACH_STR "exportForEachCount: " 306 #define EXPORT_REDUCE_STR "exportReduceCount: " 307 #define OBJECT_SLOT_STR "objectSlotCount: " 308 #define PRAGMA_STR "pragmaCount: " 309 #define THREADABLE_STR "isThreadable: " 310 #define CHECKSUM_STR "buildChecksum: " 311 #define VERSIONINFO_STR "versionInfo: " 312 313 // Copy up to a newline or size chars from str -> s, updating str 314 // Returns s when successful and nullptr when '\0' is finally reached. 315 static char* strgets(char *s, int size, const char **ppstr) { 316 if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) { 317 return nullptr; 318 } 319 320 int i; 321 for (i = 0; i < (size - 1); i++) { 322 s[i] = **ppstr; 323 (*ppstr)++; 324 if (s[i] == '\0') { 325 return s; 326 } else if (s[i] == '\n') { 327 s[i+1] = '\0'; 328 return s; 329 } 330 } 331 332 // size has been exceeded. 333 s[i] = '\0'; 334 335 return s; 336 } 337 338 // Creates a duplicate of a string. The new string is as small as possible, 339 // only including characters up to and including the first null-terminator; 340 // otherwise, the new string will be the same size as the input string. 341 // The code that calls duplicateString is responsible for the new string's 342 // lifetime, and is responsible for freeing it when it is no longer needed. 343 static char* duplicateString(const char *str, size_t length) { 344 const size_t newLen = strnlen(str, length-1) + 1; 345 char *newStr = new char[newLen]; 346 strlcpy(newStr, str, newLen); 347 return newStr; 348 } 349 350 ScriptExecutable* ScriptExecutable::createFromSharedObject( 351 void* sharedObj, uint32_t expectedChecksum) { 352 char line[MAXLINE]; 353 354 size_t varCount = 0; 355 size_t funcCount = 0; 356 size_t forEachCount = 0; 357 size_t reduceCount = 0; 358 size_t objectSlotCount = 0; 359 size_t pragmaCount = 0; 360 bool isThreadable = true; 361 362 void** fieldAddress = nullptr; 363 bool* fieldIsObject = nullptr; 364 char** fieldName = nullptr; 365 InvokeFunc_t* invokeFunctions = nullptr; 366 ForEachFunc_t* forEachFunctions = nullptr; 367 uint32_t* forEachSignatures = nullptr; 368 ReduceDescription* reduceDescriptions = nullptr; 369 const char ** pragmaKeys = nullptr; 370 const char ** pragmaValues = nullptr; 371 uint32_t checksum = 0; 372 373 const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo); 374 int numEntries = 0; 375 const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries); 376 const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames); 377 const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses); 378 const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes); 379 const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties); 380 381 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 382 return nullptr; 383 } 384 if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) { 385 ALOGE("Invalid export var count!: %s", line); 386 return nullptr; 387 } 388 389 fieldAddress = new void*[varCount]; 390 if (fieldAddress == nullptr) { 391 return nullptr; 392 } 393 394 fieldIsObject = new bool[varCount]; 395 if (fieldIsObject == nullptr) { 396 goto error; 397 } 398 399 fieldName = new char*[varCount]; 400 if (fieldName == nullptr) { 401 goto error; 402 } 403 404 for (size_t i = 0; i < varCount; ++i) { 405 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 406 goto error; 407 } 408 char *c = strrchr(line, '\n'); 409 if (c) { 410 *c = '\0'; 411 } 412 void* addr = dlsym(sharedObj, line); 413 if (addr == nullptr) { 414 ALOGE("Failed to find variable address for %s: %s", 415 line, dlerror()); 416 // Not a critical error if we don't find a global variable. 417 } 418 fieldAddress[i] = addr; 419 fieldIsObject[i] = false; 420 fieldName[i] = duplicateString(line, sizeof(line)); 421 } 422 423 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 424 goto error; 425 } 426 if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) { 427 ALOGE("Invalid export func count!: %s", line); 428 goto error; 429 } 430 431 invokeFunctions = new InvokeFunc_t[funcCount]; 432 if (invokeFunctions == nullptr) { 433 goto error; 434 } 435 436 for (size_t i = 0; i < funcCount; ++i) { 437 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 438 goto error; 439 } 440 char *c = strrchr(line, '\n'); 441 if (c) { 442 *c = '\0'; 443 } 444 445 invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line); 446 if (invokeFunctions[i] == nullptr) { 447 ALOGE("Failed to get function address for %s(): %s", 448 line, dlerror()); 449 goto error; 450 } 451 } 452 453 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 454 goto error; 455 } 456 if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) { 457 ALOGE("Invalid export forEach count!: %s", line); 458 goto error; 459 } 460 461 forEachFunctions = new ForEachFunc_t[forEachCount]; 462 if (forEachFunctions == nullptr) { 463 goto error; 464 } 465 466 forEachSignatures = new uint32_t[forEachCount]; 467 if (forEachSignatures == nullptr) { 468 goto error; 469 } 470 471 for (size_t i = 0; i < forEachCount; ++i) { 472 unsigned int tmpSig = 0; 473 char tmpName[MAXLINE]; 474 475 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 476 goto error; 477 } 478 if (sscanf(line, "%u - %" MAKE_STR(MAXLINESTR) "s", 479 &tmpSig, tmpName) != 2) { 480 ALOGE("Invalid export forEach!: %s", line); 481 goto error; 482 } 483 484 // Lookup the expanded ForEach kernel. 485 strncat(tmpName, ".expand", MAXLINESTR-strlen(tmpName)); 486 forEachSignatures[i] = tmpSig; 487 forEachFunctions[i] = 488 (ForEachFunc_t) dlsym(sharedObj, tmpName); 489 if (i != 0 && forEachFunctions[i] == nullptr && 490 strcmp(tmpName, "root.expand")) { 491 // Ignore missing root.expand functions. 492 // root() is always specified at location 0. 493 ALOGE("Failed to find forEach function address for %s(): %s", 494 tmpName, dlerror()); 495 goto error; 496 } 497 } 498 499 // Read general reduce kernels 500 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 501 goto error; 502 } 503 if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) { 504 ALOGE("Invalid export reduce new count!: %s", line); 505 goto error; 506 } 507 508 reduceDescriptions = new ReduceDescription[reduceCount]; 509 if (reduceDescriptions == nullptr) { 510 goto error; 511 } 512 513 for (size_t i = 0; i < reduceCount; ++i) { 514 static const char kNoName[] = "."; 515 516 unsigned int tmpSig = 0; 517 size_t tmpSize = 0; 518 char tmpNameReduce[MAXLINE]; 519 char tmpNameInitializer[MAXLINE]; 520 char tmpNameAccumulator[MAXLINE]; 521 char tmpNameCombiner[MAXLINE]; 522 char tmpNameOutConverter[MAXLINE]; 523 char tmpNameHalter[MAXLINE]; 524 525 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 526 goto error; 527 } 528 #define DELIMNAME " - %" MAKE_STR(MAXLINESTR) "s" 529 if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME, 530 &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator, 531 tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) { 532 ALOGE("Invalid export reduce new!: %s", line); 533 goto error; 534 } 535 #undef DELIMNAME 536 537 // For now, we expect 538 // - Reduce and Accumulator names 539 // - optional Initializer, Combiner, and OutConverter name 540 // - no Halter name 541 if (!strcmp(tmpNameReduce, kNoName) || 542 !strcmp(tmpNameAccumulator, kNoName)) { 543 ALOGE("Expected reduce and accumulator names!: %s", line); 544 goto error; 545 } 546 if (strcmp(tmpNameHalter, kNoName)) { 547 ALOGE("Did not expect halter name!: %s", line); 548 goto error; 549 } 550 551 // The current implementation does not use the signature 552 // or reduce name. 553 554 reduceDescriptions[i].accumSize = tmpSize; 555 556 // Process the (optional) initializer. 557 if (strcmp(tmpNameInitializer, kNoName)) { 558 // Lookup the original user-written initializer. 559 if (!(reduceDescriptions[i].initFunc = 560 (ReduceInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) { 561 ALOGE("Failed to find initializer function address for %s(): %s", 562 tmpNameInitializer, dlerror()); 563 goto error; 564 } 565 } else { 566 reduceDescriptions[i].initFunc = nullptr; 567 } 568 569 // Lookup the expanded accumulator. 570 strncat(tmpNameAccumulator, ".expand", MAXLINESTR-strlen(tmpNameAccumulator)); 571 if (!(reduceDescriptions[i].accumFunc = 572 (ReduceAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) { 573 ALOGE("Failed to find accumulator function address for %s(): %s", 574 tmpNameAccumulator, dlerror()); 575 goto error; 576 } 577 578 // Process the (optional) combiner. 579 if (strcmp(tmpNameCombiner, kNoName)) { 580 // Lookup the original user-written combiner. 581 if (!(reduceDescriptions[i].combFunc = 582 (ReduceCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) { 583 ALOGE("Failed to find combiner function address for %s(): %s", 584 tmpNameCombiner, dlerror()); 585 goto error; 586 } 587 } else { 588 reduceDescriptions[i].combFunc = nullptr; 589 } 590 591 // Process the (optional) outconverter. 592 if (strcmp(tmpNameOutConverter, kNoName)) { 593 // Lookup the original user-written outconverter. 594 if (!(reduceDescriptions[i].outFunc = 595 (ReduceOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) { 596 ALOGE("Failed to find outconverter function address for %s(): %s", 597 tmpNameOutConverter, dlerror()); 598 goto error; 599 } 600 } else { 601 reduceDescriptions[i].outFunc = nullptr; 602 } 603 } 604 605 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 606 goto error; 607 } 608 if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) { 609 ALOGE("Invalid object slot count!: %s", line); 610 goto error; 611 } 612 613 for (size_t i = 0; i < objectSlotCount; ++i) { 614 uint32_t varNum = 0; 615 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 616 goto error; 617 } 618 if (sscanf(line, "%u", &varNum) != 1) { 619 ALOGE("Invalid object slot!: %s", line); 620 goto error; 621 } 622 623 if (varNum < varCount) { 624 fieldIsObject[varNum] = true; 625 } 626 } 627 628 #ifndef RS_COMPATIBILITY_LIB 629 // Do not attempt to read pragmas or isThreadable flag in compat lib path. 630 // Neither is applicable for compat lib 631 632 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 633 goto error; 634 } 635 636 if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) { 637 ALOGE("Invalid pragma count!: %s", line); 638 goto error; 639 } 640 641 pragmaKeys = new const char*[pragmaCount]; 642 if (pragmaKeys == nullptr) { 643 goto error; 644 } 645 646 pragmaValues = new const char*[pragmaCount]; 647 if (pragmaValues == nullptr) { 648 goto error; 649 } 650 651 bzero(pragmaKeys, sizeof(char*) * pragmaCount); 652 bzero(pragmaValues, sizeof(char*) * pragmaCount); 653 654 for (size_t i = 0; i < pragmaCount; ++i) { 655 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 656 ALOGE("Unable to read pragma at index %zu!", i); 657 goto error; 658 } 659 char key[MAXLINE]; 660 char value[MAXLINE] = ""; // initialize in case value is empty 661 662 // pragmas can just have a key and no value. Only check to make sure 663 // that the key is not empty 664 if (sscanf(line, "%" MAKE_STR(MAXLINESTR) "s - %" MAKE_STR(MAXLINESTR) "s", 665 key, value) == 0 || 666 strlen(key) == 0) 667 { 668 ALOGE("Invalid pragma value!: %s", line); 669 670 goto error; 671 } 672 673 pragmaKeys[i] = duplicateString(key, sizeof(key)); 674 pragmaValues[i] = duplicateString(value, sizeof(value)); 675 //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue); 676 } 677 678 if (strgets(line, MAXLINE, &rsInfo) == nullptr) { 679 goto error; 680 } 681 682 char tmpFlag[4]; 683 if (sscanf(line, THREADABLE_STR "%3s", tmpFlag) != 1) { 684 ALOGE("Invalid threadable flag!: %s", line); 685 goto error; 686 } 687 if (strcmp(tmpFlag, "yes") == 0) { 688 isThreadable = true; 689 } else if (strcmp(tmpFlag, "no") == 0) { 690 isThreadable = false; 691 } else { 692 ALOGE("Invalid threadable flag!: %s", tmpFlag); 693 goto error; 694 } 695 696 if (strgets(line, MAXLINE, &rsInfo) != nullptr) { 697 if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) { 698 ALOGE("Invalid checksum flag!: %s", line); 699 goto error; 700 } 701 } else { 702 ALOGE("Missing checksum in shared obj file"); 703 goto error; 704 } 705 706 if (expectedChecksum != 0 && checksum != expectedChecksum) { 707 ALOGE("Found invalid checksum. Expected %08x, got %08x\n", 708 expectedChecksum, checksum); 709 goto error; 710 } 711 712 { 713 // Parse the version info string, but ignore its contents as it's only 714 // used by the debugger 715 size_t nLines = 0; 716 if (strgets(line, MAXLINE, &rsInfo) != nullptr) { 717 if (sscanf(line, VERSIONINFO_STR "%zu", &nLines) != 1) { 718 ALOGE("invalid versionInfo count"); 719 goto error; 720 } else { 721 // skip the versionInfo packet as libRs doesn't use it 722 while (nLines--) { 723 if (strgets(line, MAXLINE, &rsInfo) == nullptr) 724 goto error; 725 } 726 } 727 } else { 728 ALOGE(".rs.info is missing versionInfo section"); 729 } 730 } 731 732 #endif // RS_COMPATIBILITY_LIB 733 734 // Read in information about mutable global variables provided by bcc's 735 // RSGlobalInfoPass 736 if (rsGlobalEntries) { 737 numEntries = *rsGlobalEntries; 738 if (numEntries > 0) { 739 rsAssert(rsGlobalNames); 740 rsAssert(rsGlobalAddresses); 741 rsAssert(rsGlobalSizes); 742 rsAssert(rsGlobalProperties); 743 } 744 } 745 746 return new ScriptExecutable( 747 fieldAddress, fieldIsObject, fieldName, varCount, 748 invokeFunctions, funcCount, 749 forEachFunctions, forEachSignatures, forEachCount, 750 reduceDescriptions, reduceCount, 751 pragmaKeys, pragmaValues, pragmaCount, 752 rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties, 753 numEntries, isThreadable, checksum); 754 755 error: 756 757 #ifndef RS_COMPATIBILITY_LIB 758 759 if (pragmaKeys) { 760 for (size_t idx = 0; idx < pragmaCount; ++idx) { 761 delete [] pragmaKeys[idx]; 762 } 763 } 764 765 if (pragmaValues) { 766 for (size_t idx = 0; idx < pragmaCount; ++idx) { 767 delete [] pragmaValues[idx]; 768 } 769 } 770 771 delete[] pragmaValues; 772 delete[] pragmaKeys; 773 #endif // RS_COMPATIBILITY_LIB 774 775 delete[] reduceDescriptions; 776 777 delete[] forEachSignatures; 778 delete[] forEachFunctions; 779 780 delete[] invokeFunctions; 781 782 for (size_t i = 0; i < varCount; i++) { 783 delete[] fieldName[i]; 784 } 785 delete[] fieldName; 786 delete[] fieldIsObject; 787 delete[] fieldAddress; 788 789 return nullptr; 790 } 791 792 void* ScriptExecutable::getFieldAddress(const char* name) const { 793 // TODO: improve this by using a hash map. 794 for (size_t i = 0; i < mExportedVarCount; i++) { 795 if (strcmp(name, mFieldName[i]) == 0) { 796 return mFieldAddress[i]; 797 } 798 } 799 return nullptr; 800 } 801 802 bool ScriptExecutable::dumpGlobalInfo() const { 803 ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames); 804 ALOGE("P - Pointer"); 805 ALOGE(" C - Constant"); 806 ALOGE(" S - Static"); 807 for (int i = 0; i < mGlobalEntries; i++) { 808 ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i], 809 mGlobalNames[i]); 810 uint32_t properties = mGlobalProperties[i]; 811 ALOGE("%c%c%c Type: %u", 812 isGlobalPointer(properties) ? 'P' : ' ', 813 isGlobalConstant(properties) ? 'C' : ' ', 814 isGlobalStatic(properties) ? 'S' : ' ', 815 getGlobalRsType(properties)); 816 } 817 return true; 818 } 819 820 } // namespace renderscript 821 } // namespace android 822