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