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