Moved class ScriptExecutable to its own module

b/19283946

This move also included the related class SharedObjectUtils.

Change-Id: Iefd587b659c4ad99340c330955b41cd92df45563
diff --git a/cpu_ref/rsCpuScript.cpp b/cpu_ref/rsCpuScript.cpp
index 1c7fdac..af8b640 100644
--- a/cpu_ref/rsCpuScript.cpp
+++ b/cpu_ref/rsCpuScript.cpp
@@ -16,6 +16,7 @@
 
 #include "rsCpuCore.h"
 #include "rsCpuScript.h"
+#include "rsCpuExecutable.h"
 
 #ifdef RS_COMPATIBILITY_LIB
     #include <stdio.h>
@@ -41,7 +42,6 @@
 #include <dlfcn.h>
 #include <stdlib.h>
 #include <string.h>
-#include <fstream>
 #include <iostream>
 
 #ifdef __LP64__
@@ -51,90 +51,6 @@
 #endif
 
 namespace {
-
-// Create a len length string containing random characters from [A-Za-z0-9].
-static std::string getRandomString(size_t len) {
-    char buf[len + 1];
-    for (size_t i = 0; i < len; i++) {
-        uint32_t r = arc4random() & 0xffff;
-        r %= 62;
-        if (r < 26) {
-            // lowercase
-            buf[i] = 'a' + r;
-        } else if (r < 52) {
-            // uppercase
-            buf[i] = 'A' + (r - 26);
-        } else {
-            // Use a number
-            buf[i] = '0' + (r - 52);
-        }
-    }
-    buf[len] = '\0';
-    return std::string(buf);
-}
-
-// Check if a path exists and attempt to create it if it doesn't.
-static bool ensureCacheDirExists(const char *path) {
-    if (access(path, R_OK | W_OK | X_OK) == 0) {
-        // Done if we can rwx the directory
-        return true;
-    }
-    if (mkdir(path, 0700) == 0) {
-        return true;
-    }
-    return false;
-}
-
-// Copy the file named \p srcFile to \p dstFile.
-// Return 0 on success and -1 if anything wasn't copied.
-static int copyFile(const char *dstFile, const char *srcFile) {
-    std::ifstream srcStream(srcFile);
-    if (!srcStream) {
-        ALOGE("Could not verify or read source file: %s", srcFile);
-        return -1;
-    }
-    std::ofstream dstStream(dstFile);
-    if (!dstStream) {
-        ALOGE("Could not verify or write destination file: %s", dstFile);
-        return -1;
-    }
-    dstStream << srcStream.rdbuf();
-    if (!dstStream) {
-        ALOGE("Could not write destination file: %s", dstFile);
-        return -1;
-    }
-
-    srcStream.close();
-    dstStream.close();
-
-    return 0;
-}
-
-static std::string findSharedObjectName(const char *cacheDir,
-                                        const char *resName) {
-#ifndef RS_SERVER
-    std::string scriptSOName(cacheDir);
-#if defined(RS_COMPATIBILITY_LIB) && !defined(__LP64__)
-    size_t cutPos = scriptSOName.rfind("cache");
-    if (cutPos != std::string::npos) {
-        scriptSOName.erase(cutPos);
-    } else {
-        ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
-    }
-    scriptSOName.append("/lib/librs.");
-#else
-    scriptSOName.append("/librs.");
-#endif // RS_COMPATIBILITY_LIB
-
-#else
-    std::string scriptSOName("lib");
-#endif // RS_SERVER
-    scriptSOName.append(resName);
-    scriptSOName.append(".so");
-
-    return scriptSOName;
-}
-
 #ifndef RS_COMPATIBILITY_LIB
 
 static bool is_force_recompile() {
@@ -256,228 +172,12 @@
     }
 }
 
-std::string getCommandLine(int argc, const char* const* argv) {
-    std::string s;
-    for (int i = 0; i < argc; i++) {
-        if (i > 0) {
-            s += ' ';
-        }
-        s += argv[i];
-    }
-    return s;
-}
-
 #endif  // !defined(RS_COMPATIBILITY_LIB)
 }  // namespace
 
 namespace android {
 namespace renderscript {
 
-const char* SharedLibraryUtils::LD_EXE_PATH = "/system/bin/ld.mc";
-const char* SharedLibraryUtils::RS_CACHE_DIR = "com.android.renderscript.cache";
-
-#ifndef RS_COMPATIBILITY_LIB
-
-bool SharedLibraryUtils::createSharedLibrary(const char *cacheDir, const char *resName) {
-    std::string sharedLibName = findSharedObjectName(cacheDir, resName);
-    std::string objFileName = cacheDir;
-    objFileName.append("/");
-    objFileName.append(resName);
-    objFileName.append(".o");
-
-    const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so";
-    std::vector<const char *> args = {
-        LD_EXE_PATH,
-        "-shared",
-        "-nostdlib",
-        compiler_rt,
-        "-mtriple", DEFAULT_TARGET_TRIPLE_STRING,
-        "-L", SYSLIBPATH,
-        "-lRSDriver", "-lm", "-lc",
-        objFileName.c_str(),
-        "-o", sharedLibName.c_str(),
-        nullptr
-    };
-
-    std::string cmdLineStr = getCommandLine(args.size()-1, args.data());
-
-    pid_t pid = fork();
-
-    switch (pid) {
-    case -1: {  // Error occurred (we attempt no recovery)
-        ALOGE("Couldn't fork for linker (%s) execution", LD_EXE_PATH);
-        return false;
-    }
-    case 0: {  // Child process
-        ALOGV("Invoking ld.mc with args '%s'", cmdLineStr.c_str());
-        execv(LD_EXE_PATH, (char* const*) args.data());
-
-        ALOGE("execv() failed: %s", strerror(errno));
-        abort();
-        return false;
-    }
-    default: {  // Parent process (actual driver)
-        // Wait on child process to finish compiling the source.
-        int status = 0;
-        pid_t w = waitpid(pid, &status, 0);
-        if (w == -1) {
-            ALOGE("Could not wait for linker (%s)", LD_EXE_PATH);
-            return false;
-        }
-
-        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-            return true;
-        }
-
-        ALOGE("Linker (%s) terminated unexpectedly", LD_EXE_PATH);
-        return false;
-    }
-    }
-}
-
-#endif  // RS_COMPATIBILITY_LIB
-
-
-void* SharedLibraryUtils::loadSharedLibrary(const char *cacheDir, const char *resName, const char *nativeLibDir) {
-    void *loaded = nullptr;
-
-#if defined(RS_COMPATIBILITY_LIB) && defined(__LP64__)
-    std::string scriptSOName = findSharedObjectName(nativeLibDir, resName);
-#else
-    std::string scriptSOName = findSharedObjectName(cacheDir, resName);
-#endif
-
-    // We should check if we can load the library from the standard app
-    // location for shared libraries first.
-    loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName);
-
-    if (loaded == nullptr) {
-        ALOGE("Unable to open shared library (%s): %s",
-              scriptSOName.c_str(), dlerror());
-
-#ifdef RS_COMPATIBILITY_LIB
-        // One final attempt to find the library in "/system/lib".
-        // We do this to allow bundled applications to use the compatibility
-        // library fallback path. Those applications don't have a private
-        // library path, so they need to install to the system directly.
-        // Note that this is really just a testing path.
-        std::string scriptSONameSystem("/system/lib/librs.");
-        scriptSONameSystem.append(resName);
-        scriptSONameSystem.append(".so");
-        loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
-                              resName);
-        if (loaded == nullptr) {
-            ALOGE("Unable to open system shared library (%s): %s",
-                  scriptSONameSystem.c_str(), dlerror());
-        }
-#endif
-    }
-
-    return loaded;
-}
-
-void* SharedLibraryUtils::loadSOHelper(const char *origName, const char *cacheDir,
-                                       const char *resName) {
-    // Keep track of which .so libraries have been loaded. Once a library is
-    // in the set (per-process granularity), we must instead make a copy of
-    // the original shared object (randomly named .so file) and load that one
-    // instead. If we don't do this, we end up aliasing global data between
-    // the various Script instances (which are supposed to be completely
-    // independent).
-    static std::set<std::string> LoadedLibraries;
-
-    void *loaded = nullptr;
-
-    // Skip everything if we don't even have the original library available.
-    if (access(origName, F_OK) != 0) {
-        return nullptr;
-    }
-
-    // Common path is that we have not loaded this Script/library before.
-    if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
-        loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
-        if (loaded) {
-            LoadedLibraries.insert(origName);
-        }
-        return loaded;
-    }
-
-    std::string newName(cacheDir);
-
-    // Append RS_CACHE_DIR only if it is not found in cacheDir
-    // In driver mode, RS_CACHE_DIR is already appended to cacheDir.
-    if (newName.find(RS_CACHE_DIR) == std::string::npos) {
-        newName.append("/");
-        newName.append(RS_CACHE_DIR);
-        newName.append("/");
-    }
-
-    if (!ensureCacheDirExists(newName.c_str())) {
-        ALOGE("Could not verify or create cache dir: %s", cacheDir);
-        return nullptr;
-    }
-
-    // Construct an appropriately randomized filename for the copy.
-    newName.append("librs.");
-    newName.append(resName);
-    newName.append("#");
-    newName.append(getRandomString(6));  // 62^6 potential filename variants.
-    newName.append(".so");
-
-    int r = copyFile(newName.c_str(), origName);
-    if (r != 0) {
-        ALOGE("Could not create copy %s -> %s", origName, newName.c_str());
-        return nullptr;
-    }
-    loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
-    r = unlink(newName.c_str());
-    if (r != 0) {
-        ALOGE("Could not unlink copy %s", newName.c_str());
-    }
-    if (loaded) {
-        LoadedLibraries.insert(newName.c_str());
-    }
-
-    return loaded;
-}
-
-const char* RsdCpuScriptImpl::BCC_EXE_PATH = "/system/bin/bcc";
-
-#define MAXLINE 500
-#define MAKE_STR_HELPER(S) #S
-#define MAKE_STR(S) MAKE_STR_HELPER(S)
-#define EXPORT_VAR_STR "exportVarCount: "
-#define EXPORT_FUNC_STR "exportFuncCount: "
-#define EXPORT_FOREACH_STR "exportForEachCount: "
-#define OBJECT_SLOT_STR "objectSlotCount: "
-#define PRAGMA_STR "pragmaCount: "
-#define THREADABLE_STR "isThreadable: "
-
-// Copy up to a newline or size chars from str -> s, updating str
-// Returns s when successful and nullptr when '\0' is finally reached.
-static char* strgets(char *s, int size, const char **ppstr) {
-    if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
-        return nullptr;
-    }
-
-    int i;
-    for (i = 0; i < (size - 1); i++) {
-        s[i] = **ppstr;
-        (*ppstr)++;
-        if (s[i] == '\0') {
-            return s;
-        } else if (s[i] == '\n') {
-            s[i+1] = '\0';
-            return s;
-        }
-    }
-
-    // size has been exceeded.
-    s[i] = '\0';
-
-    return s;
-}
-
 RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
     mCtx = ctx;
     mScript = s;
@@ -537,265 +237,6 @@
     return true;
 }
 
-ScriptExecutable* ScriptExecutable::createFromSharedObject(
-    Context* RSContext, void* sharedObj) {
-    char line[MAXLINE];
-
-    size_t varCount = 0;
-    size_t funcCount = 0;
-    size_t forEachCount = 0;
-    size_t objectSlotCount = 0;
-    size_t pragmaCount = 0;
-    bool isThreadable = true;
-
-    void** fieldAddress = nullptr;
-    bool* fieldIsObject = nullptr;
-    InvokeFunc_t* invokeFunctions = nullptr;
-    ForEachFunc_t* forEachFunctions = nullptr;
-    uint32_t* forEachSignatures = nullptr;
-    const char ** pragmaKeys = nullptr;
-    const char ** pragmaValues = nullptr;
-
-    const char *rsInfo = (const char *) dlsym(sharedObj, ".rs.info");
-
-    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-        return nullptr;
-    }
-    if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
-        ALOGE("Invalid export var count!: %s", line);
-        return nullptr;
-    }
-
-    fieldAddress = new void*[varCount];
-    if (fieldAddress == nullptr) {
-        return nullptr;
-    }
-
-    fieldIsObject = new bool[varCount];
-    if (fieldIsObject == nullptr) {
-        goto error;
-    }
-
-    for (size_t i = 0; i < varCount; ++i) {
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            goto error;
-        }
-        char *c = strrchr(line, '\n');
-        if (c) {
-            *c = '\0';
-        }
-        void* addr = dlsym(sharedObj, line);
-        if (addr == nullptr) {
-            ALOGE("Failed to find variable address for %s: %s",
-                  line, dlerror());
-            // Not a critical error if we don't find a global variable.
-        }
-        fieldAddress[i] = addr;
-        fieldIsObject[i] = false;
-    }
-
-    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-        goto error;
-    }
-    if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
-        ALOGE("Invalid export func count!: %s", line);
-        goto error;
-    }
-
-    invokeFunctions = new InvokeFunc_t[funcCount];
-    if (invokeFunctions == nullptr) {
-        goto error;
-    }
-
-    for (size_t i = 0; i < funcCount; ++i) {
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            goto error;
-        }
-        char *c = strrchr(line, '\n');
-        if (c) {
-            *c = '\0';
-        }
-
-        invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
-        if (invokeFunctions[i] == nullptr) {
-            ALOGE("Failed to get function address for %s(): %s",
-                  line, dlerror());
-            goto error;
-        }
-    }
-
-    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-        goto error;
-    }
-    if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
-        ALOGE("Invalid export forEach count!: %s", line);
-        goto error;
-    }
-
-    forEachFunctions = new ForEachFunc_t[forEachCount];
-    if (forEachFunctions == nullptr) {
-        goto error;
-    }
-
-    forEachSignatures = new uint32_t[forEachCount];
-    if (forEachSignatures == nullptr) {
-        goto error;
-    }
-
-    for (size_t i = 0; i < forEachCount; ++i) {
-        unsigned int tmpSig = 0;
-        char tmpName[MAXLINE];
-
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            goto error;
-        }
-        if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
-                   &tmpSig, tmpName) != 2) {
-          ALOGE("Invalid export forEach!: %s", line);
-          goto error;
-        }
-
-        // Lookup the expanded ForEach kernel.
-        strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
-        forEachSignatures[i] = tmpSig;
-        forEachFunctions[i] =
-            (ForEachFunc_t) dlsym(sharedObj, tmpName);
-        if (i != 0 && forEachFunctions[i] == nullptr) {
-            // Ignore missing root.expand functions.
-            // root() is always specified at location 0.
-            ALOGE("Failed to find forEach function address for %s: %s",
-                  tmpName, dlerror());
-            goto error;
-        }
-    }
-
-    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-        goto error;
-    }
-    if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
-        ALOGE("Invalid object slot count!: %s", line);
-        goto error;
-    }
-
-    for (size_t i = 0; i < objectSlotCount; ++i) {
-        uint32_t varNum = 0;
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            goto error;
-        }
-        if (sscanf(line, "%u", &varNum) != 1) {
-            ALOGE("Invalid object slot!: %s", line);
-            goto error;
-        }
-
-        if (varNum < varCount) {
-            fieldIsObject[varNum] = true;
-        }
-    }
-
-#ifndef RS_COMPATIBILITY_LIB
-    // Do not attempt to read pragmas or isThreadable flag in compat lib path.
-    // Neither is applicable for compat lib
-
-    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-        goto error;
-    }
-
-    if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
-        ALOGE("Invalid pragma count!: %s", line);
-        goto error;
-    }
-
-    pragmaKeys = new const char*[pragmaCount];
-    if (pragmaKeys == nullptr) {
-        goto error;
-    }
-
-    pragmaValues = new const char*[pragmaCount];
-    if (pragmaValues == nullptr) {
-        goto error;
-    }
-
-    bzero(pragmaKeys, sizeof(char*) * pragmaCount);
-    bzero(pragmaValues, sizeof(char*) * pragmaCount);
-
-    for (size_t i = 0; i < pragmaCount; ++i) {
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            ALOGE("Unable to read pragma at index %zu!", i);
-            goto error;
-        }
-
-        char key[MAXLINE];
-        char value[MAXLINE] = ""; // initialize in case value is empty
-
-        // pragmas can just have a key and no value.  Only check to make sure
-        // that the key is not empty
-        if (sscanf(line, "%" MAKE_STR(MAXLINE) "s - %" MAKE_STR(MAXLINE) "s",
-                   key, value) == 0 ||
-            strlen(key) == 0)
-        {
-            ALOGE("Invalid pragma value!: %s", line);
-
-            goto error;
-        }
-
-        char *pKey = new char[strlen(key)+1];
-        strcpy(pKey, key);
-        pragmaKeys[i] = pKey;
-
-        char *pValue = new char[strlen(value)+1];
-        strcpy(pValue, value);
-        pragmaValues[i] = pValue;
-        //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
-    }
-
-    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-        goto error;
-    }
-
-    char tmpFlag[4];
-    if (sscanf(line, THREADABLE_STR "%4s", tmpFlag) != 1) {
-        ALOGE("Invalid threadable flag!: %s", line);
-        goto error;
-    }
-    if (strcmp(tmpFlag, "yes") == 0) {
-        isThreadable = true;
-    } else if (strcmp(tmpFlag, "no") == 0) {
-        isThreadable = false;
-    } else {
-        ALOGE("Invalid threadable flag!: %s", tmpFlag);
-        goto error;
-    }
-
-#endif  // RS_COMPATIBILITY_LIB
-
-    return new ScriptExecutable(
-        RSContext, fieldAddress, fieldIsObject, varCount,
-        invokeFunctions, funcCount,
-        forEachFunctions, forEachSignatures, forEachCount,
-        pragmaKeys, pragmaValues, pragmaCount,
-        isThreadable);
-
-error:
-
-#ifndef RS_COMPATIBILITY_LIB
-    for (size_t idx = 0; idx < pragmaCount; ++idx) {
-        delete [] pragmaKeys[idx];
-        delete [] pragmaValues[idx];
-    }
-
-    delete[] pragmaValues;
-    delete[] pragmaKeys;
-#endif  // RS_COMPATIBILITY_LIB
-
-    delete[] forEachSignatures;
-    delete[] forEachFunctions;
-    delete[] invokeFunctions;
-    delete[] fieldIsObject;
-    delete[] fieldAddress;
-
-    return nullptr;
-}
-
 bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
                             uint8_t const *bitcode, size_t bitcodeSize,
                             uint32_t flags, char const *bccPluginName) {
@@ -846,8 +287,9 @@
     setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib,
                         useRSDebugContext, bccPluginName);
     // The last argument of compileArguments ia a nullptr, so remove 1 from the size.
-    std::string compileCommandLine =
-                getCommandLine(compileArguments.size() - 1, compileArguments.data());
+    std::unique_ptr<const char> joined(
+        rsuJoinStrings(compileArguments.size() - 1, compileArguments.data()));
+    std::string compileCommandLine (joined.get());
 
     if (!is_force_recompile() && !useRSDebugContext) {
         mScriptSO = SharedLibraryUtils::loadSharedLibrary(cacheDir, resName);