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