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