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