rsCpuExecutable.cpp revision 5e48002cc4a11e9ce63852a77488cfb9f6765c2b
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
18namespace android {
19namespace renderscript {
20
21namespace {
22
23// Check if a path exists and attempt to create it if it doesn't.
24static 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.
37static 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
60static 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
87const char* SharedLibraryUtils::LD_EXE_PATH = "/system/bin/ld.mc";
88const char* SharedLibraryUtils::RS_CACHE_DIR = "com.android.renderscript.cache";
89
90#ifndef RS_COMPATIBILITY_LIB
91
92bool 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
129const char* RsdCpuScriptImpl::BCC_EXE_PATH = "/system/bin/bcc";
130
131void* 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
172String8 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
192void* 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#define MAXLINE 500
265#define MAKE_STR_HELPER(S) #S
266#define MAKE_STR(S) MAKE_STR_HELPER(S)
267#define EXPORT_VAR_STR "exportVarCount: "
268#define EXPORT_FUNC_STR "exportFuncCount: "
269#define EXPORT_FOREACH_STR "exportForEachCount: "
270#define EXPORT_REDUCE_STR "exportReduceCount: "
271#define EXPORT_REDUCE_NEW_STR "exportReduceNewCount: "
272#define OBJECT_SLOT_STR "objectSlotCount: "
273#define PRAGMA_STR "pragmaCount: "
274#define THREADABLE_STR "isThreadable: "
275#define CHECKSUM_STR "buildChecksum: "
276
277// Copy up to a newline or size chars from str -> s, updating str
278// Returns s when successful and nullptr when '\0' is finally reached.
279static char* strgets(char *s, int size, const char **ppstr) {
280    if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
281        return nullptr;
282    }
283
284    int i;
285    for (i = 0; i < (size - 1); i++) {
286        s[i] = **ppstr;
287        (*ppstr)++;
288        if (s[i] == '\0') {
289            return s;
290        } else if (s[i] == '\n') {
291            s[i+1] = '\0';
292            return s;
293        }
294    }
295
296    // size has been exceeded.
297    s[i] = '\0';
298
299    return s;
300}
301
302ScriptExecutable* ScriptExecutable::createFromSharedObject(
303    void* sharedObj, uint32_t expectedChecksum) {
304    char line[MAXLINE];
305
306    size_t varCount = 0;
307    size_t funcCount = 0;
308    size_t forEachCount = 0;
309    size_t reduceCount = 0;
310    size_t reduceNewCount = 0;
311    size_t objectSlotCount = 0;
312    size_t pragmaCount = 0;
313    bool isThreadable = true;
314
315    void** fieldAddress = nullptr;
316    bool* fieldIsObject = nullptr;
317    char** fieldName = nullptr;
318    InvokeFunc_t* invokeFunctions = nullptr;
319    ForEachFunc_t* forEachFunctions = nullptr;
320    uint32_t* forEachSignatures = nullptr;
321    ReduceFunc_t* reduceFunctions = nullptr;
322    ReduceNewDescription* reduceNewDescriptions = nullptr;
323    const char ** pragmaKeys = nullptr;
324    const char ** pragmaValues = nullptr;
325    uint32_t checksum = 0;
326
327    const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo);
328    int numEntries = 0;
329    const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries);
330    const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames);
331    const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses);
332    const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes);
333    const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties);
334
335    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
336        return nullptr;
337    }
338    if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
339        ALOGE("Invalid export var count!: %s", line);
340        return nullptr;
341    }
342
343    fieldAddress = new void*[varCount];
344    if (fieldAddress == nullptr) {
345        return nullptr;
346    }
347
348    fieldIsObject = new bool[varCount];
349    if (fieldIsObject == nullptr) {
350        goto error;
351    }
352
353    fieldName = new char*[varCount];
354    if (fieldName == nullptr) {
355        goto error;
356    }
357
358    for (size_t i = 0; i < varCount; ++i) {
359        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
360            goto error;
361        }
362        char *c = strrchr(line, '\n');
363        if (c) {
364            *c = '\0';
365        }
366        void* addr = dlsym(sharedObj, line);
367        if (addr == nullptr) {
368            ALOGE("Failed to find variable address for %s: %s",
369                  line, dlerror());
370            // Not a critical error if we don't find a global variable.
371        }
372        fieldAddress[i] = addr;
373        fieldIsObject[i] = false;
374        fieldName[i] = new char[strlen(line)+1];
375        strcpy(fieldName[i], line);
376    }
377
378    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
379        goto error;
380    }
381    if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
382        ALOGE("Invalid export func count!: %s", line);
383        goto error;
384    }
385
386    invokeFunctions = new InvokeFunc_t[funcCount];
387    if (invokeFunctions == nullptr) {
388        goto error;
389    }
390
391    for (size_t i = 0; i < funcCount; ++i) {
392        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
393            goto error;
394        }
395        char *c = strrchr(line, '\n');
396        if (c) {
397            *c = '\0';
398        }
399
400        invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
401        if (invokeFunctions[i] == nullptr) {
402            ALOGE("Failed to get function address for %s(): %s",
403                  line, dlerror());
404            goto error;
405        }
406    }
407
408    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
409        goto error;
410    }
411    if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
412        ALOGE("Invalid export forEach count!: %s", line);
413        goto error;
414    }
415
416    forEachFunctions = new ForEachFunc_t[forEachCount];
417    if (forEachFunctions == nullptr) {
418        goto error;
419    }
420
421    forEachSignatures = new uint32_t[forEachCount];
422    if (forEachSignatures == nullptr) {
423        goto error;
424    }
425
426    for (size_t i = 0; i < forEachCount; ++i) {
427        unsigned int tmpSig = 0;
428        char tmpName[MAXLINE];
429
430        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
431            goto error;
432        }
433        if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
434                   &tmpSig, tmpName) != 2) {
435          ALOGE("Invalid export forEach!: %s", line);
436          goto error;
437        }
438
439        // Lookup the expanded ForEach kernel.
440        strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
441        forEachSignatures[i] = tmpSig;
442        forEachFunctions[i] =
443            (ForEachFunc_t) dlsym(sharedObj, tmpName);
444        if (i != 0 && forEachFunctions[i] == nullptr &&
445            strcmp(tmpName, "root.expand")) {
446            // Ignore missing root.expand functions.
447            // root() is always specified at location 0.
448            ALOGE("Failed to find forEach function address for %s(): %s",
449                  tmpName, dlerror());
450            goto error;
451        }
452    }
453
454    // Read simple reduce kernels
455    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
456        goto error;
457    }
458    if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) {
459        ALOGE("Invalid export reduce count!: %s", line);
460        goto error;
461    }
462
463    reduceFunctions = new ReduceFunc_t[reduceCount];
464    if (reduceFunctions == nullptr) {
465        goto error;
466    }
467
468    for (size_t i = 0; i < reduceCount; ++i) {
469        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
470            goto error;
471        }
472        char *c = strrchr(line, '\n');
473        if (c) {
474            *c = '\0';
475        }
476
477        // Lookup the expanded reduce kernel.
478        strncat(line, ".expand", MAXLINE-1-strlen(line));
479
480        reduceFunctions[i] =
481            reinterpret_cast<ReduceFunc_t>(dlsym(sharedObj, line));
482        if (reduceFunctions[i] == nullptr) {
483            ALOGE("Failed to get function address for %s(): %s",
484                  line, dlerror());
485            goto error;
486        }
487    }
488
489    // Read general reduce kernels
490    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
491        goto error;
492    }
493    if (sscanf(line, EXPORT_REDUCE_NEW_STR "%zu", &reduceNewCount) != 1) {
494        ALOGE("Invalid export reduce new count!: %s", line);
495        goto error;
496    }
497
498    reduceNewDescriptions = new ReduceNewDescription[reduceNewCount];
499    if (reduceNewDescriptions == nullptr) {
500        goto error;
501    }
502
503    for (size_t i = 0; i < reduceNewCount; ++i) {
504        static const char kNoName[] = ".";
505
506        unsigned int tmpSig = 0;
507        size_t tmpSize = 0;
508        char tmpNameReduce[MAXLINE];
509        char tmpNameInitializer[MAXLINE];
510        char tmpNameAccumulator[MAXLINE];
511        char tmpNameCombiner[MAXLINE];
512        char tmpNameOutConverter[MAXLINE];
513        char tmpNameHalter[MAXLINE];
514
515        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
516            goto error;
517        }
518#define DELIMNAME " - %" MAKE_STR(MAXLINE) "s"
519        if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME,
520                   &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator,
521                   tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) {
522            ALOGE("Invalid export reduce new!: %s", line);
523            goto error;
524        }
525#undef DELIMNAME
526
527        // For now, we expect
528        // - Reduce and Accumulator names
529        // - optional Initializer, Combiner, and OutConverter name
530        // - no Halter name
531        if (!strcmp(tmpNameReduce, kNoName) ||
532            !strcmp(tmpNameAccumulator, kNoName)) {
533            ALOGE("Expected reduce and accumulator names!: %s", line);
534            goto error;
535        }
536        if (strcmp(tmpNameHalter, kNoName)) {
537            ALOGE("Did not expect halter name!: %s", line);
538            goto error;
539        }
540
541        // The current implementation does not use the signature
542        // or reduce name.
543
544        reduceNewDescriptions[i].accumSize = tmpSize;
545
546        // Process the (optional) initializer.
547        if (strcmp(tmpNameInitializer, kNoName)) {
548          // Lookup the original user-written initializer.
549          if (!(reduceNewDescriptions[i].initFunc =
550                (ReduceNewInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) {
551            ALOGE("Failed to find initializer function address for %s(): %s",
552                  tmpNameInitializer, dlerror());
553            goto error;
554          }
555        } else {
556          reduceNewDescriptions[i].initFunc = nullptr;
557        }
558
559        // Lookup the expanded accumulator.
560        strncat(tmpNameAccumulator, ".expand", MAXLINE-1-strlen(tmpNameAccumulator));
561        if (!(reduceNewDescriptions[i].accumFunc =
562              (ReduceNewAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) {
563            ALOGE("Failed to find accumulator function address for %s(): %s",
564                  tmpNameAccumulator, dlerror());
565            goto error;
566        }
567
568        // Process the (optional) combiner.
569        if (strcmp(tmpNameCombiner, kNoName)) {
570          // Lookup the original user-written combiner.
571          if (!(reduceNewDescriptions[i].combFunc =
572                (ReduceNewCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) {
573            ALOGE("Failed to find combiner function address for %s(): %s",
574                  tmpNameCombiner, dlerror());
575            goto error;
576          }
577        } else {
578          reduceNewDescriptions[i].combFunc = nullptr;
579        }
580
581        // Process the (optional) outconverter.
582        if (strcmp(tmpNameOutConverter, kNoName)) {
583          // Lookup the original user-written outconverter.
584          if (!(reduceNewDescriptions[i].outFunc =
585                (ReduceNewOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) {
586            ALOGE("Failed to find outconverter function address for %s(): %s",
587                  tmpNameOutConverter, dlerror());
588            goto error;
589          }
590        } else {
591          reduceNewDescriptions[i].outFunc = nullptr;
592        }
593    }
594
595    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
596        goto error;
597    }
598    if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
599        ALOGE("Invalid object slot count!: %s", line);
600        goto error;
601    }
602
603    for (size_t i = 0; i < objectSlotCount; ++i) {
604        uint32_t varNum = 0;
605        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
606            goto error;
607        }
608        if (sscanf(line, "%u", &varNum) != 1) {
609            ALOGE("Invalid object slot!: %s", line);
610            goto error;
611        }
612
613        if (varNum < varCount) {
614            fieldIsObject[varNum] = true;
615        }
616    }
617
618#ifndef RS_COMPATIBILITY_LIB
619    // Do not attempt to read pragmas or isThreadable flag in compat lib path.
620    // Neither is applicable for compat lib
621
622    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
623        goto error;
624    }
625
626    if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
627        ALOGE("Invalid pragma count!: %s", line);
628        goto error;
629    }
630
631    pragmaKeys = new const char*[pragmaCount];
632    if (pragmaKeys == nullptr) {
633        goto error;
634    }
635
636    pragmaValues = new const char*[pragmaCount];
637    if (pragmaValues == nullptr) {
638        goto error;
639    }
640
641    bzero(pragmaKeys, sizeof(char*) * pragmaCount);
642    bzero(pragmaValues, sizeof(char*) * pragmaCount);
643
644    for (size_t i = 0; i < pragmaCount; ++i) {
645        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
646            ALOGE("Unable to read pragma at index %zu!", i);
647            goto error;
648        }
649        char key[MAXLINE];
650        char value[MAXLINE] = ""; // initialize in case value is empty
651
652        // pragmas can just have a key and no value.  Only check to make sure
653        // that the key is not empty
654        if (sscanf(line, "%" MAKE_STR(MAXLINE) "s - %" MAKE_STR(MAXLINE) "s",
655                   key, value) == 0 ||
656            strlen(key) == 0)
657        {
658            ALOGE("Invalid pragma value!: %s", line);
659
660            goto error;
661        }
662
663        char *pKey = new char[strlen(key)+1];
664        strcpy(pKey, key);
665        pragmaKeys[i] = pKey;
666
667        char *pValue = new char[strlen(value)+1];
668        strcpy(pValue, value);
669        pragmaValues[i] = pValue;
670        //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
671    }
672
673    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
674        goto error;
675    }
676
677    char tmpFlag[4];
678    if (sscanf(line, THREADABLE_STR "%4s", tmpFlag) != 1) {
679        ALOGE("Invalid threadable flag!: %s", line);
680        goto error;
681    }
682    if (strcmp(tmpFlag, "yes") == 0) {
683        isThreadable = true;
684    } else if (strcmp(tmpFlag, "no") == 0) {
685        isThreadable = false;
686    } else {
687        ALOGE("Invalid threadable flag!: %s", tmpFlag);
688        goto error;
689    }
690
691    if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
692        if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) {
693            ALOGE("Invalid checksum flag!: %s", line);
694            goto error;
695        }
696    } else {
697        ALOGE("Missing checksum in shared obj file");
698        goto error;
699    }
700
701    if (expectedChecksum != 0 && checksum != expectedChecksum) {
702        ALOGE("Found invalid checksum.  Expected %08x, got %08x\n",
703              expectedChecksum, checksum);
704        goto error;
705    }
706
707#endif  // RS_COMPATIBILITY_LIB
708
709    // Read in information about mutable global variables provided by bcc's
710    // RSGlobalInfoPass
711    if (rsGlobalEntries) {
712        numEntries = *rsGlobalEntries;
713        if (numEntries > 0) {
714            rsAssert(rsGlobalNames);
715            rsAssert(rsGlobalAddresses);
716            rsAssert(rsGlobalSizes);
717            rsAssert(rsGlobalProperties);
718        }
719    } else {
720        ALOGD("Missing .rs.global_entries from shared object");
721    }
722
723    return new ScriptExecutable(
724        fieldAddress, fieldIsObject, fieldName, varCount,
725        invokeFunctions, funcCount,
726        forEachFunctions, forEachSignatures, forEachCount,
727        reduceFunctions, reduceCount,
728        reduceNewDescriptions, reduceNewCount,
729        pragmaKeys, pragmaValues, pragmaCount,
730        rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties,
731        numEntries, isThreadable, checksum);
732
733error:
734
735#ifndef RS_COMPATIBILITY_LIB
736
737    for (size_t idx = 0; idx < pragmaCount; ++idx) {
738        delete [] pragmaKeys[idx];
739        delete [] pragmaValues[idx];
740    }
741
742    delete[] pragmaValues;
743    delete[] pragmaKeys;
744#endif  // RS_COMPATIBILITY_LIB
745
746    delete[] reduceFunctions;
747
748    delete[] forEachSignatures;
749    delete[] forEachFunctions;
750
751    delete[] invokeFunctions;
752
753    for (size_t i = 0; i < varCount; i++) {
754        delete[] fieldName[i];
755    }
756    delete[] fieldName;
757    delete[] fieldIsObject;
758    delete[] fieldAddress;
759
760    return nullptr;
761}
762
763void* ScriptExecutable::getFieldAddress(const char* name) const {
764    // TODO: improve this by using a hash map.
765    for (size_t i = 0; i < mExportedVarCount; i++) {
766        if (strcmp(name, mFieldName[i]) == 0) {
767            return mFieldAddress[i];
768        }
769    }
770    return nullptr;
771}
772
773bool ScriptExecutable::dumpGlobalInfo() const {
774    ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames);
775    ALOGE("P   - Pointer");
776    ALOGE(" C  - Constant");
777    ALOGE("  S - Static");
778    for (int i = 0; i < mGlobalEntries; i++) {
779        ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i],
780              mGlobalNames[i]);
781        uint32_t properties = mGlobalProperties[i];
782        ALOGE("%c%c%c Type: %u",
783              isGlobalPointer(properties)  ? 'P' : ' ',
784              isGlobalConstant(properties) ? 'C' : ' ',
785              isGlobalStatic(properties)   ? 'S' : ' ',
786              getGlobalRsType(properties));
787    }
788    return true;
789}
790
791}  // namespace renderscript
792}  // namespace android
793