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