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