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