Home | History | Annotate | Download | only in wrapsim
      1 /*
      2  * Copyright 2007 The Android Open Source Project
      3  *
      4  * Simulator interactions.
      5  *
      6  * TODO: for multi-process we probably need to switch to a new process
      7  * group if we are the first process (could be runtime, could be gdb),
      8  * rather than wait for the simulator to tell us to switch.
      9  */
     10 #include "Common.h"
     11 
     12 #include <stdlib.h>
     13 #include <stdio.h>
     14 #include <stdint.h>
     15 #include <sys/types.h>
     16 #include <sys/socket.h>
     17 #include <sys/ipc.h>
     18 #include <sys/shm.h>
     19 #include <sys/sem.h>
     20 #include <sys/un.h>
     21 #include <signal.h>
     22 #include <assert.h>
     23 
     24 // fwd
     25 static int connectToSim(void);
     26 static void listenToSim(void);
     27 
     28 /*
     29  * Env var to restrict who tries to talk to the front end.
     30  */
     31 #define kWrapSimConnectedEnv    "WRAP_SIM_CONNECTED"
     32 
     33 
     34 /*
     35  * Signal the main thread that we're ready to continue.
     36  */
     37 static void signalMainThread(void)
     38 {
     39     int cc;
     40 
     41     cc = pthread_mutex_lock(&gWrapSim.startLock);
     42     assert(cc == 0);
     43 
     44     gWrapSim.startReady = 1;
     45 
     46     cc = pthread_cond_signal(&gWrapSim.startCond);
     47     assert(cc == 0);
     48 
     49     cc = pthread_mutex_unlock(&gWrapSim.startLock);
     50     assert(cc == 0);
     51 }
     52 
     53 
     54 /*
     55  * Entry point for the sim management thread.
     56  *
     57  * Once we have established a connection to the simulator and are ready
     58  * for other threads to send messages, we signal the main thread.
     59  */
     60 static void* simThreadEntry(void* arg)
     61 {
     62     wsLog("--- sim manager thread started\n");
     63 
     64     /*
     65      * Establish a connection to the simulator front-end.  If we can't do
     66      * that, we have no access to input or output devices, and we might
     67      * as well give up.
     68      */
     69     if (connectToSim() != 0) {
     70         signalMainThread();
     71         return NULL;
     72     }
     73 
     74     /* success! */
     75     wsLog("--- sim manager thread ready\n");
     76     gWrapSim.simulatorInitFailed = 0;
     77     signalMainThread();
     78 
     79     listenToSim();
     80 
     81     wsLog("--- sim manager thread exiting\n");
     82 
     83     return NULL;
     84 }
     85 
     86 /*
     87  * If we think we're not yet connected to the sim, do so now.  We only
     88  * want to do this once per process *group*, so we control access with
     89  * an environment variable.
     90  */
     91 int wsSimConnect(void)
     92 {
     93     /*
     94      * If the environment variable hasn't been set, assume we're the first
     95      * to get here, and should attach to the simulator.  We set the env
     96      * var here whether or not we succeed in connecting to the sim.
     97      *
     98      * (For correctness we should wrap the getenv/setenv in a semaphore.)
     99      */
    100     if (getenv(kWrapSimConnectedEnv) == NULL) {
    101         pthread_attr_t threadAttr;
    102         pthread_t threadHandle;
    103         int cc;
    104 
    105         gWrapSim.simulatorInitFailed = 1;
    106         setenv(kWrapSimConnectedEnv, "1", 1);
    107 
    108         cc = pthread_mutex_lock(&gWrapSim.startLock);
    109         assert(cc == 0);
    110 
    111         pthread_attr_init(&threadAttr);
    112         pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
    113         cc = pthread_create(&threadHandle, &threadAttr, simThreadEntry, NULL);
    114         if (cc != 0) {
    115             wsLog("Unable to create new thread: %s\n", strerror(errno));
    116             abort();
    117         }
    118 
    119         while (!gWrapSim.startReady) {
    120             cc = pthread_cond_wait(&gWrapSim.startCond, &gWrapSim.startLock);
    121             assert(cc == 0);
    122         }
    123 
    124         cc = pthread_mutex_unlock(&gWrapSim.startLock);
    125         assert(cc == 0);
    126 
    127         if (gWrapSim.simulatorInitFailed) {
    128             wsLog("Simulator initialization failed, bailing\n");
    129 
    130             /* this *should* be okay to do */
    131             fprintf(stderr, "Fatal error:"
    132                 " unable to connect to sim front-end (not running?)\n");
    133             abort();
    134         }
    135     }
    136 
    137     wsLog("+++ continuing\n");
    138     return 0;
    139 }
    140 
    141 
    142 /*
    143  * ===========================================================================
    144  *      Message / MessageStream
    145  * ===========================================================================
    146  */
    147 
    148 /*
    149  * This is a quick & dirty rewrite of the C++ Message and MessageStream
    150  * classes, ported to C, reduced in generality, with syscalls stubbed
    151  * where necessary.  I didn't fix the API to make it more sensible in C
    152  * (which lacks destructors), so some of this is a little fragile or
    153  * awkward.
    154  */
    155 
    156 /* values for message type byte; must match android::Message constants */
    157 typedef enum MessageType {
    158     kTypeUnknown = 0,
    159     kTypeRaw,           // chunk of raw data
    160     kTypeConfig,        // send a name=value pair to peer
    161     kTypeCommand,       // simple command w/arg
    162     kTypeCommandExt,    // slightly more complicated command
    163     kTypeLogBundle,     // multi-part log message
    164 } MessageType;
    165 
    166 /*
    167  * Reusable message object.
    168  */
    169 typedef struct Message {
    170     MessageType     mType;
    171     unsigned char*  mData;
    172     int             mLength;
    173 } Message;
    174 
    175 /* magic init messages; must match android::MessageStream constants */
    176 enum {
    177     kHelloMsg       = 0x4e303047,       // 'N00G'
    178     kHelloAckMsg    = 0x31455221,       // '1ER!'
    179 };
    180 
    181 
    182 /*
    183  * Clear out a Message.
    184  */
    185 static void Message_clear(Message* msg)
    186 {
    187     memset(msg, 0, sizeof(Message));
    188 }
    189 
    190 /*
    191  * Keep reading until we get all bytes or hit EOF/error.  "fd" is expected
    192  * to be in blocking mode.
    193  *
    194  * Returns 0 on success.
    195  */
    196 static int readAll(int fd, void* buf, size_t count)
    197 {
    198     ssize_t actual;
    199     ssize_t have;
    200 
    201     have = 0;
    202     while (have != (ssize_t) count) {
    203         actual = _ws_read(fd, ((char*) buf) + have, count - have);
    204         if (actual < 0) {
    205             if (errno == EINTR)
    206                 continue;
    207             wsLog("read %d failed: %s\n", fd, strerror(errno));
    208         } else if (actual == 0) {
    209             wsLog("early EOF on %d\n", fd);
    210             return -1;
    211         } else {
    212             have += actual;
    213         }
    214 
    215         assert(have <= (ssize_t)count);
    216     }
    217 
    218     return 0;
    219 }
    220 
    221 #if 0
    222 /*
    223  * Keep writing until we put all bytes or hit an error.  "fd" is expected
    224  * to be in blocking mode.
    225  *
    226  * Returns 0 on success.
    227  */
    228 static int writeAll(int fd, const void* buf, size_t count)
    229 {
    230     ssize_t actual;
    231     ssize_t have;
    232 
    233     have = 0;
    234     while (have != count) {
    235         actual = _ws_write(fd, ((const char*) buf) + have, count - have);
    236         if (actual < 0) {
    237             if (errno == EINTR)
    238                 continue;
    239             wsLog("write %d failed: %s\n", fd, strerror(errno));
    240         } else if (actual == 0) {
    241             wsLog("wrote zero on %d\n", fd);
    242             return -1;
    243         } else {
    244             have += actual;
    245         }
    246 
    247         assert(have <= count);
    248     }
    249 
    250     return 0;
    251 }
    252 #endif
    253 
    254 /*
    255  * Read a message from the specified file descriptor.
    256  *
    257  * The caller must Message_release(&msg).
    258  *
    259  * We guarantee 32-bit alignment for msg->mData.
    260  */
    261 static int Message_read(Message* msg, int fd)
    262 {
    263     unsigned char header[4];
    264 
    265     readAll(fd, header, 4);
    266 
    267     msg->mType = (MessageType) header[2];
    268     msg->mLength = header[0] | header[1] << 8;
    269     msg->mLength -= 2;   // we already read two of them in the header
    270 
    271     if (msg->mLength > 0) {
    272         int actual;
    273 
    274         /* Linux malloc guarantees at least 32-bit alignment */
    275         msg->mData = (unsigned char*) malloc(msg->mLength);
    276         if (msg->mData == NULL) {
    277             wsLog("alloc %d failed\n", msg->mLength);
    278             return -1;
    279         }
    280 
    281         if (readAll(fd, msg->mData, msg->mLength) != 0) {
    282             wsLog("failed reading message body (wanted %d)\n", msg->mLength);
    283             return -1;
    284         }
    285     } else {
    286         msg->mData = NULL;
    287     }
    288 
    289     return 0;
    290 }
    291 
    292 /*
    293  * Write a message to the specified file descriptor.
    294  *
    295  * The caller must Message_release(&msg).
    296  */
    297 static int Message_write(Message* msg, int fd)
    298 {
    299     struct iovec writeVec[2];
    300     unsigned char header[4];
    301     int len, numVecs;
    302     ssize_t actual;
    303 
    304     len = msg->mLength + 2;
    305     header[0] = len & 0xff;
    306     header[1] = (len >> 8) & 0xff;
    307     header[2] = msg->mType;
    308     header[3] = 0;
    309     writeVec[0].iov_base = header;
    310     writeVec[0].iov_len = 4;
    311     numVecs = 1;
    312 
    313     if (msg->mLength > 0) {
    314         assert(msg->mData != NULL);
    315         writeVec[1].iov_base = msg->mData;
    316         writeVec[1].iov_len = msg->mLength;
    317         numVecs++;
    318     }
    319 
    320     /* write it all in one shot; not worrying about partial writes for now */
    321     actual = _ws_writev(fd, writeVec, numVecs);
    322     if (actual != len+2) {
    323         wsLog("failed writing message to fd %d: %d of %d %s\n",
    324             fd, actual, len+2, strerror(errno));
    325         return -1;
    326     }
    327 
    328     return 0;
    329 }
    330 
    331 /*
    332  * Release storage associated with a Message.
    333  */
    334 static void Message_release(Message* msg)
    335 {
    336     free(msg->mData);
    337     msg->mData = NULL;
    338 }
    339 
    340 /*
    341  * Extract a name/value pair from a message.
    342  */
    343 static int getConfig(const Message* msg, const char** name, const char** val)
    344 {
    345     if (msg->mLength < 2) {
    346         wsLog("message len (%d) is too short\n", msg->mLength);
    347         return -1;
    348     }
    349     const char* ptr = (const char*) msg->mData;
    350 
    351     *name = (const char*) ptr;
    352     *val = (const char*) (ptr + strlen((char*)ptr) +1);
    353     return 0;
    354 }
    355 
    356 /*
    357  * Extract a command from a message.
    358  */
    359 static int getCommand(const Message* msg, int* pCmd, int* pArg)
    360 {
    361     if (msg->mLength != sizeof(int) * 2) {
    362         wsLog("message len (%d) is wrong for cmd (%d)\n",
    363             msg->mLength, sizeof(int) * 2);
    364         return -1;
    365     }
    366 
    367     /* this assumes 32-bit alignment on mData */
    368     const int* ptr = (const int*) msg->mData;
    369 
    370     *pCmd = ptr[0];
    371     *pArg = ptr[1];
    372 
    373     return 0;
    374 }
    375 
    376 /*
    377  * Extract an extended command from a message.
    378  */
    379 static int getCommandExt(const Message* msg, int* pCmd, int* pArg0,
    380     int* pArg1, int* pArg2)
    381 {
    382     if (msg->mLength != sizeof(int) * 4) {
    383         wsLog("message len (%d) is wrong for cmd (%d)\n",
    384             msg->mLength, sizeof(int) * 4);
    385         return -1;
    386     }
    387 
    388     /* this assumes 32-bit alignment on mData */
    389     const int* ptr = (const int*) msg->mData;
    390 
    391     *pCmd = ptr[0];
    392     *pArg0 = ptr[1];
    393     *pArg1 = ptr[2];
    394     *pArg2 = ptr[3];
    395 
    396     return 0;
    397 }
    398 
    399 /*
    400  * Attach 8 bytes of data with "cmd" and "arg" to "msg".
    401  *
    402  * "msg->mData" will need to be freed by the caller.  (This approach made
    403  * more sense when C++ destructors were available, but it's just not worth
    404  * reworking it.)
    405  */
    406 static int setCommand(Message* msg, int cmd, int arg)
    407 {
    408     Message_clear(msg);
    409 
    410     msg->mLength = 8;
    411     msg->mData = malloc(msg->mLength);
    412     msg->mType = kTypeCommand;
    413 
    414     /* assumes 32-bit alignment on malloc blocks */
    415     int* pInt = (int*) msg->mData;
    416     pInt[0] = cmd;
    417     pInt[1] = arg;
    418 
    419     return 0;
    420 }
    421 
    422 /*
    423  * Construct the full path.  The caller must free() the return value.
    424  */
    425 static char* makeFilename(const char* name)
    426 {
    427     static const char* kBasePath = "/tmp/android-";
    428     char* fileName;
    429 
    430     assert(name != NULL && name[0] != '\0');
    431 
    432     fileName = (char*) malloc(strlen(kBasePath) + strlen(name) + 1);
    433     strcpy(fileName, kBasePath);
    434     strcat(fileName, name);
    435 
    436     return fileName;
    437 }
    438 
    439 /*
    440  * Attach to a SysV shared memory segment.
    441  */
    442 static int attachToShmem(int key, int* pShmid, void** pAddr, long* pLength)
    443 {
    444     int shmid;
    445 
    446     shmid = shmget(key, 0, 0);
    447     if (shmid == -1) {
    448         wsLog("ERROR: failed to find shmem key=%d\n", key);
    449         return -1;
    450     }
    451 
    452     void* addr = shmat(shmid, NULL, 0);
    453     if (addr == (void*) -1) {
    454         wsLog("ERROR: could not attach to key=%d shmid=%d\n", key, shmid);
    455         return -1;
    456     }
    457 
    458     struct shmid_ds shmids;
    459     int cc;
    460 
    461     cc = shmctl(shmid, IPC_STAT, &shmids);
    462     if (cc != 0) {
    463         wsLog("ERROR: could not IPC_STAT shmid=%d\n", shmid);
    464         return -1;
    465     }
    466     *pLength = shmids.shm_segsz;
    467 
    468     *pAddr = addr;
    469     *pShmid = shmid;
    470     return 0;
    471 }
    472 
    473 /*
    474  * Attach to a SysV semaphore.
    475  */
    476 static int attachToSem(int key, int* pSemid)
    477 {
    478     int semid;
    479 
    480     semid = semget(key, 0, 0);
    481     if (semid == -1) {
    482         wsLog("ERROR: failed to attach to semaphore key=%d\n", key);
    483         return -1;
    484     }
    485 
    486     *pSemid = semid;
    487     return 0;
    488 }
    489 
    490 /*
    491  * "Adjust" a semaphore.
    492  */
    493 static int adjustSem(int semid, int adj)
    494 {
    495     const int wait = 1;
    496     struct sembuf op;
    497     int cc;
    498 
    499     op.sem_num = 0;
    500     op.sem_op = adj;
    501     op.sem_flg = SEM_UNDO;
    502     if (!wait)
    503         op.sem_flg |= IPC_NOWAIT;
    504 
    505     cc = semop(semid, &op, 1);
    506     if (cc != 0) {
    507         if (wait || errno != EAGAIN) {
    508             wsLog("Warning:"
    509                 " semaphore adjust by %d failed for semid=%d (errno=%d)\n",
    510                 adj, semid, errno);
    511         }
    512         return -1;
    513     }
    514 
    515     return 0;
    516 }
    517 
    518 /*
    519  * Acquire the semaphore associated with a display.
    520  */
    521 void wsLockDisplay(int displayIdx)
    522 {
    523     assert(displayIdx >= 0 && displayIdx < gWrapSim.numDisplays);
    524     int semid = gWrapSim.display[displayIdx].semid;
    525 
    526     (void) adjustSem(semid, -1);
    527 }
    528 
    529 /*
    530  * Acquire the semaphore associated with a display.
    531  */
    532 void wsUnlockDisplay(int displayIdx)
    533 {
    534     assert(displayIdx >= 0 && displayIdx < gWrapSim.numDisplays);
    535     int semid = gWrapSim.display[displayIdx].semid;
    536 
    537     (void) adjustSem(semid, 1);
    538 }
    539 
    540 /*
    541  * Process the display config from the simulator
    542  *
    543  * Right now this is a blob of raw data that looks like this:
    544  *  +00 magic number
    545  *  +04 #of displays
    546  *  +08 display 0:
    547  *      +00 width
    548  *      +04 height
    549  *      +08 format
    550  *      +0c refresh rate
    551  *      +10 shmem key
    552  *  +1c display 1...
    553  */
    554 static int handleDisplayConfig(const int* pData, int length)
    555 {
    556     int numDisplays;
    557 
    558     if (length < 8) {
    559         wsLog("Bad display config: length is %d\n", length);
    560         return -1;
    561     }
    562     assert(*pData == kDisplayConfigMagic);
    563 
    564     /*
    565      * Pull out the #of displays.  If it looks valid, configure the runtime.
    566      */
    567     pData++;        // skip over magic
    568     numDisplays = *pData++;
    569 
    570     if (numDisplays <= 0 || numDisplays > kMaxDisplays) {
    571         wsLog("Bizarre display count %d\n", numDisplays);
    572         return -1;
    573     }
    574     if (length != 8 + numDisplays * kValuesPerDisplay * (int)sizeof(int)) {
    575         wsLog("Bad display config: length is %d (expected %d)\n",
    576             length, 8 + numDisplays * kValuesPerDisplay * (int)sizeof(int));
    577         return -1;
    578     }
    579 
    580     /*
    581      * Extract the config values.
    582      *
    583      * The runtime doesn't support multiple devices, so we don't either.
    584      */
    585     int i;
    586     for (i = 0; i < numDisplays; i++) {
    587         gWrapSim.display[i].width = pData[0];
    588         gWrapSim.display[i].height = pData[1];
    589         gWrapSim.display[i].shmemKey = pData[4];
    590         /* format/refresh no longer needed */
    591 
    592         void* addr;
    593         int shmid, semid;
    594         long length;
    595         if (attachToShmem(gWrapSim.display[i].shmemKey, &shmid, &addr,
    596                 &length) != 0)
    597         {
    598             wsLog("Unable to connect to shared memory\n");
    599             return -1;
    600         }
    601 
    602         if (attachToSem(gWrapSim.display[i].shmemKey, &semid) != 0) {
    603             wsLog("Unable to attach to sempahore\n");
    604             return -1;
    605         }
    606 
    607         gWrapSim.display[i].shmid = shmid;
    608         gWrapSim.display[i].addr = addr;
    609         gWrapSim.display[i].length = length;
    610         gWrapSim.display[i].semid = semid;
    611 
    612         wsLog("Display %d: width=%d height=%d\n",
    613             i,
    614             gWrapSim.display[i].width,
    615             gWrapSim.display[i].height);
    616         wsLog("  shmem=0x%08x addr=%p len=%ld semid=%d\n",
    617             gWrapSim.display[i].shmemKey,
    618             gWrapSim.display[i].addr,
    619             gWrapSim.display[i].length,
    620             gWrapSim.display[i].semid);
    621 
    622         pData += kValuesPerDisplay;
    623     }
    624     gWrapSim.numDisplays = numDisplays;
    625 
    626     return 0;
    627 }
    628 
    629 
    630 /*
    631  * Initialize our connection to the simulator, which will be listening on
    632  * a UNIX domain socket.
    633  *
    634  * On success, this configures gWrapSim.simulatorFd and returns 0.
    635  */
    636 static int openSimConnection(const char* name)
    637 {
    638     int result = -1;
    639     char* fileName = NULL;
    640     int sock = -1;
    641     int cc;
    642 
    643     assert(gWrapSim.simulatorFd == -1);
    644 
    645     fileName = makeFilename(name);
    646 
    647     struct sockaddr_un addr;
    648 
    649     sock = socket(AF_UNIX, SOCK_STREAM, 0);
    650     if (sock < 0) {
    651         wsLog("UNIX domain socket create failed (errno=%d)\n", errno);
    652         goto bail;
    653     }
    654 
    655     /* connect to socket; fails if file doesn't exist */
    656     strcpy(addr.sun_path, fileName);    // max 108 bytes
    657     addr.sun_family = AF_UNIX;
    658     cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
    659     if (cc < 0) {
    660         // ENOENT means socket file doesn't exist
    661         // ECONNREFUSED means socket exists but nobody is listening
    662         wsLog("AF_UNIX connect failed for '%s': %s\n",
    663             fileName, strerror(errno));
    664         goto bail;
    665     }
    666 
    667     gWrapSim.simulatorFd = sock;
    668     sock = -1;
    669 
    670     result = 0;
    671     wsLog("+++ connected to '%s'\n", fileName);
    672 
    673 bail:
    674     if (sock >= 0)
    675         _ws_close(sock);
    676     free(fileName);
    677     return result;
    678 }
    679 
    680 /*
    681  * Prepare communication with the front end.  We wait for a "hello" from
    682  * the other side, and respond in kind.
    683  */
    684 static int prepSimConnection(void)
    685 {
    686     /* NOTE: this is endian-specific; we're x86 Linux only, so no problem */
    687     static const unsigned int hello = kHelloMsg;
    688     static const unsigned int helloAck = kHelloAckMsg;
    689     Message msg;
    690 
    691     if (Message_read(&msg, gWrapSim.simulatorFd) != 0) {
    692         wsLog("hello read failed\n");
    693         return -1;
    694     }
    695 
    696     if (memcmp(msg.mData, &hello, 4) != 0) {
    697         wsLog("Got bad hello from peer\n");
    698         return -1;
    699     }
    700 
    701     Message_release(&msg);
    702 
    703     msg.mType = kTypeRaw;
    704     msg.mData = (unsigned char*) &helloAck;
    705     msg.mLength = 4;
    706 
    707     if (Message_write(&msg, gWrapSim.simulatorFd) != 0) {
    708         wsLog("hello ack write failed\n");
    709         return -1;
    710     }
    711 
    712     return 0;
    713 }
    714 
    715 /*
    716  * Get the sim front-end configuration.  We loop here until the sim claims
    717  * to be done with us.
    718  */
    719 static int getSimConfig(void)
    720 {
    721     Message msg;
    722     int joinNewGroup, grabTerminal, done;
    723     int result = -1;
    724 
    725     joinNewGroup = grabTerminal = done = 0;
    726     Message_clear(&msg);        // clear out msg->mData
    727 
    728     wsLog("+++ awaiting hardware configuration\n");
    729     while (!done) {
    730         if (Message_read(&msg, gWrapSim.simulatorFd) != 0) {
    731             wsLog("failed receiving config from parent\n");
    732             goto bail;
    733         }
    734 
    735         if (msg.mType == kTypeCommand) {
    736             int cmd, arg;
    737 
    738             if (getCommand(&msg, &cmd, &arg) != 0)
    739                 goto bail;
    740 
    741             switch (cmd) {
    742             case kCommandGoAway:
    743                 wsLog("Simulator front-end is busy\n");
    744                 goto bail;
    745             case kCommandNewPGroup:
    746                 joinNewGroup = 1;
    747                 grabTerminal = (arg != 0);
    748                 wsLog("Simulator wants us to be in a new pgrp (term=%d)\n",
    749                     grabTerminal);
    750                 break;
    751             case kCommandConfigDone:
    752                 done = 1;
    753                 break;
    754             default:
    755                 wsLog("Got unexpected command %d/%d\n", cmd, arg);
    756                 break;
    757             }
    758         } else if (msg.mType == kTypeRaw) {
    759             /* assumes 32-bit alignment and identical byte ordering */
    760             int* pData = (int*) msg.mData;
    761             if (msg.mLength >= 4 && *pData == kDisplayConfigMagic) {
    762                 if (handleDisplayConfig(pData, msg.mLength) != 0)
    763                     goto bail;
    764             }
    765         } else if (msg.mType == kTypeConfig) {
    766             const char* name = NULL;
    767             const char* val = NULL;
    768             getConfig(&msg, &name, &val);
    769             if(strcmp(name, "keycharmap") == 0) {
    770                 free((void*)gWrapSim.keyMap);
    771                 gWrapSim.keyMap = strdup(val);
    772             }
    773         } else {
    774             wsLog("Unexpected msg type %d during startup\n", msg.mType);
    775             goto bail;
    776         }
    777 
    778         /* clear out the data field if necessary */
    779         Message_release(&msg);
    780     }
    781 
    782     wsLog("Configuration received from simulator\n");
    783 
    784     if (joinNewGroup) {
    785         /* set pgid to pid */
    786         pid_t pgid = getpid();
    787         setpgid(0, pgid);
    788 
    789         /*
    790          * Put our pgrp in the foreground.
    791          * tcsetpgrp() from background process causes us to get a SIGTTOU,
    792          * which is mostly harmless but makes tcsetpgrp() fail with EINTR.
    793          */
    794         signal(SIGTTOU, SIG_IGN);
    795         if (grabTerminal) {
    796             if (tcsetpgrp(fileno(stdin), getpgrp()) != 0) {
    797                 wsLog("tcsetpgrp(%d, %d) failed (errno=%d)\n",
    798                     fileno(stdin), getpgrp(), errno);
    799             }
    800             wsLog("Set pgrp %d as foreground\n", (int) getpgrp());
    801         }
    802 
    803         /* tell the sim where we're at */
    804         Message msg;
    805         setCommand(&msg, kCommandNewPGroupCreated, pgid);
    806         Message_write(&msg, gWrapSim.simulatorFd);
    807         Message_release(&msg);
    808     }
    809 
    810     result = 0;
    811 
    812 bail:
    813     /* make sure the data was freed */
    814     Message_release(&msg);
    815     //wsLog("bailing, result=%d\n", result);
    816     return result;
    817 }
    818 
    819 /*
    820  * Connect to the simulator and exchange pleasantries.
    821  *
    822  * Returns 0 on success.
    823  */
    824 static int connectToSim(void)
    825 {
    826     if (openSimConnection(kAndroidPipeName) != 0)
    827         return -1;
    828 
    829     if (prepSimConnection() != 0)
    830         return -1;
    831 
    832     if (getSimConfig() != 0)
    833         return -1;
    834 
    835     wsLog("+++ sim is ready to go\n");
    836 
    837     return 0;
    838 }
    839 
    840 /*
    841  * Listen to the sim forever or until the front end shuts down, whichever
    842  * comes first.
    843  *
    844  * All we're really getting here are key events.
    845  */
    846 static void listenToSim(void)
    847 {
    848     wsLog("--- listening for input events from front end\n");
    849 
    850     while (1) {
    851         Message msg;
    852 
    853         Message_clear(&msg);
    854         if (Message_read(&msg, gWrapSim.simulatorFd) != 0) {
    855             wsLog("--- sim message read failed\n");
    856             return;
    857         }
    858 
    859         if (msg.mType == kTypeCommand) {
    860             int cmd, arg;
    861 
    862             if (getCommand(&msg, &cmd, &arg) != 0) {
    863                 wsLog("bad command from sim?\n");
    864                 continue;
    865             }
    866 
    867             switch (cmd) {
    868             case kCommandQuit:
    869                 wsLog("--- sim sent us a QUIT message\n");
    870                 return;
    871             case kCommandKeyDown:
    872                 wsLog("KEY DOWN: %d\n", arg);
    873                 wsSendSimKeyEvent(arg, 1);
    874                 break;
    875             case kCommandKeyUp:
    876                 wsLog("KEY UP: %d\n", arg);
    877                 wsSendSimKeyEvent(arg, 0);
    878                 break;
    879             default:
    880                 wsLog("--- sim sent unrecognized command %d\n", cmd);
    881                 break;
    882             }
    883 
    884             Message_release(&msg);
    885         } else if (msg.mType == kTypeCommandExt) {
    886             int cmd, arg0, arg1, arg2;
    887 
    888             if (getCommandExt(&msg, &cmd, &arg0, &arg1, &arg2) != 0) {
    889                 wsLog("bad ext-command from sim?\n");
    890                 continue;
    891             }
    892 
    893             switch (cmd) {
    894             case kCommandTouch:
    895                 wsSendSimTouchEvent(arg0, arg1, arg2);
    896                 break;
    897             }
    898 
    899             Message_release(&msg);
    900         } else {
    901             wsLog("--- sim sent non-command message, type=%d\n", msg.mType);
    902         }
    903     }
    904 
    905     assert(0);      // not reached
    906 }
    907 
    908 
    909 /*
    910  * Tell the simulator front-end that the display has been updated.
    911  */
    912 void wsPostDisplayUpdate(int displayIdx)
    913 {
    914     if (gWrapSim.simulatorFd < 0) {
    915         wsLog("Not posting display update -- sim not ready\n");
    916         return;
    917     }
    918 
    919     Message msg;
    920 
    921     setCommand(&msg, kCommandUpdateDisplay, displayIdx);
    922     Message_write(&msg, gWrapSim.simulatorFd);
    923     Message_release(&msg);
    924 }
    925 
    926 /*
    927  * Send a log message to the front-end.
    928  */
    929 void wsPostLogMessage(int logPrio, const char* tag, const char* message)
    930 {
    931     if (gWrapSim.simulatorFd < 0) {
    932         wsLog("Not posting log message -- sim not ready\n");
    933         return;
    934     }
    935 
    936     time_t when = time(NULL);
    937     int pid = (int) getpid();
    938     int tagLen, messageLen, totalLen;
    939 
    940     tagLen = strlen(tag) +1;
    941     messageLen = strlen(message) +1;
    942     totalLen = sizeof(int) * 3 + tagLen + messageLen;
    943     unsigned char outBuf[totalLen];
    944     unsigned char* cp = outBuf;
    945 
    946     /* See Message::set/getLogBundle() in simulator/MessageStream.cpp. */
    947     memcpy(cp, &when, sizeof(int));
    948     cp += sizeof(int);
    949     memcpy(cp, &logPrio, sizeof(int));
    950     cp += sizeof(int);
    951     memcpy(cp, &pid, sizeof(int));
    952     cp += sizeof(int);
    953     memcpy(cp, tag, tagLen);
    954     cp += tagLen;
    955     memcpy(cp, message, messageLen);
    956     cp += messageLen;
    957 
    958     assert(cp - outBuf == totalLen);
    959 
    960     Message msg;
    961     msg.mType = kTypeLogBundle;
    962     msg.mData = outBuf;
    963     msg.mLength = totalLen;
    964     Message_write(&msg, gWrapSim.simulatorFd);
    965 
    966     msg.mData = NULL;       // don't free
    967     Message_release(&msg);
    968 }
    969 
    970 /*
    971  * Turn the vibrating notification device on or off.
    972  */
    973 void wsEnableVibration(int vibrateOn)
    974 {
    975     if (gWrapSim.simulatorFd < 0) {
    976         wsLog("Not posting vibrator update -- sim not ready\n");
    977         return;
    978     }
    979 
    980     Message msg;
    981 
    982     //wsLog("+++ sending vibrate:%d\n", vibrateOn);
    983 
    984     setCommand(&msg, kCommandVibrate, vibrateOn);
    985     Message_write(&msg, gWrapSim.simulatorFd);
    986     Message_release(&msg);
    987 }
    988 
    989