Add support for dup()ing fake file descriptors to the simulator.
diff --git a/simulator/wrapsim/Android.mk b/simulator/wrapsim/Android.mk
index 0a995a2..f9a2414 100644
--- a/simulator/wrapsim/Android.mk
+++ b/simulator/wrapsim/Android.mk
@@ -22,7 +22,8 @@
 	Intercept.c \
 	Log.c \
 	SimMgr.c \
-	SysPower.c
+	SysPower.c \
+	Util.c
 
 LOCAL_C_INCLUDES += prebuilt/common/esd
 
diff --git a/simulator/wrapsim/Common.h b/simulator/wrapsim/Common.h
index a9c3bb8..463262f 100644
--- a/simulator/wrapsim/Common.h
+++ b/simulator/wrapsim/Common.h
@@ -14,5 +14,6 @@
 #include "Log.h"
 #include "SimMgr.h"
 #include "Globals.h"
+#include "Util.h"
 
 #endif /*_WRAPSIM_COMMON_H*/
diff --git a/simulator/wrapsim/DevFb.c b/simulator/wrapsim/DevFb.c
index c54403e..bfdbb22 100644
--- a/simulator/wrapsim/DevFb.c
+++ b/simulator/wrapsim/DevFb.c
@@ -14,6 +14,10 @@
 #include <linux/fb.h>
 
 typedef struct FbState {
+
+    /* refcount for dup() */
+    int refCount;
+
     /* index into gWrapSim.display[] */
     int     displayIdx;
 
@@ -77,7 +81,13 @@
  */
 static void freeState(FbState* fbState)
 {
-    free(fbState);
+    int oldcount;
+
+    oldcount = wsAtomicAdd(&fbState->refCount, -1);
+
+    if (oldcount == 0) {
+        free(fbState);
+    }
 }
 
 /*
@@ -242,6 +252,28 @@
 }
 
 /*
+ * dup() an existing fake descriptor
+ */
+static FakeDev* dupFb(FakeDev* dev, int fd)
+{
+    FakeDev* newDev = wsCreateFakeDev(dev->debugName);
+    if (newDev != NULL) {
+        newDev->mmap = mmapFb;
+        newDev->ioctl = ioctlFb;
+        newDev->close = closeFb;
+        newDev->dup = dupFb;
+
+        /* use state from existing FakeDev */
+        FbState* fbState = dev->state;
+        wsAtomicAdd(&fbState->refCount, 1);
+
+        newDev->state = fbState;
+    }
+
+    return newDev;
+}
+
+/*
  * Open the console TTY device, which responds to a collection of ioctl()s.
  */
 FakeDev* wsOpenDevFb(const char* pathName, int flags)
@@ -251,6 +283,7 @@
         newDev->mmap = mmapFb;
         newDev->ioctl = ioctlFb;
         newDev->close = closeFb;
+        newDev->dup = dupFb;
 
         FbState* fbState = calloc(1, sizeof(FbState));
 
diff --git a/simulator/wrapsim/FakeDev.c b/simulator/wrapsim/FakeDev.c
index 7d2494e..f03dd29 100644
--- a/simulator/wrapsim/FakeDev.c
+++ b/simulator/wrapsim/FakeDev.c
@@ -99,6 +99,11 @@
 {
     return 0;
 }
+static FakeDev* noDup(FakeDev* dev, ...)
+{
+    notImplemented(dev, "dup");
+    return NULL;
+}
 static int noRead(FakeDev* dev, ...)
 {
     return notImplemented(dev, "read");
@@ -146,6 +151,7 @@
     newDev->state = NULL;
 
     newDev->close = (Fake_close) noClose;
+    newDev->dup = (Fake_dup) noDup;
     newDev->read = (Fake_read) noRead;
     newDev->readv = (Fake_readv) noReadv;
     newDev->write = (Fake_write) noWrite;
diff --git a/simulator/wrapsim/FakeDev.h b/simulator/wrapsim/FakeDev.h
index 4781cfc..65f47ae 100644
--- a/simulator/wrapsim/FakeDev.h
+++ b/simulator/wrapsim/FakeDev.h
@@ -12,13 +12,14 @@
 
 typedef struct FakeDev FakeDev;
 
-typedef int     (*Fake_close)(FakeDev* dev, int);
-typedef ssize_t (*Fake_read)(FakeDev* dev, int, void*, size_t);
-typedef ssize_t (*Fake_readv)(FakeDev* dev, int, const struct iovec*, int);
-typedef ssize_t (*Fake_write)(FakeDev* dev, int, const void*, size_t);
-typedef ssize_t (*Fake_writev)(FakeDev* dev, int, const struct iovec*, int);
-typedef void*   (*Fake_mmap)(FakeDev* dev, void*, size_t, int, int, int, __off_t);
-typedef int     (*Fake_ioctl)(FakeDev* dev, int, int, void*);
+typedef int      (*Fake_close)(FakeDev* dev, int);
+typedef FakeDev* (*Fake_dup)(FakeDev* dev, int);
+typedef ssize_t  (*Fake_read)(FakeDev* dev, int, void*, size_t);
+typedef ssize_t  (*Fake_readv)(FakeDev* dev, int, const struct iovec*, int);
+typedef ssize_t  (*Fake_write)(FakeDev* dev, int, const void*, size_t);
+typedef ssize_t  (*Fake_writev)(FakeDev* dev, int, const struct iovec*, int);
+typedef void*    (*Fake_mmap)(FakeDev* dev, void*, size_t, int, int, int, __off_t);
+typedef int      (*Fake_ioctl)(FakeDev* dev, int, int, void*);
 
 /*
  * An open fake device entry.
@@ -42,6 +43,7 @@
      * All other file descriptor operations should fail, usually with EBADF.
      */
     Fake_close  close;
+    Fake_dup  dup;
     Fake_read   read;
     Fake_readv  readv;
     Fake_write  write;
diff --git a/simulator/wrapsim/Globals.h b/simulator/wrapsim/Globals.h
index 75c98d8..a8d834c 100644
--- a/simulator/wrapsim/Globals.h
+++ b/simulator/wrapsim/Globals.h
@@ -29,6 +29,7 @@
 typedef int     (*Func_open64)(const char*, int, mode_t);
 
 typedef int     (*Func_close)(int);
+typedef int     (*Func_dup)(int);
 typedef ssize_t (*Func_read)(int, void*, size_t);
 typedef ssize_t (*Func_readv)(int, const struct iovec*, int);
 typedef ssize_t (*Func_write)(int, const void*, size_t);
@@ -95,6 +96,7 @@
 EXTERN_FUNC Func_open64 _ws_open64;
 
 EXTERN_FUNC Func_close _ws_close;
+EXTERN_FUNC Func_dup _ws_dup;
 EXTERN_FUNC Func_read _ws_read;
 EXTERN_FUNC Func_readv _ws_readv;
 EXTERN_FUNC Func_write _ws_write;
@@ -201,6 +203,9 @@
     pthread_mutex_t fakeFdLock;
     BitVector*  fakeFdMap;
     FakeDev*    fakeFdList[kMaxFakeFdCount];
+
+    /* used for wsAtomicAdd */
+    pthread_mutex_t atomicLock;
 };
 
 extern struct WrapSimGlobals gWrapSim;
diff --git a/simulator/wrapsim/Init.c b/simulator/wrapsim/Init.c
index eed650b..3df0efe 100644
--- a/simulator/wrapsim/Init.c
+++ b/simulator/wrapsim/Init.c
@@ -40,6 +40,7 @@
     _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");
@@ -108,6 +109,8 @@
     gWrapSim.fakeFdMap = wsAllocBitVector(kMaxFakeFdCount, 0);
     memset(gWrapSim.fakeFdList, 0, sizeof(gWrapSim.fakeFdList));
 
+    pthread_mutex_init(&gWrapSim.atomicLock, NULL);
+
     gWrapSim.numDisplays = 0;
 
     gWrapSim.keyInputDevice = NULL;
diff --git a/simulator/wrapsim/Intercept.c b/simulator/wrapsim/Intercept.c
index 49d77ee..09547fb 100644
--- a/simulator/wrapsim/Intercept.c
+++ b/simulator/wrapsim/Intercept.c
@@ -160,7 +160,7 @@
     _rtype _fname( __VA_ARGS__ )
 #define PASS_THROUGH_BODY(_fname, _patharg, ...)                            \
     {                                                                       \
-        CALLTRACEV("%s\n", __FUNCTION__);                                   \
+        CALLTRACEV("%s(%s)\n", __FUNCTION__, _patharg);                     \
         char pathBuf[PATH_MAX];                                             \
         return _ws_##_fname(rewritePath(#_fname, pathBuf, _patharg),        \
             ##__VA_ARGS__);                                                 \
@@ -631,6 +631,30 @@
 }
 
 
+int dup(int fd)
+{
+    CALLTRACEV("%s(%d)\n", __FUNCTION__, fd);
+
+    FakeDev* dev = wsFakeDevFromFd(fd);
+    if (dev != NULL) {
+        FakeDev* newDev = dev->dup(dev, fd);
+        if (newDev != NULL) {
+            /*
+             * Now that the device entry is ready, add it to the list.
+             */
+            wsLog("## dup'ed fake dev %d: '%s' %p\n",
+                newDev->fd, newDev->debugName, newDev->state);
+            gWrapSim.fakeFdList[newDev->fd - kFakeFdBase] = newDev;
+            return newDev->fd;
+        }
+        return -1;
+    } else {
+        CALLTRACE("dup(%d)\n", fd);
+        return _ws_dup(fd);
+    }
+}
+
+
 /*
  * Close a file descriptor.
  */
diff --git a/simulator/wrapsim/Util.c b/simulator/wrapsim/Util.c
new file mode 100644
index 0000000..33d903b
--- /dev/null
+++ b/simulator/wrapsim/Util.c
@@ -0,0 +1,13 @@
+
+#include "Common.h"
+
+int wsAtomicAdd(int *var, int val)
+{
+    int cc;
+    int ret;
+    cc = pthread_mutex_lock(&gWrapSim.atomicLock);
+    ret = *var;
+    *var = *var + val;
+    cc = pthread_mutex_unlock(&gWrapSim.atomicLock);
+    return ret;
+}
diff --git a/simulator/wrapsim/Util.h b/simulator/wrapsim/Util.h
new file mode 100644
index 0000000..e470802
--- /dev/null
+++ b/simulator/wrapsim/Util.h
@@ -0,0 +1,4 @@
+
+
+
+int wsAtomicAdd(int *var, int val);