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