auto import from //depot/cupcake/@135843
diff --git a/simulator/wrapsim/FakeDev.c b/simulator/wrapsim/FakeDev.c
new file mode 100644
index 0000000..3e223d3
--- /dev/null
+++ b/simulator/wrapsim/FakeDev.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2007 The Android Open Source Project
+ *
+ * Fake device support.
+ */
+/*
+Implementation notes:
+
+There are a couple of basic scenarios, exemplified by the "fb" and
+"events" devices. The framebuffer driver is pretty simple, handling a
+few ioctl()s and managing a stretch of memory. We can just intercept a
+few calls. The input event driver can be used in a select() or poll()
+call with other file descriptors, which either requires us to do some
+fancy tricks with select() and poll(), or requires that we return a real
+file descriptor (perhaps based on a socketpair).
+
+We have three basic approaches to dealing with "fake" file descriptors:
+
+(1) Always use real fds. We can dup() an open /dev/null to get a number
+ for the cases where we don't need a socketpair.
+(2) Always use fake fds with absurdly high numeric values. Testing to see
+ if the fd is one we handle is trivial (range check). This doesn't
+ work for select(), which uses fd bitmaps accessed through macros.
+(3) Use a mix of real and fake fds, in a high range (512-1023). Because
+ it's in the "real" range, we can pass real fds around for things that
+ are handed to poll() and select(), but because of the high numeric
+ value we *should* be able to get away with a trivial range check.
+
+Approach (1) is the most portable and least likely to break, but the
+efficiencies gained in approach (2) make it more desirable. There is
+a small risk of application fds wandering into our range, but we can
+minimize that by asserting on a "guard zone" and/or obstructing dup2().
+(We can also dup2(/dev/null) to "reserve" our fds, but that wastes
+resources.)
+*/
+
+#include "Common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <assert.h>
+#include <fnmatch.h>
+
+/*
+ * Devices we intercept.
+ *
+ * Needed:
+ * /dev/alarm
+ * radio
+ */
+typedef FakeDev* (*wsFileHook)(const char *path, int flags);
+
+typedef struct FakedPath {
+ const char *pathexpr;
+ wsFileHook hook;
+} FakedPath;
+
+FakedPath fakedpaths[] =
+{
+ { "/dev/graphics/fb0", wsOpenDevFb },
+ { "/dev/hw3d", NULL },
+ { "/dev/eac", wsOpenDevAudio },
+ { "/dev/tty0", wsOpenDevConsoleTty },
+ { "/dev/input/event0", wsOpenDevEvent },
+ { "/dev/input/*", NULL },
+ { "/dev/log/*", wsOpenDevLog },
+ { "/sys/class/power_supply/*", wsOpenDevPower },
+ { "/sys/devices/platform/android-vibrator/enable", wsOpenDevVibrator },
+ { "/sys/qemu_trace/*", NULL },
+ { NULL, NULL }
+};
+
+
+/*
+ * 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;
+}
+
+/*
+ * Default implementations. We want to log as much information as we can
+ * so that we can fill in the missing implementation.
+ *
+ * TODO: for some or all of these we will want to display the full arg list.
+ */
+static int noClose(FakeDev* dev, ...)
+{
+ return 0;
+}
+static int noRead(FakeDev* dev, ...)
+{
+ return notImplemented(dev, "read");
+}
+static int noReadv(FakeDev* dev, ...)
+{
+ return notImplemented(dev, "readv");
+}
+static int noWrite(FakeDev* dev, ...)
+{
+ return notImplemented(dev, "write");
+}
+static int noWritev(FakeDev* dev, ...)
+{
+ return notImplemented(dev, "writev");
+}
+static int noMmap(FakeDev* dev, ...)
+{
+ return notImplemented(dev, "mmap");
+}
+static int noIoctl(FakeDev* dev, ...)
+{
+ return notImplemented(dev, "ioctl");
+}
+
+
+/*
+ * 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;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Map a file descriptor to a fake device.
+ *
+ * Returns NULL if there's no corresponding entry.
+ */
+FakeDev* wsFakeDevFromFd(int fd)
+{
+ /* quick range test */
+ if (fd < kFakeFdBase || fd >= kFakeFdBase + kMaxFakeFdCount)
+ return NULL;
+
+ return gWrapSim.fakeFdList[fd - kFakeFdBase];
+}
+
+
+/*
+ * 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;
+}
+
+/*
+ * 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;
+}