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.
ensureCacheDirExists(const char * path)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.
copyFile(const char * dstFile,const char * srcFile)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 
findSharedObjectName(const char * cacheDir,const char * resName)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 
createSharedLibrary(const char * driverName,const char * cacheDir,const char * resName)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 
loadSharedLibrary(const char * cacheDir,const char * resName,const char * nativeLibDir,bool * alreadyLoaded)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 
getRandomString(size_t len)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 
loadSOHelper(const char * origName,const char * cacheDir,const char * resName,bool * alreadyLoaded)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.
strgets(char * s,int size,const char ** ppstr)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 
createFromSharedObject(void * sharedObj,uint32_t expectedChecksum)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 
getFieldAddress(const char * name) const724 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 
dumpGlobalInfo() const734 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