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