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