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("/apex/com.android.vndk") != 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        return loaded;
212     }
213     ALOGE("Unable to open shared library (%s): %s", scriptSOName.c_str(), dlerror());
214 
215 #ifdef RS_COMPATIBILITY_LIB
216     // Re-trying without absolute path.
217     // For RS support lib, the shared object may not be extracted from the apk.
218     // In order to access that, we need to load the library without specifying
219     // the absolute path.
220     std::string scriptSONameApk("librs.");
221     scriptSONameApk.append(resName);
222     scriptSONameApk.append(".so");
223     loaded = loadSOHelper(scriptSONameApk.c_str(), cacheDir, resName);
224     if (loaded != nullptr) {
225         return loaded;
226     }
227     ALOGE("Unable to open APK shared library (%s): %s", scriptSONameApk.c_str(), dlerror());
228 
229     // One final attempt to find the library in "/system/lib".
230     // We do this to allow bundled applications to use the compatibility
231     // library fallback path. Those applications don't have a private
232     // library path, so they need to install to the system directly.
233     // Note that this is really just a testing path.
234     std::string scriptSONameSystem("/system/lib/librs.");
235     scriptSONameSystem.append(resName);
236     scriptSONameSystem.append(".so");
237     loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir, resName);
238     if (loaded == nullptr) {
239         ALOGE("Unable to open system shared library (%s): %s",
240               scriptSONameSystem.c_str(), dlerror());
241     }
242 #endif
243 
244     return loaded;
245 }
246 
getRandomString(size_t len)247 std::string SharedLibraryUtils::getRandomString(size_t len) {
248     char buf[len + 1];
249     for (size_t i = 0; i < len; i++) {
250         uint32_t r = arc4random() & 0xffff;
251         r %= 62;
252         if (r < 26) {
253             // lowercase
254             buf[i] = 'a' + r;
255         } else if (r < 52) {
256             // uppercase
257             buf[i] = 'A' + (r - 26);
258         } else {
259             // Use a number
260             buf[i] = '0' + (r - 52);
261         }
262     }
263     buf[len] = '\0';
264     return std::string(buf);
265 }
266 
loadAsCopy(const char * origName,std::string newName)267 static void* loadAsCopy(const char *origName, std::string newName) {
268     void *loaded = nullptr;
269 #ifndef RS_COMPATIBILITY_LIB
270     int fd = TEMP_FAILURE_RETRY(open(origName, O_RDONLY | O_CLOEXEC));
271     if (fd == -1) {
272         ALOGE("Unable to open original file %s: %s", origName, strerror(errno));
273         return nullptr;
274     }
275 
276     android_dlextinfo extinfo;
277     memset(&extinfo, 0, sizeof(extinfo));
278     extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_FORCE_LOAD;
279     extinfo.library_fd = fd;
280 
281     loaded = android_dlopen_ext(newName.c_str(), RTLD_NOW | RTLD_LOCAL, &extinfo);
282     close(fd);
283 #else
284     int r = copyFile(newName.c_str(), origName);
285     if (r != 0) {
286         ALOGE("Could not create copy %s -> %s", origName, newName.c_str());
287         return nullptr;
288     }
289     loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
290     r = unlink(newName.c_str());
291     if (r != 0) {
292         ALOGE("Could not unlink copy %s", newName.c_str());
293     }
294 #endif  // RS_COMPATIBILITY_LIB
295     return loaded;
296 }
297 
loadSOHelper(const char * origName,const char * cacheDir,const char * resName,bool * alreadyLoaded)298 void* SharedLibraryUtils::loadSOHelper(const char *origName, const char *cacheDir,
299                                        const char *resName, bool *alreadyLoaded) {
300     // Keep track of which .so libraries have been loaded. Once a library is
301     // in the set (per-process granularity), we must instead make a copy of
302     // the original shared object (randomly named .so file) and load that one
303     // instead. If we don't do this, we end up aliasing global data between
304     // the various Script instances (which are supposed to be completely
305     // independent).
306     static std::set<std::string> LoadedLibraries;
307 
308     void *loaded = nullptr;
309 
310 #ifndef RS_COMPATIBILITY_LIB
311     // Skip everything if we don't even have the original library available.
312     if (access(origName, F_OK) != 0) {
313         return nullptr;
314     }
315 #endif  // RS_COMPATIBILITY_LIB
316 
317     // Common path is that we have not loaded this Script/library before.
318     if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
319         if (alreadyLoaded != nullptr) {
320             *alreadyLoaded = false;
321         }
322         loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
323         if (loaded) {
324             LoadedLibraries.insert(origName);
325         }
326         return loaded;
327     }
328 
329     if (alreadyLoaded != nullptr) {
330         *alreadyLoaded = true;
331     }
332 
333     std::string newName(cacheDir);
334 
335     // Append RS_CACHE_DIR only if it is not found in cacheDir
336     // In driver mode, RS_CACHE_DIR is already appended to cacheDir.
337     if (newName.find(RS_CACHE_DIR) == std::string::npos) {
338         newName.append("/");
339         newName.append(RS_CACHE_DIR);
340         newName.append("/");
341     }
342 
343     if (!ensureCacheDirExists(newName.c_str())) {
344         ALOGE("Could not verify or create cache dir: %s", cacheDir);
345         return nullptr;
346     }
347 
348     // Construct an appropriately randomized filename for the copy.
349     newName.append("librs.");
350     newName.append(resName);
351     newName.append("#");
352     newName.append(getRandomString(6).c_str());  // 62^6 potential filename variants.
353     newName.append(".so");
354 
355     loaded = loadAsCopy(origName, newName);
356 
357     if (loaded) {
358         LoadedLibraries.insert(newName.c_str());
359     }
360 
361     return loaded;
362 }
363 
364 // MAXLINESTR must be compatible with operator '#' in C macro.
365 #define MAXLINESTR 499
366 // MAXLINE must be (MAXLINESTR + 1), representing the size of a C string
367 // containing MAXLINESTR non-null chars plus a null.
368 #define MAXLINE (MAXLINESTR + 1)
369 #define MAKE_STR_HELPER(S) #S
370 #define MAKE_STR(S) MAKE_STR_HELPER(S)
371 #define EXPORT_VAR_STR "exportVarCount: "
372 #define EXPORT_FUNC_STR "exportFuncCount: "
373 #define EXPORT_FOREACH_STR "exportForEachCount: "
374 #define EXPORT_REDUCE_STR "exportReduceCount: "
375 #define OBJECT_SLOT_STR "objectSlotCount: "
376 #define PRAGMA_STR "pragmaCount: "
377 #define THREADABLE_STR "isThreadable: "
378 #define CHECKSUM_STR "buildChecksum: "
379 #define VERSIONINFO_STR "versionInfo: "
380 
381 // Copy up to a newline or size chars from str -> s, updating str
382 // Returns s when successful and nullptr when '\0' is finally reached.
strgets(char * s,int size,const char ** ppstr)383 static char* strgets(char *s, int size, const char **ppstr) {
384     if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
385         return nullptr;
386     }
387 
388     int i;
389     for (i = 0; i < (size - 1); i++) {
390         s[i] = **ppstr;
391         (*ppstr)++;
392         if (s[i] == '\0') {
393             return s;
394         } else if (s[i] == '\n') {
395             s[i+1] = '\0';
396             return s;
397         }
398     }
399 
400     // size has been exceeded.
401     s[i] = '\0';
402 
403     return s;
404 }
405 
406 // Creates a duplicate of a string. The new string is as small as possible,
407 // only including characters up to and including the first null-terminator;
408 // otherwise, the new string will be the same size as the input string.
409 // The code that calls duplicateString is responsible for the new string's
410 // lifetime, and is responsible for freeing it when it is no longer needed.
duplicateString(const char * str,size_t length)411 static char* duplicateString(const char *str, size_t length) {
412     const size_t newLen = strnlen(str, length-1) + 1;
413     char *newStr = new char[newLen];
414     strlcpy(newStr, str, newLen);
415     return newStr;
416 }
417 
createFromSharedObject(void * sharedObj,uint32_t expectedChecksum)418 ScriptExecutable* ScriptExecutable::createFromSharedObject(
419     void* sharedObj, uint32_t expectedChecksum) {
420     char line[MAXLINE];
421 
422     size_t varCount = 0;
423     size_t funcCount = 0;
424     size_t forEachCount = 0;
425     size_t reduceCount = 0;
426     size_t objectSlotCount = 0;
427     size_t pragmaCount = 0;
428     bool isThreadable = true;
429 
430     void** fieldAddress = nullptr;
431     bool* fieldIsObject = nullptr;
432     char** fieldName = nullptr;
433     InvokeFunc_t* invokeFunctions = nullptr;
434     ForEachFunc_t* forEachFunctions = nullptr;
435     uint32_t* forEachSignatures = nullptr;
436     ReduceDescription* reduceDescriptions = nullptr;
437     const char ** pragmaKeys = nullptr;
438     const char ** pragmaValues = nullptr;
439     uint32_t checksum = 0;
440 
441     const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo);
442     int numEntries = 0;
443     const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries);
444     const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames);
445     const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses);
446     const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes);
447     const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties);
448 
449     if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
450         return nullptr;
451     }
452     if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
453         ALOGE("Invalid export var count!: %s", line);
454         return nullptr;
455     }
456 
457     fieldAddress = new void*[varCount];
458     if (fieldAddress == nullptr) {
459         return nullptr;
460     }
461 
462     fieldIsObject = new bool[varCount];
463     if (fieldIsObject == nullptr) {
464         goto error;
465     }
466 
467     fieldName = new char*[varCount];
468     if (fieldName == nullptr) {
469         goto error;
470     }
471 
472     for (size_t i = 0; i < varCount; ++i) {
473         if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
474             goto error;
475         }
476         char *c = strrchr(line, '\n');
477         if (c) {
478             *c = '\0';
479         }
480         void* addr = dlsym(sharedObj, line);
481         if (addr == nullptr) {
482             ALOGE("Failed to find variable address for %s: %s",
483                   line, dlerror());
484             // Not a critical error if we don't find a global variable.
485         }
486         fieldAddress[i] = addr;
487         fieldIsObject[i] = false;
488         fieldName[i] = duplicateString(line, sizeof(line));
489     }
490 
491     if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
492         goto error;
493     }
494     if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
495         ALOGE("Invalid export func count!: %s", line);
496         goto error;
497     }
498 
499     invokeFunctions = new InvokeFunc_t[funcCount];
500     if (invokeFunctions == nullptr) {
501         goto error;
502     }
503 
504     for (size_t i = 0; i < funcCount; ++i) {
505         if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
506             goto error;
507         }
508         char *c = strrchr(line, '\n');
509         if (c) {
510             *c = '\0';
511         }
512 
513         invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
514         if (invokeFunctions[i] == nullptr) {
515             ALOGE("Failed to get function address for %s(): %s",
516                   line, dlerror());
517             goto error;
518         }
519     }
520 
521     if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
522         goto error;
523     }
524     if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
525         ALOGE("Invalid export forEach count!: %s", line);
526         goto error;
527     }
528 
529     forEachFunctions = new ForEachFunc_t[forEachCount];
530     if (forEachFunctions == nullptr) {
531         goto error;
532     }
533 
534     forEachSignatures = new uint32_t[forEachCount];
535     if (forEachSignatures == nullptr) {
536         goto error;
537     }
538 
539     for (size_t i = 0; i < forEachCount; ++i) {
540         unsigned int tmpSig = 0;
541         char tmpName[MAXLINE];
542 
543         if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
544             goto error;
545         }
546         if (sscanf(line, "%u - %" MAKE_STR(MAXLINESTR) "s",
547                    &tmpSig, tmpName) != 2) {
548           ALOGE("Invalid export forEach!: %s", line);
549           goto error;
550         }
551 
552         // Lookup the expanded ForEach kernel.
553         strncat(tmpName, ".expand", MAXLINESTR-strlen(tmpName));
554         forEachSignatures[i] = tmpSig;
555         forEachFunctions[i] =
556             (ForEachFunc_t) dlsym(sharedObj, tmpName);
557         if (i != 0 && forEachFunctions[i] == nullptr &&
558             strcmp(tmpName, "root.expand")) {
559             // Ignore missing root.expand functions.
560             // root() is always specified at location 0.
561             ALOGE("Failed to find forEach function address for %s(): %s",
562                   tmpName, dlerror());
563             goto error;
564         }
565     }
566 
567     // Read general reduce kernels
568     if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
569         goto error;
570     }
571     if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) {
572         ALOGE("Invalid export reduce new count!: %s", line);
573         goto error;
574     }
575 
576     reduceDescriptions = new ReduceDescription[reduceCount];
577     if (reduceDescriptions == nullptr) {
578         goto error;
579     }
580 
581     for (size_t i = 0; i < reduceCount; ++i) {
582         static const char kNoName[] = ".";
583 
584         unsigned int tmpSig = 0;
585         size_t tmpSize = 0;
586         char tmpNameReduce[MAXLINE];
587         char tmpNameInitializer[MAXLINE];
588         char tmpNameAccumulator[MAXLINE];
589         char tmpNameCombiner[MAXLINE];
590         char tmpNameOutConverter[MAXLINE];
591         char tmpNameHalter[MAXLINE];
592 
593         if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
594             goto error;
595         }
596 #define DELIMNAME " - %" MAKE_STR(MAXLINESTR) "s"
597         if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME,
598                    &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator,
599                    tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) {
600             ALOGE("Invalid export reduce new!: %s", line);
601             goto error;
602         }
603 #undef DELIMNAME
604 
605         // For now, we expect
606         // - Reduce and Accumulator names
607         // - optional Initializer, Combiner, and OutConverter name
608         // - no Halter name
609         if (!strcmp(tmpNameReduce, kNoName) ||
610             !strcmp(tmpNameAccumulator, kNoName)) {
611             ALOGE("Expected reduce and accumulator names!: %s", line);
612             goto error;
613         }
614         if (strcmp(tmpNameHalter, kNoName)) {
615             ALOGE("Did not expect halter name!: %s", line);
616             goto error;
617         }
618 
619         // The current implementation does not use the signature
620         // or reduce name.
621 
622         reduceDescriptions[i].accumSize = tmpSize;
623 
624         // Process the (optional) initializer.
625         if (strcmp(tmpNameInitializer, kNoName)) {
626           // Lookup the original user-written initializer.
627           if (!(reduceDescriptions[i].initFunc =
628                 (ReduceInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) {
629             ALOGE("Failed to find initializer function address for %s(): %s",
630                   tmpNameInitializer, dlerror());
631             goto error;
632           }
633         } else {
634           reduceDescriptions[i].initFunc = nullptr;
635         }
636 
637         // Lookup the expanded accumulator.
638         strncat(tmpNameAccumulator, ".expand", MAXLINESTR-strlen(tmpNameAccumulator));
639         if (!(reduceDescriptions[i].accumFunc =
640               (ReduceAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) {
641             ALOGE("Failed to find accumulator function address for %s(): %s",
642                   tmpNameAccumulator, dlerror());
643             goto error;
644         }
645 
646         // Process the (optional) combiner.
647         if (strcmp(tmpNameCombiner, kNoName)) {
648           // Lookup the original user-written combiner.
649           if (!(reduceDescriptions[i].combFunc =
650                 (ReduceCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) {
651             ALOGE("Failed to find combiner function address for %s(): %s",
652                   tmpNameCombiner, dlerror());
653             goto error;
654           }
655         } else {
656           reduceDescriptions[i].combFunc = nullptr;
657         }
658 
659         // Process the (optional) outconverter.
660         if (strcmp(tmpNameOutConverter, kNoName)) {
661           // Lookup the original user-written outconverter.
662           if (!(reduceDescriptions[i].outFunc =
663                 (ReduceOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) {
664             ALOGE("Failed to find outconverter function address for %s(): %s",
665                   tmpNameOutConverter, dlerror());
666             goto error;
667           }
668         } else {
669           reduceDescriptions[i].outFunc = nullptr;
670         }
671     }
672 
673     if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
674         goto error;
675     }
676     if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
677         ALOGE("Invalid object slot count!: %s", line);
678         goto error;
679     }
680 
681     for (size_t i = 0; i < objectSlotCount; ++i) {
682         uint32_t varNum = 0;
683         if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
684             goto error;
685         }
686         if (sscanf(line, "%u", &varNum) != 1) {
687             ALOGE("Invalid object slot!: %s", line);
688             goto error;
689         }
690 
691         if (varNum < varCount) {
692             fieldIsObject[varNum] = true;
693         }
694     }
695 
696 #ifndef RS_COMPATIBILITY_LIB
697     // Do not attempt to read pragmas or isThreadable flag in compat lib path.
698     // Neither is applicable for compat lib
699 
700     if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
701         goto error;
702     }
703 
704     if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
705         ALOGE("Invalid pragma count!: %s", line);
706         goto error;
707     }
708 
709     pragmaKeys = new const char*[pragmaCount];
710     if (pragmaKeys == nullptr) {
711         goto error;
712     }
713 
714     pragmaValues = new const char*[pragmaCount];
715     if (pragmaValues == nullptr) {
716         goto error;
717     }
718 
719     bzero(pragmaKeys, sizeof(char*) * pragmaCount);
720     bzero(pragmaValues, sizeof(char*) * pragmaCount);
721 
722     for (size_t i = 0; i < pragmaCount; ++i) {
723         if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
724             ALOGE("Unable to read pragma at index %zu!", i);
725             goto error;
726         }
727         char key[MAXLINE];
728         char value[MAXLINE] = ""; // initialize in case value is empty
729 
730         // pragmas can just have a key and no value.  Only check to make sure
731         // that the key is not empty
732         if (sscanf(line, "%" MAKE_STR(MAXLINESTR) "s - %" MAKE_STR(MAXLINESTR) "s",
733                    key, value) == 0 ||
734             strlen(key) == 0)
735         {
736             ALOGE("Invalid pragma value!: %s", line);
737 
738             goto error;
739         }
740 
741         pragmaKeys[i] = duplicateString(key, sizeof(key));
742         pragmaValues[i] = duplicateString(value, sizeof(value));
743         //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
744     }
745 
746     if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
747         goto error;
748     }
749 
750     char tmpFlag[4];
751     if (sscanf(line, THREADABLE_STR "%3s", tmpFlag) != 1) {
752         ALOGE("Invalid threadable flag!: %s", line);
753         goto error;
754     }
755     if (strcmp(tmpFlag, "yes") == 0) {
756         isThreadable = true;
757     } else if (strcmp(tmpFlag, "no") == 0) {
758         isThreadable = false;
759     } else {
760         ALOGE("Invalid threadable flag!: %s", tmpFlag);
761         goto error;
762     }
763 
764     if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
765         if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) {
766             ALOGE("Invalid checksum flag!: %s", line);
767             goto error;
768         }
769     } else {
770         ALOGE("Missing checksum in shared obj file");
771         goto error;
772     }
773 
774     if (expectedChecksum != 0 && checksum != expectedChecksum) {
775         ALOGE("Found invalid checksum.  Expected %08x, got %08x\n",
776               expectedChecksum, checksum);
777         goto error;
778     }
779 
780     {
781       // Parse the version info string, but ignore its contents as it's only
782       // used by the debugger
783       size_t nLines = 0;
784       if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
785         if (sscanf(line, VERSIONINFO_STR "%zu", &nLines) != 1) {
786           ALOGE("invalid versionInfo count");
787           goto error;
788         } else {
789           // skip the versionInfo packet as libRs doesn't use it
790           while (nLines) {
791             --nLines;
792             if (strgets(line, MAXLINE, &rsInfo) == nullptr)
793               goto error;
794           }
795         }
796       } else {
797         ALOGE(".rs.info is missing versionInfo section");
798       }
799     }
800 
801 #endif  // RS_COMPATIBILITY_LIB
802 
803     // Read in information about mutable global variables provided by bcc's
804     // RSGlobalInfoPass
805     if (rsGlobalEntries) {
806         numEntries = *rsGlobalEntries;
807         if (numEntries > 0) {
808             rsAssert(rsGlobalNames);
809             rsAssert(rsGlobalAddresses);
810             rsAssert(rsGlobalSizes);
811             rsAssert(rsGlobalProperties);
812         }
813     }
814 
815     return new ScriptExecutable(
816         fieldAddress, fieldIsObject, fieldName, varCount,
817         invokeFunctions, funcCount,
818         forEachFunctions, forEachSignatures, forEachCount,
819         reduceDescriptions, reduceCount,
820         pragmaKeys, pragmaValues, pragmaCount,
821         rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties,
822         numEntries, isThreadable, checksum);
823 
824 error:
825 
826 #ifndef RS_COMPATIBILITY_LIB
827 
828     if (pragmaKeys) {
829         for (size_t idx = 0; idx < pragmaCount; ++idx) {
830             delete [] pragmaKeys[idx];
831         }
832     }
833 
834     if (pragmaValues) {
835         for (size_t idx = 0; idx < pragmaCount; ++idx) {
836             delete [] pragmaValues[idx];
837         }
838     }
839 
840     delete[] pragmaValues;
841     delete[] pragmaKeys;
842 #endif  // RS_COMPATIBILITY_LIB
843 
844     delete[] reduceDescriptions;
845 
846     delete[] forEachSignatures;
847     delete[] forEachFunctions;
848 
849     delete[] invokeFunctions;
850 
851     for (size_t i = 0; i < varCount; i++) {
852         delete[] fieldName[i];
853     }
854     delete[] fieldName;
855     delete[] fieldIsObject;
856     delete[] fieldAddress;
857 
858     return nullptr;
859 }
860 
getFieldAddress(const char * name) const861 void* ScriptExecutable::getFieldAddress(const char* name) const {
862     // TODO: improve this by using a hash map.
863     for (size_t i = 0; i < mExportedVarCount; i++) {
864         if (strcmp(name, mFieldName[i]) == 0) {
865             return mFieldAddress[i];
866         }
867     }
868     return nullptr;
869 }
870 
dumpGlobalInfo() const871 bool ScriptExecutable::dumpGlobalInfo() const {
872     ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames);
873     ALOGE("P   - Pointer");
874     ALOGE(" C  - Constant");
875     ALOGE("  S - Static");
876     for (int i = 0; i < mGlobalEntries; i++) {
877         ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i],
878               mGlobalNames[i]);
879         uint32_t properties = mGlobalProperties[i];
880         ALOGE("%c%c%c Type: %u",
881               isGlobalPointer(properties)  ? 'P' : ' ',
882               isGlobalConstant(properties) ? 'C' : ' ',
883               isGlobalStatic(properties)   ? 'S' : ' ',
884               getGlobalRsType(properties));
885     }
886     return true;
887 }
888 
889 }  // namespace renderscript
890 }  // namespace android
891