/* * Create a new FakeDev entry, and open a file descriptor that actually * works. */ FakeDev* wsCreateRealFakeDev(const char* debugName) { FakeDev* newDev = wsCreateFakeDev(debugName); if (newDev == NULL) return newDev; int fds[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { wsLog("socketpair() failed: %s\n", strerror(errno)); wsFreeFakeDev(newDev); return NULL; } if (dup2(fds[0], newDev->fd) < 0) { wsLog("dup2(%d,%d) failed: %s\n", fds[0], newDev->fd, strerror(errno)); wsFreeFakeDev(newDev); return NULL; } close(fds[0]); /* okay to leave this one in the "normal" range; not visible to app */ newDev->otherFd = fds[1]; return newDev; }
/* * Check to see if we're opening a device that we want to fake out. * * We return a file descriptor >= 0 on success, -1 if we're not interested, * or -2 if we explicitly want to pretend that the device doesn't exist. */ int wsInterceptDeviceOpen(const char* pathName, int flags) { FakedPath* p = fakedpaths; while (p->pathexpr) { if (fnmatch(p->pathexpr, pathName, 0) == 0) { if (p->hook != NULL) { FakeDev* dev = p->hook(pathName, flags); if (dev != NULL) { /* * Now that the device entry is ready, add it to the list. */ wsLog("## created fake dev %d: '%s' %p\n", dev->fd, dev->debugName, dev->state); gWrapSim.fakeFdList[dev->fd - kFakeFdBase] = dev; return dev->fd; } } else { wsLog("## rejecting attempt to open %s\n", pathName); errno = ENOENT; return -2; } break; } p++; } return -1; }
/* * Generic drop-in for an unimplemented call. * * Returns -1, which conveniently is the same as MAP_FAILED for mmap. */ static int notImplemented(FakeDev* dev, const char* callName) { wsLog("WARNING: unimplemented %s() on '%s' %p\n", callName, dev->debugName, dev->state); errno = kNoHandlerError; return -1; }
/* * Free fake device entry. */ void wsFreeFakeDev(FakeDev* dev) { if (dev == NULL) return; wsLog("## closing/freeing '%s' (%d/%d)\n", dev->debugName, dev->fd, dev->otherFd); /* * If we assigned a file descriptor slot, free it up. */ if (dev->fd >= 0) { int cc; gWrapSim.fakeFdList[dev->fd - kFakeFdBase] = NULL; cc = pthread_mutex_lock(&gWrapSim.fakeFdLock); assert(cc == 0); wsFreeBit(gWrapSim.fakeFdMap, dev->fd - kFakeFdBase); cc = pthread_mutex_unlock(&gWrapSim.fakeFdLock); assert(cc == 0); } if (dev->otherFd >= 0) close(dev->otherFd); if (dev->debugName) free(dev->debugName); free(dev); }
/* * If appropriate, rewrite the path to point to a different location. * * Returns either "pathBuf" or "origPath" depending on whether or not we * chose to rewrite the path. "origPath" must be a buffer capable of * holding an extended pathname; for best results use PATH_MAX. */ static const char* rewritePath(const char* func, char* pathBuf, const char* origPath) { /* * Rewrite paths that start with "/system/" or "/data/" */ if (origPath[0] != '/') goto skip_rewrite; if (memcmp(origPath+1, "system", 6) == 0 && (origPath[7] == '/' || origPath[7] == '\0')) goto do_rewrite; if (memcmp(origPath+1, "data", 4) == 0 && (origPath[5] == '/' || origPath[5] == '\0')) goto do_rewrite; skip_rewrite: /* check to see if something is side-stepping the rewrite */ if (memcmp(origPath, gWrapSim.remapBaseDir, gWrapSim.remapBaseDirLen) == 0) { wsLog("NOTE: full path used: %s(%s)\n", func, origPath); } CALLTRACE("rewrite %s('%s') --> (not rewritten)\n", func, origPath); return origPath; do_rewrite: memcpy(pathBuf, gWrapSim.remapBaseDir, gWrapSim.remapBaseDirLen); strcpy(pathBuf + gWrapSim.remapBaseDirLen, origPath); CALLTRACE("rewrite %s('%s') --> '%s'\n", func, origPath, pathBuf); return pathBuf; }
/* * Set some stuff up. */ static int configureInitialState(const char* pathName, AudioState* audioState) { #if BUILD_SIM_WITHOUT_AUDIO return 0; #else audioState->handle = NULL; snd_pcm_open(&audioState->handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (audioState->handle) { snd_pcm_hw_params_t *params; snd_pcm_hw_params_malloc(¶ms); snd_pcm_hw_params_any(audioState->handle, params); snd_pcm_hw_params_set_access(audioState->handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(audioState->handle, params, SND_PCM_FORMAT_S16_LE); unsigned int rate = 44100; snd_pcm_hw_params_set_rate_near(audioState->handle, params, &rate, NULL); snd_pcm_hw_params_set_channels(audioState->handle, params, 2); snd_pcm_hw_params(audioState->handle, params); snd_pcm_hw_params_free(params); } else { wsLog("Couldn't open audio hardware, faking it\n"); } return 0; #endif }
/* * 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); }
/* * 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; }
/* * Check to see if we're accessing a device that we want to fake out. * Returns 0 if the device can be (fake) opened with the given mode, * -1 if it can't, -2 if it can't and we don't want to allow fallback * to the host-device either. * TODO: actually check the mode. */ int wsInterceptDeviceAccess(const char *pathName, int mode) { FakedPath *p = fakedpaths; while (p->pathexpr) { if (fnmatch(p->pathexpr, pathName, 0) == 0) { if (p->hook) { return 0; } else { wsLog("## rejecting attempt to open %s\n", pathName); errno = ENOENT; return -2; } break; } p++; } errno = ENOENT; return -1; }
/* * Create a new FakeDev entry. * * We mark the fd slot as "used" in the bitmap, but don't add it to the * table yet since the entry is not fully prepared. */ FakeDev* wsCreateFakeDev(const char* debugName) { FakeDev* newDev; int cc; assert(debugName != NULL); newDev = (FakeDev*) calloc(1, sizeof(FakeDev)); if (newDev == NULL) return NULL; newDev->debugName = strdup(debugName); newDev->state = NULL; newDev->close = (Fake_close) noClose; newDev->read = (Fake_read) noRead; newDev->readv = (Fake_readv) noReadv; newDev->write = (Fake_write) noWrite; newDev->writev = (Fake_writev) noWritev; newDev->mmap = (Fake_mmap) noMmap; newDev->ioctl = (Fake_ioctl) noIoctl; /* * Allocate a new entry. The bit vector map is really only used as a * performance boost in the current implementation. */ cc = pthread_mutex_lock(&gWrapSim.fakeFdLock); assert(cc == 0); int newfd = wsAllocBit(gWrapSim.fakeFdMap); cc = pthread_mutex_unlock(&gWrapSim.fakeFdLock); assert(cc == 0); if (newfd < 0) { wsLog("WARNING: ran out of 'fake' file descriptors\n"); free(newDev); return NULL; } newDev->fd = newfd + kFakeFdBase; newDev->otherFd = -1; assert(gWrapSim.fakeFdList[newDev->fd - kFakeFdBase] == NULL); return newDev; }
/* * 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; }