• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
signalMainThread(void)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  */
simThreadEntry(void * arg)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  */
wsSimConnect(void)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  */
Message_clear(Message * msg)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  */
readAll(int fd,void * buf,size_t count)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  */
Message_read(Message * msg,int fd)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  */
Message_write(Message * msg,int fd)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  */
Message_release(Message * msg)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  */
getConfig(const Message * msg,const char ** name,const char ** val)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  */
getCommand(const Message * msg,int * pCmd,int * pArg)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  */
getCommandExt(const Message * msg,int * pCmd,int * pArg0,int * pArg1,int * pArg2)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  */
setCommand(Message * msg,int cmd,int arg)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  */
makeFilename(const char * name)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  */
attachToShmem(int key,int * pShmid,void ** pAddr,long * pLength)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  */
attachToSem(int key,int * pSemid)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  */
adjustSem(int semid,int adj)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  */
wsLockDisplay(int displayIdx)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  */
wsUnlockDisplay(int displayIdx)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  */
handleDisplayConfig(const int * pData,int length)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  */
openSimConnection(const char * name)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  */
prepSimConnection(void)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  */
getSimConfig(void)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  */
connectToSim(void)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  */
listenToSim(void)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  */
wsPostDisplayUpdate(int displayIdx)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  */
wsPostLogMessage(int logPrio,const char * tag,const char * message)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  */
wsEnableVibration(int vibrateOn)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