rsCpuExecutable.cpp 28 KB

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