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