|  | /* | 
|  | * Copyright 2007 The Android Open Source Project | 
|  | * | 
|  | * Initialize the intercepts. | 
|  | */ | 
|  | #include "Common.h" | 
|  |  | 
|  | #define __USE_GNU       /* need RTLD_NEXT */ | 
|  | #include <dlfcn.h> | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <pthread.h> | 
|  | #include <string.h> | 
|  | #include <errno.h> | 
|  | #include <assert.h> | 
|  | #include <sys/stat.h> | 
|  | #include <sys/types.h> | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Global state. | 
|  | */ | 
|  | struct WrapSimGlobals gWrapSim; | 
|  | pthread_once_t gWrapSimInitialized = PTHREAD_ONCE_INIT; | 
|  |  | 
|  | /* | 
|  | * Initialize our global state. | 
|  | */ | 
|  | static void initGlobals(void) | 
|  | { | 
|  | memset(&gWrapSim, 0xdd, sizeof(gWrapSim)); | 
|  | gWrapSim.logFd = -1; | 
|  | gWrapSim.keyMap = NULL; | 
|  |  | 
|  | /* | 
|  | * Find the original version of functions we override. | 
|  | */ | 
|  | _ws_access = dlsym(RTLD_NEXT, "access"); | 
|  | _ws_open = dlsym(RTLD_NEXT, "open"); | 
|  | _ws_open64 = dlsym(RTLD_NEXT, "open64"); | 
|  |  | 
|  | _ws_close = dlsym(RTLD_NEXT, "close"); | 
|  | _ws_dup = dlsym(RTLD_NEXT, "dup"); | 
|  | _ws_read = dlsym(RTLD_NEXT, "read"); | 
|  | _ws_readv = dlsym(RTLD_NEXT, "readv"); | 
|  | _ws_write = dlsym(RTLD_NEXT, "write"); | 
|  | _ws_writev = dlsym(RTLD_NEXT, "writev"); | 
|  | _ws_mmap = dlsym(RTLD_NEXT, "mmap"); | 
|  | _ws_mmap64 = dlsym(RTLD_NEXT, "mmap64"); | 
|  | _ws_ioctl = dlsym(RTLD_NEXT, "ioctl"); | 
|  |  | 
|  | _ws_chdir = dlsym(RTLD_NEXT, "chdir"); | 
|  | _ws_chmod = dlsym(RTLD_NEXT, "chmod"); | 
|  | _ws_chown = dlsym(RTLD_NEXT, "chown"); | 
|  | _ws_creat = dlsym(RTLD_NEXT, "creat"); | 
|  | _ws_execve = dlsym(RTLD_NEXT, "execve"); | 
|  | _ws_getcwd = dlsym(RTLD_NEXT, "getcwd"); | 
|  | _ws_lchown = dlsym(RTLD_NEXT, "lchown"); | 
|  | _ws_link = dlsym(RTLD_NEXT, "link"); | 
|  | _ws_lstat = dlsym(RTLD_NEXT, "lstat"); | 
|  | _ws_lstat64 = dlsym(RTLD_NEXT, "lstat64"); | 
|  | _ws___lxstat = dlsym(RTLD_NEXT, "__lxstat"); | 
|  | _ws___lxstat64 = dlsym(RTLD_NEXT, "__lxstat64"); | 
|  | _ws_mkdir = dlsym(RTLD_NEXT, "mkdir"); | 
|  | _ws_readlink = dlsym(RTLD_NEXT, "readlink"); | 
|  | _ws_rename = dlsym(RTLD_NEXT, "rename"); | 
|  | _ws_rmdir = dlsym(RTLD_NEXT, "rmdir"); | 
|  | _ws_stat = dlsym(RTLD_NEXT, "stat"); | 
|  | _ws_stat64 = dlsym(RTLD_NEXT, "stat64"); | 
|  | _ws___xstat = dlsym(RTLD_NEXT, "__xstat"); | 
|  | _ws___xstat64 = dlsym(RTLD_NEXT, "__xstat64"); | 
|  | _ws_statfs = dlsym(RTLD_NEXT, "statfs"); | 
|  | _ws_statfs64 = dlsym(RTLD_NEXT, "statfs64"); | 
|  | _ws_symlink = dlsym(RTLD_NEXT, "symlink"); | 
|  | _ws_unlink = dlsym(RTLD_NEXT, "unlink"); | 
|  | _ws_utime = dlsym(RTLD_NEXT, "utime"); | 
|  | _ws_utimes = dlsym(RTLD_NEXT, "utimes"); | 
|  |  | 
|  | _ws_execl = dlsym(RTLD_NEXT, "execl"); | 
|  | _ws_execle = dlsym(RTLD_NEXT, "execle"); | 
|  | _ws_execlp = dlsym(RTLD_NEXT, "execlp"); | 
|  | _ws_execv = dlsym(RTLD_NEXT, "execv"); | 
|  | _ws_execvp = dlsym(RTLD_NEXT, "execvp"); | 
|  | _ws_fopen = dlsym(RTLD_NEXT, "fopen"); | 
|  | _ws_fopen64 = dlsym(RTLD_NEXT, "fopen64"); | 
|  | _ws_freopen = dlsym(RTLD_NEXT, "freopen"); | 
|  | _ws_ftw = dlsym(RTLD_NEXT, "ftw"); | 
|  | _ws_opendir = dlsym(RTLD_NEXT, "opendir"); | 
|  | _ws_dlopen = dlsym(RTLD_NEXT, "dlopen"); | 
|  |  | 
|  | _ws_setpriority = dlsym(RTLD_NEXT, "setpriority"); | 
|  | //_ws_pipe = dlsym(RTLD_NEXT, "pipe"); | 
|  |  | 
|  | const char* logFileName = getenv("WRAPSIM_LOG"); | 
|  | if (logFileName != NULL ){ | 
|  | gWrapSim.logFd = _ws_open(logFileName, O_WRONLY|O_APPEND|O_CREAT, 0664); | 
|  | } | 
|  |  | 
|  | /* log messages now work; say hello */ | 
|  | wsLog("--- initializing sim wrapper ---\n"); | 
|  |  | 
|  | gWrapSim.simulatorFd = -1; | 
|  |  | 
|  | pthread_mutex_init(&gWrapSim.startLock, NULL); | 
|  | pthread_cond_init(&gWrapSim.startCond, NULL); | 
|  | gWrapSim.startReady = 0; | 
|  |  | 
|  | pthread_mutex_init(&gWrapSim.fakeFdLock, NULL); | 
|  | gWrapSim.fakeFdMap = wsAllocBitVector(kMaxFakeFdCount, 0); | 
|  | memset(gWrapSim.fakeFdList, 0, sizeof(gWrapSim.fakeFdList)); | 
|  |  | 
|  | pthread_mutex_init(&gWrapSim.atomicLock, NULL); | 
|  |  | 
|  | gWrapSim.numDisplays = 0; | 
|  |  | 
|  | gWrapSim.keyInputDevice = NULL; | 
|  |  | 
|  | /* | 
|  | * Get target for remapped "/system" and "/data". | 
|  | * | 
|  | * The ANDROID_PRODUCT_OUT env var *must* be set for rewriting to work. | 
|  | */ | 
|  | const char* outEnv = getenv("ANDROID_PRODUCT_OUT"); | 
|  | if (outEnv == NULL) { | 
|  | gWrapSim.remapBaseDir = NULL; | 
|  | wsLog("--- $ANDROID_PRODUCT_OUT not set, " | 
|  | "filename remapping disabled\n"); | 
|  | } else { | 
|  | /* grab string and append '/' -- note this never gets freed */ | 
|  | gWrapSim.remapBaseDirLen = strlen(outEnv); | 
|  | gWrapSim.remapBaseDir = strdup(outEnv); | 
|  | wsLog("--- name remap to %s\n", gWrapSim.remapBaseDir); | 
|  | } | 
|  |  | 
|  | gWrapSim.initialized = 1; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Creates a directory, or prints a log message if it fails. | 
|  | */ | 
|  | static int createTargetDirectory(const char *path, mode_t mode) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | ret = mkdir(path, mode); | 
|  | if (ret == 0 || errno == EEXIST) { | 
|  | return 0; | 
|  | } | 
|  | wsLog("--- could not create target directory %s: %s\n", | 
|  | path, strerror(errno)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Any setup that would normally be done by init(8). | 
|  | * Note that since the syscall redirects have been installed | 
|  | * at this point, we are effectively operating within the | 
|  | * simulation context. | 
|  | */ | 
|  | static void initGeneral(void) | 
|  | { | 
|  | wsLog("--- preparing system\n"); | 
|  |  | 
|  | /* Try to make sure that certain directories exist. | 
|  | * If we fail to create them, the errors will show up in the log, | 
|  | * but we keep going. | 
|  | */ | 
|  | createTargetDirectory("/data", 0777); | 
|  | createTargetDirectory("/data/dalvik-cache", 0777); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Initialize all necessary state, and indicate that we're ready to go. | 
|  | */ | 
|  | static void initOnce(void) | 
|  | { | 
|  | initGlobals(); | 
|  | initGeneral(); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Shared object initializer.  glibc guarantees that this function is | 
|  | * called before dlopen() returns.  It may be called multiple times. | 
|  | */ | 
|  | __attribute__((constructor)) | 
|  | static void initialize(void) | 
|  | { | 
|  | pthread_once(&gWrapSimInitialized, initOnce); | 
|  | } | 
|  |  | 
|  |  |