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