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