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