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