1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 /* 13 * Android emulator control console 14 * 15 * this console is enabled automatically at emulator startup, on port 5554 by default, 16 * unless some other emulator is already running. See (android_emulation_start in android_sdl.c 17 * for details) 18 * 19 * you can telnet to the console, then use commands like 'help' or others to dynamically 20 * change emulator settings. 21 * 22 */ 23 24 #include "sockets.h" 25 #include "qemu-char.h" 26 #include "sysemu.h" 27 #include "android/android.h" 28 #include "cpu.h" 29 #include "hw/goldfish_device.h" 30 #include "hw/power_supply.h" 31 #include "shaper.h" 32 #include "modem_driver.h" 33 #include "android/gps.h" 34 #include "android/globals.h" 35 #include "android/utils/bufprint.h" 36 #include "android/utils/debug.h" 37 #include "android/utils/stralloc.h" 38 #include "android/config/config.h" 39 #include "tcpdump.h" 40 #include "net.h" 41 #include "monitor.h" 42 43 #include <stdlib.h> 44 #include <stdio.h> 45 #include <stdarg.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <fcntl.h> 49 #include "android/hw-events.h" 50 #include "user-events.h" 51 #include "android/hw-sensors.h" 52 #include "android/keycode-array.h" 53 #include "android/charmap.h" 54 #include "android/display-core.h" 55 #include "android/protocol/fb-updates-proxy.h" 56 #include "android/protocol/user-events-impl.h" 57 #include "android/protocol/ui-commands-api.h" 58 #include "android/protocol/core-commands-impl.h" 59 #include "android/protocol/ui-commands-proxy.h" 60 #include "android/protocol/attach-ui-proxy.h" 61 62 #if defined(CONFIG_SLIRP) 63 #include "libslirp.h" 64 #endif 65 66 #define DEBUG 1 67 68 #if 1 69 # define D_ACTIVE VERBOSE_CHECK(console) 70 #else 71 # define D_ACTIVE DEBUG 72 #endif 73 74 #if DEBUG 75 # define D(x) do { if (D_ACTIVE) ( printf x , fflush(stdout) ); } while (0) 76 #else 77 # define D(x) do{}while(0) 78 #endif 79 80 typedef struct ControlGlobalRec_* ControlGlobal; 81 82 typedef struct ControlClientRec_* ControlClient; 83 84 typedef struct { 85 int host_port; 86 int host_udp; 87 unsigned int guest_ip; 88 int guest_port; 89 } RedirRec, *Redir; 90 91 92 typedef int Socket; 93 94 typedef struct ControlClientRec_ 95 { 96 struct ControlClientRec_* next; /* next client in list */ 97 Socket sock; /* socket used for communication */ 98 ControlGlobal global; 99 char finished; 100 char buff[ 4096 ]; 101 int buff_len; 102 103 } ControlClientRec; 104 105 106 typedef struct ControlGlobalRec_ 107 { 108 /* listening socket */ 109 Socket listen_fd; 110 111 /* the list of current clients */ 112 ControlClient clients; 113 114 /* the list of redirections currently active */ 115 Redir redirs; 116 int num_redirs; 117 int max_redirs; 118 119 } ControlGlobalRec; 120 121 #ifdef CONFIG_STANDALONE_CORE 122 /* UI client currently attached to the core. */ 123 ControlClient attached_ui_client = NULL; 124 125 /* User events service client. */ 126 ControlClient user_events_client = NULL; 127 128 /* UI control service client (UI -> Core). */ 129 ControlClient ui_core_ctl_client = NULL; 130 131 /* UI control service (UI -> Core. */ 132 // CoreUICtl* ui_core_ctl = NULL; 133 134 /* UI control service client (Core-> UI). */ 135 ControlClient core_ui_ctl_client = NULL; 136 #endif // CONFIG_STANDALONE_CORE 137 138 static int 139 control_global_add_redir( ControlGlobal global, 140 int host_port, 141 int host_udp, 142 unsigned int guest_ip, 143 int guest_port ) 144 { 145 Redir redir; 146 147 if (global->num_redirs >= global->max_redirs) 148 { 149 int old_max = global->max_redirs; 150 int new_max = old_max + (old_max >> 1) + 4; 151 152 Redir new_redirs = realloc( global->redirs, new_max*sizeof(global->redirs[0]) ); 153 if (new_redirs == NULL) 154 return -1; 155 156 global->redirs = new_redirs; 157 global->max_redirs = new_max; 158 } 159 160 redir = &global->redirs[ global->num_redirs++ ]; 161 162 redir->host_port = host_port; 163 redir->host_udp = host_udp; 164 redir->guest_ip = guest_ip; 165 redir->guest_port = guest_port; 166 167 return 0; 168 } 169 170 static int 171 control_global_del_redir( ControlGlobal global, 172 int host_port, 173 int host_udp ) 174 { 175 int nn; 176 177 for (nn = 0; nn < global->num_redirs; nn++) 178 { 179 Redir redir = &global->redirs[nn]; 180 181 if ( redir->host_port == host_port && 182 redir->host_udp == host_udp ) 183 { 184 memmove( redir, redir + 1, ((global->num_redirs - nn)-1)*sizeof(*redir) ); 185 global->num_redirs -= 1; 186 return 0; 187 } 188 } 189 /* we didn't find it */ 190 return -1; 191 } 192 193 /* Detach the socket descriptor from a given ControlClient 194 * and return its value. This is useful either when destroying 195 * the client, or redirecting the socket to another service. 196 * 197 * NOTE: this does not close the socket. 198 */ 199 static int 200 control_client_detach( ControlClient client ) 201 { 202 int result; 203 204 if (client->sock < 0) 205 return -1; 206 207 qemu_set_fd_handler( client->sock, NULL, NULL, NULL ); 208 result = client->sock; 209 client->sock = -1; 210 211 return result; 212 } 213 214 static void control_client_read( void* _client ); /* forward */ 215 216 /* Reattach a control client to a given socket. 217 * Return the old socket descriptor for the client. 218 */ 219 static int 220 control_client_reattach( ControlClient client, int fd ) 221 { 222 int result = control_client_detach(client); 223 client->sock = fd; 224 qemu_set_fd_handler( fd, control_client_read, NULL, client ); 225 return result; 226 } 227 228 static void 229 control_client_destroy( ControlClient client ) 230 { 231 ControlGlobal global = client->global; 232 ControlClient *pnode = &global->clients; 233 int sock; 234 235 D(( "destroying control client %p\n", client )); 236 237 #ifdef CONFIG_STANDALONE_CORE 238 if (client == attached_ui_client) { 239 attachUiProxy_destroy(); 240 attached_ui_client = NULL; 241 } 242 243 if (client == user_events_client) { 244 userEventsImpl_destroy(); 245 user_events_client = NULL; 246 } 247 248 if (client == ui_core_ctl_client) { 249 coreCmdImpl_destroy(); 250 ui_core_ctl_client = NULL; 251 } 252 253 if (client == core_ui_ctl_client) { 254 uiCmdProxy_destroy(); 255 core_ui_ctl_client = NULL; 256 } 257 #endif // CONFIG_STANDALONE_CORE 258 259 sock = control_client_detach( client ); 260 if (sock >= 0) 261 socket_close(sock); 262 263 for ( ;; ) { 264 ControlClient node = *pnode; 265 if ( node == NULL ) 266 break; 267 if ( node == client ) { 268 *pnode = node->next; 269 node->next = NULL; 270 break; 271 } 272 pnode = &node->next; 273 } 274 275 free( client ); 276 } 277 278 279 280 static void control_control_write( ControlClient client, const char* buff, int len ) 281 { 282 int ret; 283 284 if (len < 0) 285 len = strlen(buff); 286 287 while (len > 0) { 288 ret = socket_send( client->sock, buff, len); 289 if (ret < 0) { 290 if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN) 291 return; 292 } else { 293 buff += ret; 294 len -= ret; 295 } 296 } 297 } 298 299 static int control_vwrite( ControlClient client, const char* format, va_list args ) 300 { 301 static char temp[1024]; 302 int ret = vsnprintf( temp, sizeof(temp), format, args ); 303 temp[ sizeof(temp)-1 ] = 0; 304 control_control_write( client, temp, -1 ); 305 306 return ret; 307 } 308 309 static int control_write( ControlClient client, const char* format, ... ) 310 { 311 int ret; 312 va_list args; 313 va_start(args, format); 314 ret = control_vwrite(client, format, args); 315 va_end(args); 316 317 return ret; 318 } 319 320 321 static ControlClient 322 control_client_create( Socket socket, 323 ControlGlobal global ) 324 { 325 ControlClient client = calloc( sizeof(*client), 1 ); 326 327 if (client) { 328 socket_set_nodelay( socket ); 329 socket_set_nonblock( socket ); 330 client->finished = 0; 331 client->global = global; 332 client->sock = socket; 333 client->next = global->clients; 334 global->clients = client; 335 336 qemu_set_fd_handler( socket, control_client_read, NULL, client ); 337 } 338 return client; 339 } 340 341 typedef const struct CommandDefRec_ *CommandDef; 342 343 typedef struct CommandDefRec_ { 344 const char* names; 345 const char* abstract; 346 const char* description; 347 void (*descriptor)( ControlClient client ); 348 int (*handler)( ControlClient client, char* args ); 349 CommandDef subcommands; /* if handler is NULL */ 350 351 } CommandDefRec; 352 353 static const CommandDefRec main_commands[]; /* forward */ 354 355 static CommandDef 356 find_command( char* input, CommandDef commands, char* *pend, char* *pargs ) 357 { 358 int nn; 359 char* args = strchr(input, ' '); 360 361 if (args != NULL) { 362 while (*args == ' ') 363 args++; 364 365 if (args[0] == 0) 366 args = NULL; 367 } 368 369 for (nn = 0; commands[nn].names != NULL; nn++) 370 { 371 const char* name = commands[nn].names; 372 const char* sep; 373 374 do { 375 int len, c; 376 377 sep = strchr( name, '|' ); 378 if (sep) 379 len = sep - name; 380 else 381 len = strlen(name); 382 383 c = input[len]; 384 if ( !memcmp( name, input, len ) && (c == ' ' || c == 0) ) { 385 *pend = input + len; 386 *pargs = args; 387 return &commands[nn]; 388 } 389 390 if (sep) 391 name = sep + 1; 392 393 } while (sep != NULL && *name); 394 } 395 /* NOTE: don't touch *pend and *pargs if no command is found */ 396 return NULL; 397 } 398 399 static void 400 dump_help( ControlClient client, 401 CommandDef cmd, 402 const char* prefix ) 403 { 404 if (cmd->description) { 405 control_write( client, "%s", cmd->description ); 406 } else if (cmd->descriptor) { 407 cmd->descriptor( client ); 408 } else 409 control_write( client, "%s\r\n", cmd->abstract ); 410 411 if (cmd->subcommands) { 412 cmd = cmd->subcommands; 413 control_write( client, "\r\navailable sub-commands:\r\n" ); 414 for ( ; cmd->names != NULL; cmd++ ) { 415 control_write( client, " %s %-15s %s\r\n", prefix, cmd->names, cmd->abstract ); 416 } 417 control_write( client, "\r\n" ); 418 } 419 } 420 421 static void 422 control_client_do_command( ControlClient client ) 423 { 424 char* line = client->buff; 425 char* args = NULL; 426 CommandDef commands = main_commands; 427 char* cmdend = client->buff; 428 CommandDef cmd = find_command( line, commands, &cmdend, &args ); 429 430 if (cmd == NULL) { 431 control_write( client, "KO: unknown command, try 'help'\r\n" ); 432 return; 433 } 434 435 for (;;) { 436 CommandDef subcmd; 437 438 if (cmd->handler) { 439 if ( !cmd->handler( client, args ) ) { 440 control_write( client, "OK\r\n" ); 441 } 442 break; 443 } 444 445 /* no handler means we should have sub-commands */ 446 if (cmd->subcommands == NULL) { 447 control_write( client, "KO: internal error: buggy command table for '%.*s'\r\n", 448 cmdend - client->buff, client->buff ); 449 break; 450 } 451 452 /* we need a sub-command here */ 453 if ( !args ) { 454 dump_help( client, cmd, "" ); 455 control_write( client, "KO: missing sub-command\r\n" ); 456 break; 457 } 458 459 line = args; 460 commands = cmd->subcommands; 461 subcmd = find_command( line, commands, &cmdend, &args ); 462 if (subcmd == NULL) { 463 dump_help( client, cmd, "" ); 464 control_write( client, "KO: bad sub-command\r\n" ); 465 break; 466 } 467 cmd = subcmd; 468 } 469 } 470 471 /* implement the 'help' command */ 472 static int 473 do_help( ControlClient client, char* args ) 474 { 475 char* line; 476 char* start = args; 477 char* end = start; 478 CommandDef cmd = main_commands; 479 480 /* without arguments, simply dump all commands */ 481 if (args == NULL) { 482 control_write( client, "Android console command help:\r\n\r\n" ); 483 for ( ; cmd->names != NULL; cmd++ ) { 484 control_write( client, " %-15s %s\r\n", cmd->names, cmd->abstract ); 485 } 486 control_write( client, "\r\ntry 'help <command>' for command-specific help\r\n" ); 487 return 0; 488 } 489 490 /* with an argument, find the corresponding command */ 491 for (;;) { 492 CommandDef subcmd; 493 494 line = args; 495 subcmd = find_command( line, cmd, &end, &args ); 496 if (subcmd == NULL) { 497 control_write( client, "try one of these instead:\r\n\r\n" ); 498 for ( ; cmd->names != NULL; cmd++ ) { 499 control_write( client, " %.*s %s\r\n", 500 end - start, start, cmd->names ); 501 } 502 control_write( client, "\r\nKO: unknown command\r\n" ); 503 return -1; 504 } 505 506 if ( !args || !subcmd->subcommands ) { 507 dump_help( client, subcmd, start ); 508 return 0; 509 } 510 cmd = subcmd->subcommands; 511 } 512 } 513 514 515 static void 516 control_client_read_byte( ControlClient client, unsigned char ch ) 517 { 518 if (ch == '\r') 519 { 520 /* filter them out */ 521 } 522 else if (ch == '\n') 523 { 524 client->buff[ client->buff_len ] = 0; 525 control_client_do_command( client ); 526 if (client->finished) 527 return; 528 529 client->buff_len = 0; 530 } 531 else 532 { 533 if (client->buff_len >= sizeof(client->buff)-1) 534 client->buff_len = 0; 535 536 client->buff[ client->buff_len++ ] = ch; 537 } 538 } 539 540 static void 541 control_client_read( void* _client ) 542 { 543 ControlClient client = _client; 544 unsigned char buf[4096]; 545 int size; 546 547 D(( "in control_client read: " )); 548 size = socket_recv( client->sock, buf, sizeof(buf) ); 549 if (size < 0) { 550 D(( "size < 0, exiting with %d: %s\n", errno, errno_str )); 551 if (errno != EWOULDBLOCK && errno != EAGAIN) 552 control_client_destroy( client ); 553 return; 554 } 555 556 if (size == 0) { 557 /* end of connection */ 558 D(( "end of connection detected !!\n" )); 559 control_client_destroy( client ); 560 } 561 else { 562 int nn; 563 #ifdef _WIN32 564 # if DEBUG 565 char temp[16]; 566 int count = size > sizeof(temp)-1 ? sizeof(temp)-1 : size; 567 for (nn = 0; nn < count; nn++) { 568 int c = buf[nn]; 569 if (c == '\n') 570 temp[nn] = '!'; 571 else if (c < 32) 572 temp[nn] = '.'; 573 else 574 temp[nn] = (char)c; 575 } 576 temp[nn] = 0; 577 D(( "received %d bytes: %s\n", size, temp )); 578 # endif 579 #else 580 D(( "received %.*s\n", size, buf )); 581 #endif 582 for (nn = 0; nn < size; nn++) { 583 control_client_read_byte( client, buf[nn] ); 584 if (client->finished) { 585 control_client_destroy(client); 586 return; 587 } 588 } 589 } 590 } 591 592 593 /* this function is called on each new client connection */ 594 static void 595 control_global_accept( void* _global ) 596 { 597 ControlGlobal global = _global; 598 ControlClient client; 599 Socket fd; 600 601 D(( "control_global_accept: just in (fd=%d)\n", global->listen_fd )); 602 603 for(;;) { 604 fd = socket_accept( global->listen_fd, NULL ); 605 if (fd < 0 && errno != EINTR) { 606 D(( "problem in accept: %d: %s\n", errno, errno_str )); 607 perror("accept"); 608 return; 609 } else if (fd >= 0) { 610 break; 611 } 612 D(( "relooping in accept()\n" )); 613 } 614 615 socket_set_xreuseaddr( fd ); 616 617 D(( "control_global_accept: creating new client\n" )); 618 client = control_client_create( fd, global ); 619 if (client) { 620 D(( "control_global_accept: new client %p\n", client )); 621 control_write( client, "Android Console: type 'help' for a list of commands\r\n" ); 622 control_write( client, "OK\r\n" ); 623 } 624 } 625 626 627 static int 628 control_global_init( ControlGlobal global, 629 int control_port ) 630 { 631 Socket fd; 632 int ret; 633 SockAddress sockaddr; 634 635 memset( global, 0, sizeof(*global) ); 636 637 fd = socket_create_inet( SOCKET_STREAM ); 638 if (fd < 0) { 639 perror("socket"); 640 return -1; 641 } 642 643 socket_set_xreuseaddr( fd ); 644 645 sock_address_init_inet( &sockaddr, SOCK_ADDRESS_INET_LOOPBACK, control_port ); 646 647 ret = socket_bind(fd, &sockaddr ); 648 if (ret < 0) { 649 perror("bind"); 650 socket_close( fd ); 651 return -1; 652 } 653 654 ret = socket_listen(fd, 0); 655 if (ret < 0) { 656 perror("listen"); 657 socket_close( fd ); 658 return -1; 659 } 660 661 socket_set_nonblock(fd); 662 663 global->listen_fd = fd; 664 665 qemu_set_fd_handler( fd, control_global_accept, NULL, global ); 666 return 0; 667 } 668 669 670 671 static int 672 do_quit( ControlClient client, char* args ) 673 { 674 client->finished = 1; 675 return -1; 676 } 677 678 /********************************************************************************************/ 679 /********************************************************************************************/ 680 /***** ******/ 681 /***** N E T W O R K S E T T I N G S ******/ 682 /***** ******/ 683 /********************************************************************************************/ 684 /********************************************************************************************/ 685 686 static int 687 do_network_status( ControlClient client, char* args ) 688 { 689 control_write( client, "Current network status:\r\n" ); 690 691 control_write( client, " download speed: %8d bits/s (%.1f KB/s)\r\n", 692 (long)qemu_net_download_speed, qemu_net_download_speed/8192. ); 693 694 control_write( client, " upload speed: %8d bits/s (%.1f KB/s)\r\n", 695 (long)qemu_net_upload_speed, qemu_net_upload_speed/8192. ); 696 697 control_write( client, " minimum latency: %ld ms\r\n", qemu_net_min_latency ); 698 control_write( client, " maximum latency: %ld ms\r\n", qemu_net_max_latency ); 699 return 0; 700 } 701 702 static void 703 dump_network_speeds( ControlClient client ) 704 { 705 const NetworkSpeed* speed = android_netspeeds; 706 const char* const format = " %-8s %s\r\n"; 707 for ( ; speed->name; speed++ ) { 708 control_write( client, format, speed->name, speed->display ); 709 } 710 control_write( client, format, "<num>", "selects both upload and download speed" ); 711 control_write( client, format, "<up>:<down>", "select individual upload/download speeds" ); 712 } 713 714 715 static int 716 do_network_speed( ControlClient client, char* args ) 717 { 718 if ( !args ) { 719 control_write( client, "KO: missing <speed> argument, see 'help network speed'\r\n" ); 720 return -1; 721 } 722 if ( android_parse_network_speed( args ) < 0 ) { 723 control_write( client, "KO: invalid <speed> argument, see 'help network speed' for valid values\r\n" ); 724 return -1; 725 } 726 727 netshaper_set_rate( slirp_shaper_in, qemu_net_download_speed ); 728 netshaper_set_rate( slirp_shaper_out, qemu_net_upload_speed ); 729 730 if (android_modem) { 731 amodem_set_data_network_type( android_modem, 732 android_parse_network_type( args ) ); 733 } 734 return 0; 735 } 736 737 static void 738 describe_network_speed( ControlClient client ) 739 { 740 control_write( client, 741 "'network speed <speed>' allows you to dynamically change the speed of the emulated\r\n" 742 "network on the device, where <speed> is one of the following:\r\n\r\n" ); 743 dump_network_speeds( client ); 744 } 745 746 static int 747 do_network_delay( ControlClient client, char* args ) 748 { 749 if ( !args ) { 750 control_write( client, "KO: missing <delay> argument, see 'help network delay'\r\n" ); 751 return -1; 752 } 753 if ( android_parse_network_latency( args ) < 0 ) { 754 control_write( client, "KO: invalid <delay> argument, see 'help network delay' for valid values\r\n" ); 755 return -1; 756 } 757 netdelay_set_latency( slirp_delay_in, qemu_net_min_latency, qemu_net_max_latency ); 758 return 0; 759 } 760 761 static void 762 describe_network_delay( ControlClient client ) 763 { 764 control_write( client, 765 "'network delay <latency>' allows you to dynamically change the latency of the emulated\r\n" 766 "network on the device, where <latency> is one of the following:\r\n\r\n" ); 767 /* XXX: TODO */ 768 } 769 770 static int 771 do_network_capture_start( ControlClient client, char* args ) 772 { 773 if ( !args ) { 774 control_write( client, "KO: missing <file> argument, see 'help network capture start'\r\n" ); 775 return -1; 776 } 777 if ( qemu_tcpdump_start(args) < 0) { 778 control_write( client, "KO: could not start capture: %s", strerror(errno) ); 779 return -1; 780 } 781 return 0; 782 } 783 784 static int 785 do_network_capture_stop( ControlClient client, char* args ) 786 { 787 /* no need to return an error here */ 788 qemu_tcpdump_stop(); 789 return 0; 790 } 791 792 static const CommandDefRec network_capture_commands[] = 793 { 794 { "start", "start network capture", 795 "'network capture start <file>' starts a new capture of network packets\r\n" 796 "into a specific <file>. This will stop any capture already in progress.\r\n" 797 "the capture file can later be analyzed by tools like WireShark. It uses\r\n" 798 "the libpcap file format.\r\n\r\n" 799 "you can stop the capture anytime with 'network capture stop'\r\n", NULL, 800 do_network_capture_start, NULL }, 801 802 { "stop", "stop network capture", 803 "'network capture stop' stops a currently running packet capture, if any.\r\n" 804 "you can start one with 'network capture start <file>'\r\n", NULL, 805 do_network_capture_stop, NULL }, 806 807 { NULL, NULL, NULL, NULL, NULL, NULL } 808 }; 809 810 static const CommandDefRec network_commands[] = 811 { 812 { "status", "dump network status", NULL, NULL, 813 do_network_status, NULL }, 814 815 { "speed", "change network speed", NULL, describe_network_speed, 816 do_network_speed, NULL }, 817 818 { "delay", "change network latency", NULL, describe_network_delay, 819 do_network_delay, NULL }, 820 821 { "capture", "dump network packets to file", 822 "allows to start/stop capture of network packets to a file for later analysis\r\n", NULL, 823 NULL, network_capture_commands }, 824 825 { NULL, NULL, NULL, NULL, NULL, NULL } 826 }; 827 828 /********************************************************************************************/ 829 /********************************************************************************************/ 830 /***** ******/ 831 /***** P O R T R E D I R E C T I O N S ******/ 832 /***** ******/ 833 /********************************************************************************************/ 834 /********************************************************************************************/ 835 836 static int 837 do_redir_list( ControlClient client, char* args ) 838 { 839 ControlGlobal global = client->global; 840 841 if (global->num_redirs == 0) 842 control_write( client, "no active redirections\r\n" ); 843 else { 844 int nn; 845 for (nn = 0; nn < global->num_redirs; nn++) { 846 Redir redir = &global->redirs[nn]; 847 control_write( client, "%s:%-5d => %-5d\r\n", 848 redir->host_udp ? "udp" : "tcp", 849 redir->host_port, 850 redir->guest_port ); 851 } 852 } 853 return 0; 854 } 855 856 /* parse a protocol:port specification */ 857 static int 858 redir_parse_proto_port( char* args, int *pport, int *pproto ) 859 { 860 int proto = -1; 861 int len = 0; 862 char* end; 863 864 if ( !memcmp( args, "tcp:", 4 ) ) { 865 proto = 0; 866 len = 4; 867 } 868 else if ( !memcmp( args, "udp:", 4 ) ) { 869 proto = 1; 870 len = 4; 871 } 872 else 873 return 0; 874 875 args += len; 876 *pproto = proto; 877 *pport = strtol( args, &end, 10 ); 878 if (end == args) 879 return 0; 880 881 len += end - args; 882 return len; 883 } 884 885 static int 886 redir_parse_guest_port( char* arg, int *pport ) 887 { 888 char* end; 889 890 *pport = strtoul( arg, &end, 10 ); 891 if (end == arg) 892 return 0; 893 894 return end - arg; 895 } 896 897 static Redir 898 redir_find( ControlGlobal global, int port, int isudp ) 899 { 900 int nn; 901 902 for (nn = 0; nn < global->num_redirs; nn++) { 903 Redir redir = &global->redirs[nn]; 904 905 if (redir->host_port == port && redir->host_udp == isudp) 906 return redir; 907 } 908 return NULL; 909 } 910 911 912 static int 913 do_redir_add( ControlClient client, char* args ) 914 { 915 int len, host_proto, host_port, guest_port; 916 uint32_t guest_ip; 917 Redir redir; 918 919 if ( !args ) 920 goto BadFormat; 921 922 if (!slirp_is_inited()) { 923 control_write( client, "KO: network emulation disabled\r\n"); 924 return -1; 925 } 926 927 len = redir_parse_proto_port( args, &host_port, &host_proto ); 928 if (len == 0 || args[len] != ':') 929 goto BadFormat; 930 931 args += len + 1; 932 len = redir_parse_guest_port( args, &guest_port ); 933 if (len == 0 || args[len] != 0) 934 goto BadFormat; 935 936 redir = redir_find( client->global, host_port, host_proto ); 937 if ( redir != NULL ) { 938 control_write( client, "KO: host port already active, use 'redir del' to remove first\r\n" ); 939 return -1; 940 } 941 942 if (inet_strtoip("10.0.2.15", &guest_ip) < 0) { 943 control_write( client, "KO: unexpected internal failure when resolving 10.0.2.15\r\n" ); 944 return -1; 945 } 946 947 D(("pattern hport=%d gport=%d proto=%d\n", host_port, guest_port, host_proto )); 948 if ( control_global_add_redir( client->global, host_port, host_proto, 949 guest_ip, guest_port ) < 0 ) 950 { 951 control_write( client, "KO: not enough memory to allocate redirection\r\n" ); 952 return -1; 953 } 954 955 if (slirp_redir(host_proto, host_port, guest_ip, guest_port) < 0) { 956 control_write( client, "KO: can't setup redirection, port probably used by another program on host\r\n" ); 957 control_global_del_redir( client->global, host_port, host_proto ); 958 return -1; 959 } 960 961 return 0; 962 963 BadFormat: 964 control_write( client, "KO: bad redirection format, try (tcp|udp):hostport:guestport\r\n", -1 ); 965 return -1; 966 } 967 968 969 static int 970 do_redir_del( ControlClient client, char* args ) 971 { 972 int len, proto, port; 973 Redir redir; 974 975 if ( !args ) 976 goto BadFormat; 977 len = redir_parse_proto_port( args, &port, &proto ); 978 if ( len == 0 || args[len] != 0 ) 979 goto BadFormat; 980 981 redir = redir_find( client->global, port, proto ); 982 if (redir == NULL) { 983 control_write( client, "KO: can't remove unknown redirection (%s:%d)\r\n", 984 proto ? "udp" : "tcp", port ); 985 return -1; 986 } 987 988 slirp_unredir( redir->host_udp, redir->host_port ); 989 control_global_del_redir( client->global, port, proto );\ 990 991 return 0; 992 993 BadFormat: 994 control_write( client, "KO: bad redirection format, try (tcp|udp):hostport\r\n" ); 995 return -1; 996 } 997 998 static const CommandDefRec redir_commands[] = 999 { 1000 { "list", "list current redirections", 1001 "list current port redirections. use 'redir add' and 'redir del' to add and remove them\r\n", NULL, 1002 do_redir_list, NULL }, 1003 1004 { "add", "add new redirection", 1005 "add a new port redirection, arguments must be:\r\n\r\n" 1006 " redir add <protocol>:<host-port>:<guest-port>\r\n\r\n" 1007 "where: <protocol> is either 'tcp' or 'udp'\r\n" 1008 " <host-port> a number indicating which port on the host to open\r\n" 1009 " <guest-port> a number indicating which port to route to on the device\r\n" 1010 "\r\nas an example, 'redir tcp:5000:6000' will allow any packets sent to\r\n" 1011 "the host's TCP port 5000 to be routed to TCP port 6000 of the emulated device\r\n", NULL, 1012 do_redir_add, NULL }, 1013 1014 { "del", "remove existing redirection", 1015 "remove a port redirecion that was created with 'redir add', arguments must be:\r\n\r\n" 1016 " redir del <protocol>:<host-port>\r\n\r\n" 1017 "see the 'help redir add' for the meaning of <protocol> and <host-port>\r\n", NULL, 1018 do_redir_del, NULL }, 1019 1020 { NULL, NULL, NULL, NULL, NULL, NULL } 1021 }; 1022 1023 1024 1025 /********************************************************************************************/ 1026 /********************************************************************************************/ 1027 /***** ******/ 1028 /***** C D M A M O D E M ******/ 1029 /***** ******/ 1030 /********************************************************************************************/ 1031 /********************************************************************************************/ 1032 1033 static const struct { 1034 const char * name; 1035 const char * display; 1036 ACdmaSubscriptionSource source; 1037 } _cdma_subscription_sources[] = { 1038 { "nv", "Read subscription from non-volatile RAM", A_SUBSCRIPTION_NVRAM }, 1039 { "ruim", "Read subscription from RUIM", A_SUBSCRIPTION_RUIM }, 1040 }; 1041 1042 static void 1043 dump_subscription_sources( ControlClient client ) 1044 { 1045 int i; 1046 for (i = 0; 1047 i < sizeof(_cdma_subscription_sources) / sizeof(_cdma_subscription_sources[0]); 1048 i++) { 1049 control_write( client, " %s: %s\r\n", 1050 _cdma_subscription_sources[i].name, 1051 _cdma_subscription_sources[i].display ); 1052 } 1053 } 1054 1055 static void 1056 describe_subscription_source( ControlClient client ) 1057 { 1058 control_write( client, 1059 "'cdma ssource <ssource>' allows you to specify where to read the subscription from\r\n" ); 1060 dump_subscription_sources( client ); 1061 } 1062 1063 static int 1064 do_cdma_ssource( ControlClient client, char* args ) 1065 { 1066 int nn; 1067 if (!args) { 1068 control_write( client, "KO: missing argument, try 'cdma ssource <source>'\r\n" ); 1069 return -1; 1070 } 1071 1072 for (nn = 0; ; nn++) { 1073 const char* name = _cdma_subscription_sources[nn].name; 1074 ACdmaSubscriptionSource ssource = _cdma_subscription_sources[nn].source; 1075 1076 if (!name) 1077 break; 1078 1079 if (!strcasecmp( args, name )) { 1080 amodem_set_cdma_subscription_source( android_modem, ssource ); 1081 return 0; 1082 } 1083 } 1084 control_write( client, "KO: Don't know source %s\r\n", args ); 1085 return -1; 1086 } 1087 1088 static int 1089 do_cdma_prl_version( ControlClient client, char * args ) 1090 { 1091 int version = 0; 1092 char *endptr; 1093 1094 if (!args) { 1095 control_write( client, "KO: missing argument, try 'cdma prl_version <version>'\r\n"); 1096 return -1; 1097 } 1098 1099 version = strtol(args, &endptr, 0); 1100 if (endptr != args) { 1101 amodem_set_cdma_prl_version( android_modem, version ); 1102 } 1103 return 0; 1104 } 1105 /********************************************************************************************/ 1106 /********************************************************************************************/ 1107 /***** ******/ 1108 /***** G S M M O D E M ******/ 1109 /***** ******/ 1110 /********************************************************************************************/ 1111 /********************************************************************************************/ 1112 1113 static const struct { 1114 const char* name; 1115 const char* display; 1116 ARegistrationState state; 1117 } _gsm_states[] = { 1118 { "unregistered", "no network available", A_REGISTRATION_UNREGISTERED }, 1119 { "home", "on local network, non-roaming", A_REGISTRATION_HOME }, 1120 { "roaming", "on roaming network", A_REGISTRATION_ROAMING }, 1121 { "searching", "searching networks", A_REGISTRATION_SEARCHING }, 1122 { "denied", "emergency calls only", A_REGISTRATION_DENIED }, 1123 { "off", "same as 'unregistered'", A_REGISTRATION_UNREGISTERED }, 1124 { "on", "same as 'home'", A_REGISTRATION_HOME }, 1125 { NULL, NULL, A_REGISTRATION_UNREGISTERED } 1126 }; 1127 1128 static const char* 1129 gsm_state_to_string( ARegistrationState state ) 1130 { 1131 int nn; 1132 for (nn = 0; _gsm_states[nn].name != NULL; nn++) { 1133 if (state == _gsm_states[nn].state) 1134 return _gsm_states[nn].name; 1135 } 1136 return "<unknown>"; 1137 } 1138 1139 static int 1140 do_gsm_status( ControlClient client, char* args ) 1141 { 1142 if (args) { 1143 control_write( client, "KO: no argument required\r\n" ); 1144 return -1; 1145 } 1146 if (!android_modem) { 1147 control_write( client, "KO: modem emulation not running\r\n" ); 1148 return -1; 1149 } 1150 control_write( client, "gsm voice state: %s\r\n", 1151 gsm_state_to_string( 1152 amodem_get_voice_registration(android_modem) ) ); 1153 control_write( client, "gsm data state: %s\r\n", 1154 gsm_state_to_string( 1155 amodem_get_data_registration(android_modem) ) ); 1156 return 0; 1157 } 1158 1159 1160 static void 1161 help_gsm_data( ControlClient client ) 1162 { 1163 int nn; 1164 control_write( client, 1165 "the 'gsm data <state>' allows you to change the state of your GPRS connection\r\n" 1166 "valid values for <state> are the following:\r\n\r\n" ); 1167 for (nn = 0; ; nn++) { 1168 const char* name = _gsm_states[nn].name; 1169 const char* display = _gsm_states[nn].display; 1170 1171 if (!name) 1172 break; 1173 1174 control_write( client, " %-15s %s\r\n", name, display ); 1175 } 1176 control_write( client, "\r\n" ); 1177 } 1178 1179 1180 static int 1181 do_gsm_data( ControlClient client, char* args ) 1182 { 1183 int nn; 1184 1185 if (!args) { 1186 control_write( client, "KO: missing argument, try 'gsm data <state>'\r\n" ); 1187 return -1; 1188 } 1189 1190 for (nn = 0; ; nn++) { 1191 const char* name = _gsm_states[nn].name; 1192 ARegistrationState state = _gsm_states[nn].state; 1193 1194 if (!name) 1195 break; 1196 1197 if ( !strcmp( args, name ) ) { 1198 if (!android_modem) { 1199 control_write( client, "KO: modem emulation not running\r\n" ); 1200 return -1; 1201 } 1202 amodem_set_data_registration( android_modem, state ); 1203 qemu_net_disable = (state != A_REGISTRATION_HOME && 1204 state != A_REGISTRATION_ROAMING ); 1205 return 0; 1206 } 1207 } 1208 control_write( client, "KO: bad GSM data state name, try 'help gsm data' for list of valid values\r\n" ); 1209 return -1; 1210 } 1211 1212 static void 1213 help_gsm_voice( ControlClient client ) 1214 { 1215 int nn; 1216 control_write( client, 1217 "the 'gsm voice <state>' allows you to change the state of your GPRS connection\r\n" 1218 "valid values for <state> are the following:\r\n\r\n" ); 1219 for (nn = 0; ; nn++) { 1220 const char* name = _gsm_states[nn].name; 1221 const char* display = _gsm_states[nn].display; 1222 1223 if (!name) 1224 break; 1225 1226 control_write( client, " %-15s %s\r\n", name, display ); 1227 } 1228 control_write( client, "\r\n" ); 1229 } 1230 1231 1232 static int 1233 do_gsm_voice( ControlClient client, char* args ) 1234 { 1235 int nn; 1236 1237 if (!args) { 1238 control_write( client, "KO: missing argument, try 'gsm voice <state>'\r\n" ); 1239 return -1; 1240 } 1241 1242 for (nn = 0; ; nn++) { 1243 const char* name = _gsm_states[nn].name; 1244 ARegistrationState state = _gsm_states[nn].state; 1245 1246 if (!name) 1247 break; 1248 1249 if ( !strcmp( args, name ) ) { 1250 if (!android_modem) { 1251 control_write( client, "KO: modem emulation not running\r\n" ); 1252 return -1; 1253 } 1254 amodem_set_voice_registration( android_modem, state ); 1255 return 0; 1256 } 1257 } 1258 control_write( client, "KO: bad GSM data state name, try 'help gsm voice' for list of valid values\r\n" ); 1259 return -1; 1260 } 1261 1262 1263 static int 1264 gsm_check_number( char* args ) 1265 { 1266 int nn; 1267 1268 for (nn = 0; args[nn] != 0; nn++) { 1269 int c = args[nn]; 1270 if ( !isdigit(c) && c != '+' && c != '#' ) { 1271 return -1; 1272 } 1273 } 1274 if (nn == 0) 1275 return -1; 1276 1277 return 0; 1278 } 1279 1280 static int 1281 do_gsm_call( ControlClient client, char* args ) 1282 { 1283 /* check that we have a phone number made of digits */ 1284 if (!args) { 1285 control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" ); 1286 return -1; 1287 } 1288 1289 if (gsm_check_number(args)) { 1290 control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" ); 1291 return -1; 1292 } 1293 1294 if (!android_modem) { 1295 control_write( client, "KO: modem emulation not running\r\n" ); 1296 return -1; 1297 } 1298 amodem_add_inbound_call( android_modem, args ); 1299 return 0; 1300 } 1301 1302 static int 1303 do_gsm_cancel( ControlClient client, char* args ) 1304 { 1305 if (!args) { 1306 control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" ); 1307 return -1; 1308 } 1309 if (gsm_check_number(args)) { 1310 control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" ); 1311 return -1; 1312 } 1313 if (!android_modem) { 1314 control_write( client, "KO: modem emulation not running\r\n" ); 1315 return -1; 1316 } 1317 if ( amodem_disconnect_call( android_modem, args ) < 0 ) { 1318 control_write( client, "KO: could not cancel this number\r\n" ); 1319 return -1; 1320 } 1321 return 0; 1322 } 1323 1324 1325 static const char* 1326 call_state_to_string( ACallState state ) 1327 { 1328 switch (state) { 1329 case A_CALL_ACTIVE: return "active"; 1330 case A_CALL_HELD: return "held"; 1331 case A_CALL_ALERTING: return "ringing"; 1332 case A_CALL_WAITING: return "waiting"; 1333 case A_CALL_INCOMING: return "incoming"; 1334 default: return "unknown"; 1335 } 1336 } 1337 1338 static int 1339 do_gsm_list( ControlClient client, char* args ) 1340 { 1341 /* check that we have a phone number made of digits */ 1342 int count = amodem_get_call_count( android_modem ); 1343 int nn; 1344 for (nn = 0; nn < count; nn++) { 1345 ACall call = amodem_get_call( android_modem, nn ); 1346 const char* dir; 1347 1348 if (call == NULL) 1349 continue; 1350 1351 if (call->dir == A_CALL_OUTBOUND) 1352 dir = "outbound to "; 1353 else 1354 dir = "inbound from"; 1355 1356 control_write( client, "%s %-10s : %s\r\n", dir, 1357 call->number, call_state_to_string(call->state) ); 1358 } 1359 return 0; 1360 } 1361 1362 static int 1363 do_gsm_busy( ControlClient client, char* args ) 1364 { 1365 ACall call; 1366 1367 if (!args) { 1368 control_write( client, "KO: missing argument, try 'gsm busy <phonenumber>'\r\n" ); 1369 return -1; 1370 } 1371 call = amodem_find_call_by_number( android_modem, args ); 1372 if (call == NULL || call->dir != A_CALL_OUTBOUND) { 1373 control_write( client, "KO: no current outbound call to number '%s' (call %p)\r\n", args, call ); 1374 return -1; 1375 } 1376 if ( amodem_disconnect_call( android_modem, args ) < 0 ) { 1377 control_write( client, "KO: could not cancel this number\r\n" ); 1378 return -1; 1379 } 1380 return 0; 1381 } 1382 1383 static int 1384 do_gsm_hold( ControlClient client, char* args ) 1385 { 1386 ACall call; 1387 1388 if (!args) { 1389 control_write( client, "KO: missing argument, try 'gsm out hold <phonenumber>'\r\n" ); 1390 return -1; 1391 } 1392 call = amodem_find_call_by_number( android_modem, args ); 1393 if (call == NULL) { 1394 control_write( client, "KO: no current call to/from number '%s'\r\n", args ); 1395 return -1; 1396 } 1397 if ( amodem_update_call( android_modem, args, A_CALL_HELD ) < 0 ) { 1398 control_write( client, "KO: could put this call on hold\r\n" ); 1399 return -1; 1400 } 1401 return 0; 1402 } 1403 1404 1405 static int 1406 do_gsm_accept( ControlClient client, char* args ) 1407 { 1408 ACall call; 1409 1410 if (!args) { 1411 control_write( client, "KO: missing argument, try 'gsm accept <phonenumber>'\r\n" ); 1412 return -1; 1413 } 1414 call = amodem_find_call_by_number( android_modem, args ); 1415 if (call == NULL) { 1416 control_write( client, "KO: no current call to/from number '%s'\r\n", args ); 1417 return -1; 1418 } 1419 if ( amodem_update_call( android_modem, args, A_CALL_ACTIVE ) < 0 ) { 1420 control_write( client, "KO: could not activate this call\r\n" ); 1421 return -1; 1422 } 1423 return 0; 1424 } 1425 1426 static int 1427 do_gsm_signal( ControlClient client, char* args ) 1428 { 1429 enum { SIGNAL_RSSI = 0, SIGNAL_BER, NUM_SIGNAL_PARAMS }; 1430 char* p = args; 1431 int top_param = -1; 1432 int params[ NUM_SIGNAL_PARAMS ]; 1433 1434 static int last_ber = 99; 1435 1436 if (!p) 1437 p = ""; 1438 1439 /* tokenize */ 1440 while (*p) { 1441 char* end; 1442 int val = strtol( p, &end, 10 ); 1443 1444 if (end == p) { 1445 control_write( client, "KO: argument '%s' is not a number\n", p ); 1446 return -1; 1447 } 1448 1449 params[++top_param] = val; 1450 if (top_param + 1 == NUM_SIGNAL_PARAMS) 1451 break; 1452 1453 p = end; 1454 while (*p && (p[0] == ' ' || p[0] == '\t')) 1455 p += 1; 1456 } 1457 1458 /* sanity check */ 1459 if (top_param < SIGNAL_RSSI) { 1460 control_write( client, "KO: not enough arguments: see 'help gsm signal' for details\r\n" ); 1461 return -1; 1462 } 1463 1464 int rssi = params[SIGNAL_RSSI]; 1465 if ((rssi < 0 || rssi > 31) && rssi != 99) { 1466 control_write( client, "KO: invalid RSSI - must be 0..31 or 99\r\n"); 1467 return -1; 1468 } 1469 1470 /* check ber is 0..7 or 99 */ 1471 if (top_param >= SIGNAL_BER) { 1472 int ber = params[SIGNAL_BER]; 1473 if ((ber < 0 || ber > 7) && ber != 99) { 1474 control_write( client, "KO: invalid BER - must be 0..7 or 99\r\n"); 1475 return -1; 1476 } 1477 last_ber = ber; 1478 } 1479 1480 amodem_set_signal_strength( android_modem, rssi, last_ber ); 1481 1482 return 0; 1483 } 1484 1485 1486 #if 0 1487 static const CommandDefRec gsm_in_commands[] = 1488 { 1489 { "new", "create a new 'waiting' inbound call", 1490 "'gsm in create <phonenumber>' creates a new inbound phone call, placed in\r\n" 1491 "the 'waiting' state by default, until the system answers/holds/closes it\r\n", NULL 1492 do_gsm_in_create, NULL }, 1493 1494 { "hold", "change the state of an oubtound call to 'held'", 1495 "change the state of an outbound call to 'held'. this is only possible\r\n" 1496 "if the call in the 'waiting' or 'active' state\r\n", NULL, 1497 do_gsm_out_hold, NULL }, 1498 1499 { "accept", "change the state of an outbound call to 'active'", 1500 "change the state of an outbound call to 'active'. this is only possible\r\n" 1501 "if the call is in the 'waiting' or 'held' state\r\n", NULL, 1502 do_gsm_out_accept, NULL }, 1503 1504 { NULL, NULL, NULL, NULL, NULL, NULL } 1505 }; 1506 #endif 1507 1508 1509 static const CommandDefRec cdma_commands[] = 1510 { 1511 { "ssource", "Set the current CDMA subscription source", 1512 NULL, describe_subscription_source, 1513 do_cdma_ssource, NULL }, 1514 { "prl_version", "Dump the current PRL version", 1515 NULL, NULL, 1516 do_cdma_prl_version, NULL }, 1517 }; 1518 1519 static const CommandDefRec gsm_commands[] = 1520 { 1521 { "list", "list current phone calls", 1522 "'gsm list' lists all inbound and outbound calls and their state\r\n", NULL, 1523 do_gsm_list, NULL }, 1524 1525 { "call", "create inbound phone call", 1526 "'gsm call <phonenumber>' allows you to simulate a new inbound call\r\n", NULL, 1527 do_gsm_call, NULL }, 1528 1529 { "busy", "close waiting outbound call as busy", 1530 "'gsm busy <remoteNumber>' closes an outbound call, reporting\r\n" 1531 "the remote phone as busy. only possible if the call is 'waiting'.\r\n", NULL, 1532 do_gsm_busy, NULL }, 1533 1534 { "hold", "change the state of an oubtound call to 'held'", 1535 "'gsm hold <remoteNumber>' change the state of a call to 'held'. this is only possible\r\n" 1536 "if the call in the 'waiting' or 'active' state\r\n", NULL, 1537 do_gsm_hold, NULL }, 1538 1539 { "accept", "change the state of an outbound call to 'active'", 1540 "'gsm accept <remoteNumber>' change the state of a call to 'active'. this is only possible\r\n" 1541 "if the call is in the 'waiting' or 'held' state\r\n", NULL, 1542 do_gsm_accept, NULL }, 1543 1544 { "cancel", "disconnect an inbound or outbound phone call", 1545 "'gsm cancel <phonenumber>' allows you to simulate the end of an inbound or outbound call\r\n", NULL, 1546 do_gsm_cancel, NULL }, 1547 1548 { "data", "modify data connection state", NULL, help_gsm_data, 1549 do_gsm_data, NULL }, 1550 1551 { "voice", "modify voice connection state", NULL, help_gsm_voice, 1552 do_gsm_voice, NULL }, 1553 1554 { "status", "display GSM status", 1555 "'gsm status' displays the current state of the GSM emulation\r\n", NULL, 1556 do_gsm_status, NULL }, 1557 1558 { "signal", "set sets the rssi and ber", 1559 "'gsm signal <rssi> [<ber>]' changes the reported strength and error rate on next (15s) update.\r\n" 1560 "rssi range is 0..31 and 99 for unknown\r\n" 1561 "ber range is 0..7 percent and 99 for unknown\r\n", 1562 NULL, do_gsm_signal, NULL }, 1563 1564 { NULL, NULL, NULL, NULL, NULL, NULL } 1565 }; 1566 1567 /********************************************************************************************/ 1568 /********************************************************************************************/ 1569 /***** ******/ 1570 /***** S M S C O M M A N D ******/ 1571 /***** ******/ 1572 /********************************************************************************************/ 1573 /********************************************************************************************/ 1574 1575 static int 1576 do_sms_send( ControlClient client, char* args ) 1577 { 1578 char* p; 1579 int textlen; 1580 SmsAddressRec sender; 1581 SmsPDU* pdus; 1582 int nn; 1583 1584 /* check that we have a phone number made of digits */ 1585 if (!args) { 1586 MissingArgument: 1587 control_write( client, "KO: missing argument, try 'sms send <phonenumber> <text message>'\r\n" ); 1588 return -1; 1589 } 1590 p = strchr( args, ' ' ); 1591 if (!p) { 1592 goto MissingArgument; 1593 } 1594 1595 if ( sms_address_from_str( &sender, args, p - args ) < 0 ) { 1596 control_write( client, "KO: bad phone number format, must be [+](0-9)*\r\n" ); 1597 return -1; 1598 } 1599 1600 1601 /* un-secape message text into proper utf-8 (conversion happens in-site) */ 1602 p += 1; 1603 textlen = strlen(p); 1604 textlen = sms_utf8_from_message_str( p, textlen, (unsigned char*)p, textlen ); 1605 if (textlen < 0) { 1606 control_write( client, "message must be utf8 and can use the following escapes:\r\n" 1607 " \\n for a newline\r\n" 1608 " \\xNN where NN are two hexadecimal numbers\r\n" 1609 " \\uNNNN where NNNN are four hexadecimal numbers\r\n" 1610 " \\\\ to send a '\\' character\r\n\r\n" 1611 " anything else is an error\r\n" 1612 "KO: badly formatted text\r\n" ); 1613 return -1; 1614 } 1615 1616 if (!android_modem) { 1617 control_write( client, "KO: modem emulation not running\r\n" ); 1618 return -1; 1619 } 1620 1621 /* create a list of SMS PDUs, then send them */ 1622 pdus = smspdu_create_deliver_utf8( (cbytes_t)p, textlen, &sender, NULL ); 1623 if (pdus == NULL) { 1624 control_write( client, "KO: internal error when creating SMS-DELIVER PDUs\n" ); 1625 return -1; 1626 } 1627 1628 for (nn = 0; pdus[nn] != NULL; nn++) 1629 amodem_receive_sms( android_modem, pdus[nn] ); 1630 1631 smspdu_free_list( pdus ); 1632 return 0; 1633 } 1634 1635 static int 1636 do_sms_sendpdu( ControlClient client, char* args ) 1637 { 1638 SmsPDU pdu; 1639 1640 /* check that we have a phone number made of digits */ 1641 if (!args) { 1642 control_write( client, "KO: missing argument, try 'sms sendpdu <hexstring>'\r\n" ); 1643 return -1; 1644 } 1645 1646 if (!android_modem) { 1647 control_write( client, "KO: modem emulation not running\r\n" ); 1648 return -1; 1649 } 1650 1651 pdu = smspdu_create_from_hex( args, strlen(args) ); 1652 if (pdu == NULL) { 1653 control_write( client, "KO: badly formatted <hexstring>\r\n" ); 1654 return -1; 1655 } 1656 1657 amodem_receive_sms( android_modem, pdu ); 1658 smspdu_free( pdu ); 1659 return 0; 1660 } 1661 1662 static const CommandDefRec sms_commands[] = 1663 { 1664 { "send", "send inbound SMS text message", 1665 "'sms send <phonenumber> <message>' allows you to simulate a new inbound sms message\r\n", NULL, 1666 do_sms_send, NULL }, 1667 1668 { "pdu", "send inbound SMS PDU", 1669 "'sms pdu <hexstring>' allows you to simulate a new inbound sms PDU\r\n" 1670 "(used internally when one emulator sends SMS messages to another instance).\r\n" 1671 "you probably don't want to play with this at all\r\n", NULL, 1672 do_sms_sendpdu, NULL }, 1673 1674 { NULL, NULL, NULL, NULL, NULL, NULL } 1675 }; 1676 1677 static void 1678 do_control_write(void* data, const char* string) 1679 { 1680 control_write((ControlClient)data, string); 1681 } 1682 1683 static int 1684 do_power_display( ControlClient client, char* args ) 1685 { 1686 goldfish_battery_display(do_control_write, client); 1687 return 0; 1688 } 1689 1690 static int 1691 do_ac_state( ControlClient client, char* args ) 1692 { 1693 if (args) { 1694 if (strcasecmp(args, "on") == 0) { 1695 goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 1); 1696 return 0; 1697 } 1698 if (strcasecmp(args, "off") == 0) { 1699 goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 0); 1700 return 0; 1701 } 1702 } 1703 1704 control_write( client, "KO: Usage: \"ac on\" or \"ac off\"\n" ); 1705 return -1; 1706 } 1707 1708 static int 1709 do_battery_status( ControlClient client, char* args ) 1710 { 1711 if (args) { 1712 if (strcasecmp(args, "unknown") == 0) { 1713 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_UNKNOWN); 1714 return 0; 1715 } 1716 if (strcasecmp(args, "charging") == 0) { 1717 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_CHARGING); 1718 return 0; 1719 } 1720 if (strcasecmp(args, "discharging") == 0) { 1721 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_DISCHARGING); 1722 return 0; 1723 } 1724 if (strcasecmp(args, "not-charging") == 0) { 1725 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_NOT_CHARGING); 1726 return 0; 1727 } 1728 if (strcasecmp(args, "full") == 0) { 1729 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_FULL); 1730 return 0; 1731 } 1732 } 1733 1734 control_write( client, "KO: Usage: \"status unknown|charging|discharging|not-charging|full\"\n" ); 1735 return -1; 1736 } 1737 1738 static int 1739 do_battery_present( ControlClient client, char* args ) 1740 { 1741 if (args) { 1742 if (strcasecmp(args, "true") == 0) { 1743 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 1); 1744 return 0; 1745 } 1746 if (strcasecmp(args, "false") == 0) { 1747 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 0); 1748 return 0; 1749 } 1750 } 1751 1752 control_write( client, "KO: Usage: \"present true\" or \"present false\"\n" ); 1753 return -1; 1754 } 1755 1756 static int 1757 do_battery_health( ControlClient client, char* args ) 1758 { 1759 if (args) { 1760 if (strcasecmp(args, "unknown") == 0) { 1761 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNKNOWN); 1762 return 0; 1763 } 1764 if (strcasecmp(args, "good") == 0) { 1765 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_GOOD); 1766 return 0; 1767 } 1768 if (strcasecmp(args, "overheat") == 0) { 1769 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERHEAT); 1770 return 0; 1771 } 1772 if (strcasecmp(args, "dead") == 0) { 1773 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_DEAD); 1774 return 0; 1775 } 1776 if (strcasecmp(args, "overvoltage") == 0) { 1777 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERVOLTAGE); 1778 return 0; 1779 } 1780 if (strcasecmp(args, "failure") == 0) { 1781 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNSPEC_FAILURE); 1782 return 0; 1783 } 1784 } 1785 1786 control_write( client, "KO: Usage: \"health unknown|good|overheat|dead|overvoltage|failure\"\n" ); 1787 return -1; 1788 } 1789 1790 static int 1791 do_battery_capacity( ControlClient client, char* args ) 1792 { 1793 if (args) { 1794 int capacity; 1795 1796 if (sscanf(args, "%d", &capacity) == 1 && capacity >= 0 && capacity <= 100) { 1797 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_CAPACITY, capacity); 1798 return 0; 1799 } 1800 } 1801 1802 control_write( client, "KO: Usage: \"capacity <percentage>\"\n" ); 1803 return -1; 1804 } 1805 1806 1807 static const CommandDefRec power_commands[] = 1808 { 1809 { "display", "display battery and charger state", 1810 "display battery and charger state\r\n", NULL, 1811 do_power_display, NULL }, 1812 1813 { "ac", "set AC charging state", 1814 "'ac on|off' allows you to set the AC charging state to on or off\r\n", NULL, 1815 do_ac_state, NULL }, 1816 1817 { "status", "set battery status", 1818 "'status unknown|charging|discharging|not-charging|full' allows you to set battery status\r\n", NULL, 1819 do_battery_status, NULL }, 1820 1821 { "present", "set battery present state", 1822 "'present true|false' allows you to set battery present state to true or false\r\n", NULL, 1823 do_battery_present, NULL }, 1824 1825 { "health", "set battery health state", 1826 "'health unknown|good|overheat|dead|overvoltage|failure' allows you to set battery health state\r\n", NULL, 1827 do_battery_health, NULL }, 1828 1829 { "capacity", "set battery capacity state", 1830 "'capacity <percentage>' allows you to set battery capacity to a value 0 - 100\r\n", NULL, 1831 do_battery_capacity, NULL }, 1832 1833 { NULL, NULL, NULL, NULL, NULL, NULL } 1834 }; 1835 1836 /********************************************************************************************/ 1837 /********************************************************************************************/ 1838 /***** ******/ 1839 /***** E V E N T C O M M A N D S ******/ 1840 /***** ******/ 1841 /********************************************************************************************/ 1842 /********************************************************************************************/ 1843 1844 1845 static int 1846 do_event_send( ControlClient client, char* args ) 1847 { 1848 char* p; 1849 1850 if (!args) { 1851 control_write( client, "KO: Usage: event send <type>:<code>:<value> ...\r\n" ); 1852 return -1; 1853 } 1854 1855 p = args; 1856 while (*p) { 1857 char* q; 1858 char temp[128]; 1859 int type, code, value, ret; 1860 1861 p += strspn( p, " \t" ); /* skip spaces */ 1862 if (*p == 0) 1863 break; 1864 1865 q = p + strcspn( p, " \t" ); 1866 1867 if (q == p) 1868 break; 1869 1870 snprintf(temp, sizeof temp, "%.*s", (int)(intptr_t)(q-p), p); 1871 ret = android_event_from_str( temp, &type, &code, &value ); 1872 if (ret < 0) { 1873 if (ret == -1) { 1874 control_write( client, 1875 "KO: invalid event type in '%.*s', try 'event list types' for valid values\r\n", 1876 q-p, p ); 1877 } else if (ret == -2) { 1878 control_write( client, 1879 "KO: invalid event code in '%.*s', try 'event list codes <type>' for valid values\r\n", 1880 q-p, p ); 1881 } else { 1882 control_write( client, 1883 "KO: invalid event value in '%.*s', must be an integer\r\n", 1884 q-p, p); 1885 } 1886 return -1; 1887 } 1888 1889 user_event_generic( type, code, value ); 1890 p = q; 1891 } 1892 return 0; 1893 } 1894 1895 static int 1896 do_event_types( ControlClient client, char* args ) 1897 { 1898 int count = android_event_get_type_count(); 1899 int nn; 1900 1901 control_write( client, "event <type> can be an integer or one of the following aliases\r\n" ); 1902 for (nn = 0; nn < count; nn++) { 1903 char tmp[16]; 1904 char* p = tmp; 1905 char* end = p + sizeof(tmp); 1906 int count2 = android_event_get_code_count( nn );; 1907 1908 p = android_event_bufprint_type_str( p, end, nn ); 1909 1910 control_write( client, " %-8s", tmp ); 1911 if (count2 > 0) 1912 control_write( client, " (%d code aliases)", count2 ); 1913 1914 control_write( client, "\r\n" ); 1915 } 1916 return 0; 1917 } 1918 1919 static int 1920 do_event_codes( ControlClient client, char* args ) 1921 { 1922 int count; 1923 int nn, type, dummy; 1924 1925 if (!args) { 1926 control_write( client, "KO: argument missing, try 'event codes <type>'\r\n" ); 1927 return -1; 1928 } 1929 1930 if ( android_event_from_str( args, &type, &dummy, &dummy ) < 0 ) { 1931 control_write( client, "KO: bad argument, see 'event types' for valid values\r\n" ); 1932 return -1; 1933 } 1934 1935 count = android_event_get_code_count( type ); 1936 if (count == 0) { 1937 control_write( client, "no code aliases defined for this type\r\n" ); 1938 } else { 1939 control_write( client, "type '%s' accepts the following <code> aliases:\r\n", 1940 args ); 1941 for (nn = 0; nn < count; nn++) { 1942 char temp[20], *p = temp, *end = p + sizeof(temp); 1943 android_event_bufprint_code_str( p, end, type, nn ); 1944 control_write( client, " %-12s\r\n", temp ); 1945 } 1946 } 1947 1948 return 0; 1949 } 1950 1951 static __inline__ int 1952 utf8_next( unsigned char* *pp, unsigned char* end ) 1953 { 1954 unsigned char* p = *pp; 1955 int result = -1; 1956 1957 if (p < end) { 1958 int c= *p++; 1959 if (c >= 128) { 1960 if ((c & 0xe0) == 0xc0) 1961 c &= 0x1f; 1962 else if ((c & 0xf0) == 0xe0) 1963 c &= 0x0f; 1964 else 1965 c &= 0x07; 1966 1967 while (p < end && (p[0] & 0xc0) == 0x80) { 1968 c = (c << 6) | (p[0] & 0x3f); 1969 } 1970 } 1971 result = c; 1972 *pp = p; 1973 } 1974 return result; 1975 } 1976 1977 static int 1978 do_event_text( ControlClient client, char* args ) 1979 { 1980 AKeycodeBuffer keycodes; 1981 unsigned char* p = (unsigned char*) args; 1982 unsigned char* end = p + strlen(args); 1983 int textlen; 1984 const AKeyCharmap* charmap; 1985 1986 if (!args) { 1987 control_write( client, "KO: argument missing, try 'event text <message>'\r\n" ); 1988 return -1; 1989 } 1990 1991 /* Get active charmap. */ 1992 charmap = android_get_charmap(); 1993 if (charmap == NULL) { 1994 control_write( client, "KO: no character map active in current device layout/config\r\n" ); 1995 return -1; 1996 } 1997 1998 keycodes.keycode_count = 0; 1999 2000 /* un-secape message text into proper utf-8 (conversion happens in-site) */ 2001 textlen = strlen((char*)p); 2002 textlen = sms_utf8_from_message_str( args, textlen, (unsigned char*)p, textlen ); 2003 if (textlen < 0) { 2004 control_write( client, "message must be utf8 and can use the following escapes:\r\n" 2005 " \\n for a newline\r\n" 2006 " \\xNN where NN are two hexadecimal numbers\r\n" 2007 " \\uNNNN where NNNN are four hexadecimal numbers\r\n" 2008 " \\\\ to send a '\\' character\r\n\r\n" 2009 " anything else is an error\r\n" 2010 "KO: badly formatted text\r\n" ); 2011 return -1; 2012 } 2013 2014 end = p + textlen; 2015 while (p < end) { 2016 int c = utf8_next( &p, end ); 2017 if (c <= 0) 2018 break; 2019 2020 android_charmap_reverse_map_unicode( NULL, (unsigned)c, 1, &keycodes ); 2021 android_charmap_reverse_map_unicode( NULL, (unsigned)c, 0, &keycodes ); 2022 android_keycodes_flush( &keycodes ); 2023 } 2024 2025 return 0; 2026 } 2027 2028 static const CommandDefRec event_commands[] = 2029 { 2030 { "send", "send a series of events to the kernel", 2031 "'event send <type>:<code>:<value> ...' allows your to send one or more hardware events\r\n" 2032 "to the Android kernel. you can use text names or integers for <type> and <code>\r\n", NULL, 2033 do_event_send, NULL }, 2034 2035 { "types", "list all <type> aliases", 2036 "'event types' list all <type> string aliases supported by the 'event' subcommands\r\n", 2037 NULL, do_event_types, NULL }, 2038 2039 { "codes", "list all <code> aliases for a given <type>", 2040 "'event codes <type>' lists all <code> string aliases for a given event <type>\r\n", 2041 NULL, do_event_codes, NULL }, 2042 2043 { "text", "simulate keystrokes from a given text", 2044 "'event text <message>' allows you to simulate keypresses to generate a given text\r\n" 2045 "message. <message> must be an utf-8 string. Unicode points will be reverse-mapped\r\n" 2046 "according to the current device keyboard. unsupported characters will be discarded\r\n" 2047 "silently\r\n", NULL, do_event_text, NULL }, 2048 2049 { NULL, NULL, NULL, NULL, NULL, NULL } 2050 }; 2051 2052 2053 /********************************************************************************************/ 2054 /********************************************************************************************/ 2055 /***** ******/ 2056 /***** S N A P S H O T C O M M A N D S ******/ 2057 /***** ******/ 2058 /********************************************************************************************/ 2059 /********************************************************************************************/ 2060 2061 static int 2062 control_write_out_cb(void* opaque, const char* str, int strsize) 2063 { 2064 ControlClient client = opaque; 2065 control_control_write(client, str, strsize); 2066 return strsize; 2067 } 2068 2069 static int 2070 control_write_err_cb(void* opaque, const char* str, int strsize) 2071 { 2072 int ret = 0; 2073 ControlClient client = opaque; 2074 ret += control_write(client, "KO: "); 2075 control_control_write(client, str, strsize); 2076 return ret + strsize; 2077 } 2078 2079 static int 2080 do_snapshot_list( ControlClient client, char* args ) 2081 { 2082 int64_t ret; 2083 Monitor *out = monitor_fake_new(client, control_write_out_cb); 2084 Monitor *err = monitor_fake_new(client, control_write_err_cb); 2085 do_info_snapshots(out, err); 2086 ret = monitor_fake_get_bytes(err); 2087 monitor_fake_free(err); 2088 monitor_fake_free(out); 2089 2090 return ret > 0; 2091 } 2092 2093 static int 2094 do_snapshot_save( ControlClient client, char* args ) 2095 { 2096 int64_t ret; 2097 2098 if (args == NULL) { 2099 control_write(client, "KO: argument missing, try 'avd snapshot save <name>'\r\n"); 2100 return -1; 2101 } 2102 2103 Monitor *err = monitor_fake_new(client, control_write_err_cb); 2104 do_savevm(err, args); 2105 ret = monitor_fake_get_bytes(err); 2106 monitor_fake_free(err); 2107 2108 return ret > 0; // no output on error channel indicates success 2109 } 2110 2111 static int 2112 do_snapshot_load( ControlClient client, char* args ) 2113 { 2114 int64_t ret; 2115 2116 if (args == NULL) { 2117 control_write(client, "KO: argument missing, try 'avd snapshot load <name>'\r\n"); 2118 return -1; 2119 } 2120 2121 Monitor *err = monitor_fake_new(client, control_write_err_cb); 2122 do_loadvm(err, args); 2123 ret = monitor_fake_get_bytes(err); 2124 monitor_fake_free(err); 2125 2126 return ret > 0; 2127 } 2128 2129 static int 2130 do_snapshot_del( ControlClient client, char* args ) 2131 { 2132 int64_t ret; 2133 2134 if (args == NULL) { 2135 control_write(client, "KO: argument missing, try 'avd snapshot del <name>'\r\n"); 2136 return -1; 2137 } 2138 2139 Monitor *err = monitor_fake_new(client, control_write_err_cb); 2140 do_delvm(err, args); 2141 ret = monitor_fake_get_bytes(err); 2142 monitor_fake_free(err); 2143 2144 return ret > 0; 2145 } 2146 2147 static const CommandDefRec snapshot_commands[] = 2148 { 2149 { "list", "list available state snapshots", 2150 "'avd snapshot list' will show a list of all state snapshots that can be loaded\r\n", 2151 NULL, do_snapshot_list, NULL }, 2152 2153 { "save", "save state snapshot", 2154 "'avd snapshot save <name>' will save the current (run-time) state to a snapshot with the given name\r\n", 2155 NULL, do_snapshot_save, NULL }, 2156 2157 { "load", "load state snapshot", 2158 "'avd snapshot load <name>' will load the state snapshot of the given name\r\n", 2159 NULL, do_snapshot_load, NULL }, 2160 2161 { "del", "delete state snapshot", 2162 "'avd snapshot del <name>' will delete the state snapshot with the given name\r\n", 2163 NULL, do_snapshot_del, NULL }, 2164 2165 { NULL, NULL, NULL, NULL, NULL, NULL } 2166 }; 2167 2168 2169 2170 /********************************************************************************************/ 2171 /********************************************************************************************/ 2172 /***** ******/ 2173 /***** V M C O M M A N D S ******/ 2174 /***** ******/ 2175 /********************************************************************************************/ 2176 /********************************************************************************************/ 2177 2178 static int 2179 do_avd_stop( ControlClient client, char* args ) 2180 { 2181 if (!vm_running) { 2182 control_write( client, "KO: virtual device already stopped\r\n" ); 2183 return -1; 2184 } 2185 vm_stop(EXCP_INTERRUPT); 2186 return 0; 2187 } 2188 2189 static int 2190 do_avd_start( ControlClient client, char* args ) 2191 { 2192 if (vm_running) { 2193 control_write( client, "KO: virtual device already running\r\n" ); 2194 return -1; 2195 } 2196 vm_start(); 2197 return 0; 2198 } 2199 2200 static int 2201 do_avd_status( ControlClient client, char* args ) 2202 { 2203 control_write( client, "virtual device is %s\r\n", vm_running ? "running" : "stopped" ); 2204 return 0; 2205 } 2206 2207 static int 2208 do_avd_name( ControlClient client, char* args ) 2209 { 2210 control_write( client, "%s\r\n", android_hw->avd_name); 2211 return 0; 2212 } 2213 2214 static const CommandDefRec vm_commands[] = 2215 { 2216 { "stop", "stop the virtual device", 2217 "'avd stop' stops the virtual device immediately, use 'avd start' to continue execution\r\n", 2218 NULL, do_avd_stop, NULL }, 2219 2220 { "start", "start/restart the virtual device", 2221 "'avd start' will start or continue the virtual device, use 'avd stop' to stop it\r\n", 2222 NULL, do_avd_start, NULL }, 2223 2224 { "status", "query virtual device status", 2225 "'avd status' will indicate whether the virtual device is running or not\r\n", 2226 NULL, do_avd_status, NULL }, 2227 2228 { "name", "query virtual device name", 2229 "'avd name' will return the name of this virtual device\r\n", 2230 NULL, do_avd_name, NULL }, 2231 2232 { "snapshot", "state snapshot commands", 2233 "allows you to save and restore the virtual device state in snapshots\r\n", 2234 NULL, NULL, snapshot_commands }, 2235 2236 { NULL, NULL, NULL, NULL, NULL, NULL } 2237 }; 2238 2239 /********************************************************************************************/ 2240 /********************************************************************************************/ 2241 /***** ******/ 2242 /***** G E O C O M M A N D S ******/ 2243 /***** ******/ 2244 /********************************************************************************************/ 2245 /********************************************************************************************/ 2246 2247 static int 2248 do_geo_nmea( ControlClient client, char* args ) 2249 { 2250 if (!args) { 2251 control_write( client, "KO: NMEA sentence missing, try 'help geo nmea'\r\n" ); 2252 return -1; 2253 } 2254 if (!android_gps_cs) { 2255 control_write( client, "KO: no GPS emulation in this virtual device\r\n" ); 2256 return -1; 2257 } 2258 android_gps_send_nmea( args ); 2259 return 0; 2260 } 2261 2262 static int 2263 do_geo_fix( ControlClient client, char* args ) 2264 { 2265 // GEO_SAT2 provides bug backwards compatibility. 2266 enum { GEO_LONG = 0, GEO_LAT, GEO_ALT, GEO_SAT, GEO_SAT2, NUM_GEO_PARAMS }; 2267 char* p = args; 2268 int top_param = -1; 2269 double params[ NUM_GEO_PARAMS ]; 2270 int n_satellites = 1; 2271 2272 static int last_time = 0; 2273 static double last_altitude = 0.; 2274 2275 if (!p) 2276 p = ""; 2277 2278 /* tokenize */ 2279 while (*p) { 2280 char* end; 2281 double val = strtod( p, &end ); 2282 2283 if (end == p) { 2284 control_write( client, "KO: argument '%s' is not a number\n", p ); 2285 return -1; 2286 } 2287 2288 params[++top_param] = val; 2289 if (top_param + 1 == NUM_GEO_PARAMS) 2290 break; 2291 2292 p = end; 2293 while (*p && (p[0] == ' ' || p[0] == '\t')) 2294 p += 1; 2295 } 2296 2297 /* sanity check */ 2298 if (top_param < GEO_LAT) { 2299 control_write( client, "KO: not enough arguments: see 'help geo fix' for details\r\n" ); 2300 return -1; 2301 } 2302 2303 /* check number of satellites, must be integer between 1 and 12 */ 2304 if (top_param >= GEO_SAT) { 2305 int sat_index = (top_param >= GEO_SAT2) ? GEO_SAT2 : GEO_SAT; 2306 n_satellites = (int) params[sat_index]; 2307 if (n_satellites != params[sat_index] 2308 || n_satellites < 1 || n_satellites > 12) { 2309 control_write( client, "KO: invalid number of satellites. Must be an integer between 1 and 12\r\n"); 2310 return -1; 2311 } 2312 } 2313 2314 /* generate an NMEA sentence for this fix */ 2315 { 2316 STRALLOC_DEFINE(s); 2317 double val; 2318 int deg, min; 2319 char hemi; 2320 2321 /* format overview: 2322 * time of fix 123519 12:35:19 UTC 2323 * latitude 4807.038 48 degrees, 07.038 minutes 2324 * north/south N or S 2325 * longitude 01131.000 11 degrees, 31. minutes 2326 * east/west E or W 2327 * fix quality 1 standard GPS fix 2328 * satellites 1 to 12 number of satellites being tracked 2329 * HDOP <dontcare> horizontal dilution 2330 * altitude 546. altitude above sea-level 2331 * altitude units M to indicate meters 2332 * diff <dontcare> height of sea-level above ellipsoid 2333 * diff units M to indicate meters (should be <dontcare>) 2334 * dgps age <dontcare> time in seconds since last DGPS fix 2335 * dgps sid <dontcare> DGPS station id 2336 */ 2337 2338 /* first, the time */ 2339 stralloc_add_format( s, "$GPGGA,%06d", last_time ); 2340 last_time ++; 2341 2342 /* then the latitude */ 2343 hemi = 'N'; 2344 val = params[GEO_LAT]; 2345 if (val < 0) { 2346 hemi = 'S'; 2347 val = -val; 2348 } 2349 deg = (int) val; 2350 val = 60*(val - deg); 2351 min = (int) val; 2352 val = 10000*(val - min); 2353 stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)val, hemi ); 2354 2355 /* the longitude */ 2356 hemi = 'E'; 2357 val = params[GEO_LONG]; 2358 if (val < 0) { 2359 hemi = 'W'; 2360 val = -val; 2361 } 2362 deg = (int) val; 2363 val = 60*(val - deg); 2364 min = (int) val; 2365 val = 10000*(val - min); 2366 stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)val, hemi ); 2367 2368 /* bogus fix quality, satellite count and dilution */ 2369 stralloc_add_format( s, ",1,%02d,", n_satellites ); 2370 2371 /* optional altitude + bogus diff */ 2372 if (top_param >= GEO_ALT) { 2373 stralloc_add_format( s, ",%.1g,M,0.,M", params[GEO_ALT] ); 2374 last_altitude = params[GEO_ALT]; 2375 } else { 2376 stralloc_add_str( s, ",,,," ); 2377 } 2378 /* bogus rest and checksum */ 2379 stralloc_add_str( s, ",,,*47" ); 2380 2381 /* send it, then free */ 2382 android_gps_send_nmea( stralloc_cstr(s) ); 2383 stralloc_reset( s ); 2384 } 2385 return 0; 2386 } 2387 2388 static const CommandDefRec geo_commands[] = 2389 { 2390 { "nmea", "send an GPS NMEA sentence", 2391 "'geo nema <sentence>' sends a NMEA 0183 sentence to the emulated device, as\r\n" 2392 "if it came from an emulated GPS modem. <sentence> must begin with '$GP'. only\r\n" 2393 "'$GPGGA' and '$GPRCM' sentences are supported at the moment.\r\n", 2394 NULL, do_geo_nmea, NULL }, 2395 2396 { "fix", "send a simple GPS fix", 2397 "'geo fix <longitude> <latitude> [<altitude> [<satellites>]]'\r\n" 2398 " allows you to send a simple GPS fix to the emulated system.\r\n" 2399 " The parameters are:\r\n\r\n" 2400 " <longitude> longitude, in decimal degrees\r\n" 2401 " <latitude> latitude, in decimal degrees\r\n" 2402 " <altitude> optional altitude in meters\r\n" 2403 " <satellites> number of satellites being tracked (1-12)\r\n" 2404 "\r\n", 2405 NULL, do_geo_fix, NULL }, 2406 2407 { NULL, NULL, NULL, NULL, NULL, NULL } 2408 }; 2409 2410 2411 /********************************************************************************************/ 2412 /********************************************************************************************/ 2413 /***** ******/ 2414 /***** S E N S O R S C O M M A N D S ******/ 2415 /***** ******/ 2416 /********************************************************************************************/ 2417 /********************************************************************************************/ 2418 2419 /* For sensors user prompt string size.*/ 2420 #define SENSORS_INFO_SIZE 150 2421 2422 /* Get sensor data - (a,b,c) from sensor name */ 2423 static int 2424 do_sensors_get( ControlClient client, char* args ) 2425 { 2426 if (! args) { 2427 control_write( client, "KO: Usage: \"get <sensorname>\"\n" ); 2428 return -1; 2429 } 2430 2431 int status = SENSOR_STATUS_UNKNOWN; 2432 char sensor[strlen(args) + 1]; 2433 if (1 != sscanf( args, "%s", &sensor[0] )) 2434 goto SENSOR_STATUS_ERROR; 2435 2436 int sensor_id = android_sensors_get_id_from_name( sensor ); 2437 char buffer[SENSORS_INFO_SIZE] = { 0 }; 2438 float a, b, c; 2439 2440 if (sensor_id < 0) { 2441 status = sensor_id; 2442 goto SENSOR_STATUS_ERROR; 2443 } else { 2444 status = android_sensors_get( sensor_id, &a, &b, &c ); 2445 if (status != SENSOR_STATUS_OK) 2446 goto SENSOR_STATUS_ERROR; 2447 snprintf( buffer, sizeof(buffer), 2448 "%s = %g:%g:%g\r\n", sensor, a, b, c ); 2449 do_control_write( client, buffer ); 2450 return 0; 2451 } 2452 2453 SENSOR_STATUS_ERROR: 2454 switch(status) { 2455 case SENSOR_STATUS_NO_SERVICE: 2456 snprintf( buffer, sizeof(buffer), "KO: No sensor service found!\r\n" ); 2457 break; 2458 case SENSOR_STATUS_DISABLED: 2459 snprintf( buffer, sizeof(buffer), "KO: '%s' sensor is disabled.\r\n", sensor ); 2460 break; 2461 case SENSOR_STATUS_UNKNOWN: 2462 snprintf( buffer, sizeof(buffer), 2463 "KO: unknown sensor name: %s, run 'sensor status' to get available sensors.\r\n", sensor ); 2464 break; 2465 default: 2466 snprintf( buffer, sizeof(buffer), "KO: '%s' sensor: exception happens.\r\n", sensor ); 2467 } 2468 do_control_write( client, buffer ); 2469 return -1; 2470 } 2471 2472 /* set sensor data - (a,b,c) from sensor name */ 2473 static int 2474 do_sensors_set( ControlClient client, char* args ) 2475 { 2476 if (! args) { 2477 control_write( client, "KO: Usage: \"set <sensorname> <value-a>[:<value-b>[:<value-c>]]\"\n" ); 2478 return -1; 2479 } 2480 2481 int status; 2482 char* sensor; 2483 char* value; 2484 char* args_dup = strdup( args ); 2485 if (args_dup == NULL) { 2486 control_write( client, "KO: Memory allocation failed.\n" ); 2487 return -1; 2488 } 2489 char* p = args_dup; 2490 2491 /* Parsing the args to get sensor name string */ 2492 while (*p && isspace(*p)) p++; 2493 if (*p == 0) 2494 goto INPUT_ERROR; 2495 sensor = p; 2496 2497 /* Parsing the args to get value string */ 2498 while (*p && (! isspace(*p))) p++; 2499 if (*p == 0 || *(p + 1) == 0/* make sure value isn't NULL */) 2500 goto INPUT_ERROR; 2501 *p = 0; 2502 value = p + 1; 2503 2504 if (! (strlen(sensor) && strlen(value))) 2505 goto INPUT_ERROR; 2506 2507 int sensor_id = android_sensors_get_id_from_name( sensor ); 2508 char buffer[SENSORS_INFO_SIZE] = { 0 }; 2509 2510 if (sensor_id < 0) { 2511 status = sensor_id; 2512 goto SENSOR_STATUS_ERROR; 2513 } else { 2514 float fvalues[3]; 2515 status = android_sensors_get( sensor_id, &fvalues[0], &fvalues[1], &fvalues[2] ); 2516 if (status != SENSOR_STATUS_OK) 2517 goto SENSOR_STATUS_ERROR; 2518 2519 /* Parsing the value part to get the sensor values(a, b, c) */ 2520 int i; 2521 char* pnext; 2522 char* pend = value + strlen(value); 2523 for (i = 0; i < 3; i++, value = pnext + 1) { 2524 pnext=strchr( value, ':' ); 2525 if (pnext) { 2526 *pnext = 0; 2527 } else { 2528 pnext = pend; 2529 } 2530 2531 if (pnext > value) { 2532 if (1 != sscanf( value,"%g", &fvalues[i] )) 2533 goto INPUT_ERROR; 2534 } 2535 } 2536 2537 status = android_sensors_set( sensor_id, fvalues[0], fvalues[1], fvalues[2] ); 2538 if (status != SENSOR_STATUS_OK) 2539 goto SENSOR_STATUS_ERROR; 2540 2541 free( args_dup ); 2542 return 0; 2543 } 2544 2545 SENSOR_STATUS_ERROR: 2546 switch(status) { 2547 case SENSOR_STATUS_NO_SERVICE: 2548 snprintf( buffer, sizeof(buffer), "KO: No sensor service found!\r\n" ); 2549 break; 2550 case SENSOR_STATUS_DISABLED: 2551 snprintf( buffer, sizeof(buffer), "KO: '%s' sensor is disabled.\r\n", sensor ); 2552 break; 2553 case SENSOR_STATUS_UNKNOWN: 2554 snprintf( buffer, sizeof(buffer), 2555 "KO: unknown sensor name: %s, run 'sensor status' to get available sensors.\r\n", sensor ); 2556 break; 2557 default: 2558 snprintf( buffer, sizeof(buffer), "KO: '%s' sensor: exception happens.\r\n", sensor ); 2559 } 2560 do_control_write( client, buffer ); 2561 free( args_dup ); 2562 return -1; 2563 2564 INPUT_ERROR: 2565 control_write( client, "KO: Usage: \"set <sensorname> <value-a>[:<value-b>[:<value-c>]]\"\n" ); 2566 free( args_dup ); 2567 return -1; 2568 } 2569 2570 /* get all available sensor names and enable status respectively. */ 2571 static int 2572 do_sensors_status( ControlClient client, char* args ) 2573 { 2574 uint8_t id, status; 2575 char buffer[SENSORS_INFO_SIZE] = { 0 }; 2576 2577 for(id = 0; id < MAX_SENSORS; id++) { 2578 status = android_sensors_get_sensor_status( id ); 2579 snprintf( buffer, sizeof(buffer), "%s: %s\n", 2580 android_sensors_get_name_from_id(id), (status ? "enabled.":"disabled.") ); 2581 control_write( client, buffer ); 2582 } 2583 2584 return 0; 2585 } 2586 2587 /* Sensor commands for get/set sensor values and get available sensor names. */ 2588 static const CommandDefRec sensor_commands[] = 2589 { 2590 { "status", "list all sensors and their status.", 2591 "'status': list all sensors and their status.\r\n", 2592 NULL, do_sensors_status, NULL }, 2593 2594 { "get", "get sensor values", 2595 "'get <sensorname>' returns the values of a given sensor.\r\n", 2596 NULL, do_sensors_get, NULL }, 2597 2598 { "set", "set sensor values", 2599 "'set <sensorname> <value-a>[:<value-b>[:<value-c>]]' set the values of a given sensor.\r\n", 2600 NULL, do_sensors_set, NULL }, 2601 2602 { NULL, NULL, NULL, NULL, NULL, NULL } 2603 }; 2604 2605 /********************************************************************************************/ 2606 /********************************************************************************************/ 2607 /***** ******/ 2608 /***** M A I N C O M M A N D S ******/ 2609 /***** ******/ 2610 /********************************************************************************************/ 2611 /********************************************************************************************/ 2612 2613 static int 2614 do_window_scale( ControlClient client, char* args ) 2615 { 2616 double scale; 2617 int is_dpi = 0; 2618 char* end; 2619 2620 if (!args) { 2621 control_write( client, "KO: argument missing, try 'window scale <scale>'\r\n" ); 2622 return -1; 2623 } 2624 2625 scale = strtol( args, &end, 10 ); 2626 if (end > args && !memcmp( end, "dpi", 4 )) { 2627 is_dpi = 1; 2628 } 2629 else { 2630 scale = strtod( args, &end ); 2631 if (end == args || end[0]) { 2632 control_write( client, "KO: argument <scale> must be a real number, or an integer followed by 'dpi'\r\n" ); 2633 return -1; 2634 } 2635 } 2636 2637 uicmd_set_window_scale( scale, is_dpi ); 2638 return 0; 2639 } 2640 2641 static const CommandDefRec window_commands[] = 2642 { 2643 { "scale", "change the window scale", 2644 "'window scale <scale>' allows you to change the scale of the emulator window at runtime\r\n" 2645 "<scale> must be either a real number between 0.1 and 3.0, or an integer followed by\r\n" 2646 "the 'dpi' prefix (as in '120dpi')\r\n", 2647 NULL, do_window_scale, NULL }, 2648 2649 { NULL, NULL, NULL, NULL, NULL, NULL } 2650 }; 2651 2652 /********************************************************************************************/ 2653 /********************************************************************************************/ 2654 /***** ******/ 2655 /***** Q E M U C O M M A N D S ******/ 2656 /***** ******/ 2657 /********************************************************************************************/ 2658 /********************************************************************************************/ 2659 2660 static int 2661 do_qemu_monitor( ControlClient client, char* args ) 2662 { 2663 char socketname[32]; 2664 int fd; 2665 CharDriverState* cs; 2666 2667 if (args != NULL) { 2668 control_write( client, "KO: no argument for 'qemu monitor'\r\n" ); 2669 return -1; 2670 } 2671 /* Detach the client socket, and re-attach it to a monitor */ 2672 fd = control_client_detach(client); 2673 snprintf(socketname, sizeof socketname, "tcp:socket=%d", fd); 2674 cs = qemu_chr_open("monitor", socketname, NULL); 2675 if (cs == NULL) { 2676 control_client_reattach(client, fd); 2677 control_write( client, "KO: internal error: could not detach from console !\r\n" ); 2678 return -1; 2679 } 2680 monitor_init(cs, MONITOR_USE_READLINE|MONITOR_QUIT_DOESNT_EXIT); 2681 control_client_destroy(client); 2682 return 0; 2683 } 2684 2685 #ifdef CONFIG_STANDALONE_CORE 2686 /* UI settings, passed to the core via -ui-settings command line parameter. */ 2687 extern char* android_op_ui_settings; 2688 2689 static int 2690 do_attach_ui( ControlClient client, char* args ) 2691 { 2692 // Make sure that there are no UI already attached to this console. 2693 if (attached_ui_client != NULL) { 2694 control_write( client, "KO: Another UI is attached to this core!\r\n" ); 2695 control_client_destroy(client); 2696 return -1; 2697 } 2698 2699 if (!attachUiProxy_create(client->sock)) { 2700 char reply_buf[4096]; 2701 attached_ui_client = client; 2702 // Reply "OK" with the saved -ui-settings property. 2703 snprintf(reply_buf, sizeof(reply_buf), "OK: %s\r\n", android_op_ui_settings); 2704 control_write( client, reply_buf); 2705 } else { 2706 control_write( client, "KO\r\n" ); 2707 control_client_destroy(client); 2708 return -1; 2709 } 2710 2711 return 0; 2712 } 2713 2714 void 2715 destroy_attach_ui_client(void) 2716 { 2717 if (attached_ui_client != NULL) { 2718 control_client_destroy(attached_ui_client); 2719 } 2720 } 2721 2722 static int 2723 do_create_framebuffer_service( ControlClient client, char* args ) 2724 { 2725 ProxyFramebuffer* core_fb; 2726 const char* protocol = "-raw"; // Default framebuffer exchange protocol. 2727 char reply_buf[64]; 2728 2729 // Protocol type is defined by the arguments passed with the stream switch 2730 // command. 2731 if (args != NULL && *args != '\0') { 2732 size_t token_len; 2733 const char* param_end = strchr(args, ' '); 2734 if (param_end == NULL) { 2735 param_end = args + strlen(args); 2736 } 2737 token_len = param_end - args; 2738 protocol = args; 2739 2740 // Make sure that this is one of the supported protocols. 2741 if (strncmp(protocol, "-raw", token_len) && 2742 strncmp(protocol, "-shared", token_len)) { 2743 derror("Invalid framebuffer parameter %s\n", protocol); 2744 control_write( client, "KO: Invalid parameter\r\n" ); 2745 control_client_destroy(client); 2746 return -1; 2747 } 2748 } 2749 2750 core_fb = proxyFb_create(client->sock, protocol); 2751 if (core_fb == NULL) { 2752 control_write( client, "KO\r\n" ); 2753 control_client_destroy(client); 2754 return -1; 2755 } 2756 2757 // Reply "OK" with the framebuffer's bits per pixel 2758 snprintf(reply_buf, sizeof(reply_buf), "OK: -bitsperpixel=%d\r\n", 2759 proxyFb_get_bits_per_pixel(core_fb)); 2760 control_write( client, reply_buf); 2761 return 0; 2762 } 2763 2764 static int 2765 do_create_user_events_service( ControlClient client, char* args ) 2766 { 2767 // Make sure that there are no user events client already existing. 2768 if (user_events_client != NULL) { 2769 control_write( client, "KO: Another user events service is already existing!\r\n" ); 2770 control_client_destroy(client); 2771 return -1; 2772 } 2773 2774 if (!userEventsImpl_create(client->sock)) { 2775 char reply_buf[4096]; 2776 user_events_client = client; 2777 snprintf(reply_buf, sizeof(reply_buf), "OK\r\n"); 2778 control_write( client, reply_buf); 2779 } else { 2780 control_write( client, "KO\r\n" ); 2781 control_client_destroy(client); 2782 return -1; 2783 } 2784 2785 return 0; 2786 } 2787 2788 void 2789 destroy_user_events_client(void) 2790 { 2791 if (user_events_client != NULL) { 2792 control_client_destroy(user_events_client); 2793 } 2794 } 2795 2796 static int 2797 do_create_ui_core_ctl_service( ControlClient client, char* args ) 2798 { 2799 // Make sure that there are no ui control client already existing. 2800 if (ui_core_ctl_client != NULL) { 2801 control_write( client, "KO: Another UI control service is already existing!\r\n" ); 2802 control_client_destroy(client); 2803 return -1; 2804 } 2805 2806 if (!coreCmdImpl_create(client->sock)) { 2807 char reply_buf[4096]; 2808 ui_core_ctl_client = client; 2809 snprintf(reply_buf, sizeof(reply_buf), "OK\r\n"); 2810 control_write( client, reply_buf); 2811 } else { 2812 control_write( client, "KO\r\n" ); 2813 control_client_destroy(client); 2814 return -1; 2815 } 2816 2817 return 0; 2818 } 2819 2820 void 2821 destroy_ui_core_ctl_client(void) 2822 { 2823 if (ui_core_ctl_client != NULL) { 2824 control_client_destroy(ui_core_ctl_client); 2825 } 2826 } 2827 2828 void 2829 destroy_corecmd_client(void) 2830 { 2831 if (ui_core_ctl_client != NULL) { 2832 control_client_destroy(ui_core_ctl_client); 2833 } 2834 } 2835 2836 static int 2837 do_create_core_ui_ctl_service( ControlClient client, char* args ) 2838 { 2839 // Make sure that there are no ui control client already existing. 2840 if (core_ui_ctl_client != NULL) { 2841 control_write( client, "KO: Another UI control service is already existing!\r\n" ); 2842 control_client_destroy(client); 2843 return -1; 2844 } 2845 2846 if (!uiCmdProxy_create(client->sock)) { 2847 char reply_buf[4096]; 2848 core_ui_ctl_client = client; 2849 snprintf(reply_buf, sizeof(reply_buf), "OK\r\n"); 2850 control_write( client, reply_buf); 2851 } else { 2852 control_write( client, "KO\r\n" ); 2853 control_client_destroy(client); 2854 return -1; 2855 } 2856 2857 return 0; 2858 } 2859 2860 void 2861 destroy_core_ui_ctl_client(void) 2862 { 2863 if (core_ui_ctl_client != NULL) { 2864 control_client_destroy(core_ui_ctl_client); 2865 } 2866 } 2867 2868 void 2869 destroy_uicmd_client(void) 2870 { 2871 if (core_ui_ctl_client != NULL) { 2872 control_client_destroy(core_ui_ctl_client); 2873 } 2874 } 2875 2876 #endif // CONFIG_STANDALONE_CORE 2877 2878 static const CommandDefRec qemu_commands[] = 2879 { 2880 { "monitor", "enter QEMU monitor", 2881 "Enter the QEMU virtual machine monitor\r\n", 2882 NULL, do_qemu_monitor, NULL }, 2883 2884 #ifdef CONFIG_STANDALONE_CORE 2885 { "attach-UI", "attach UI to the core", 2886 "Attach UI to the core\r\n", 2887 NULL, do_attach_ui, NULL }, 2888 2889 { "framebuffer", "create framebuffer service", 2890 "Create framebuffer service\r\n", 2891 NULL, do_create_framebuffer_service, NULL }, 2892 2893 { "user-events", "create user events service", 2894 "Create user events service\r\n", 2895 NULL, do_create_user_events_service, NULL }, 2896 2897 { "ui-core-control", "create UI control service", 2898 "Create UI control service\r\n", 2899 NULL, do_create_ui_core_ctl_service, NULL }, 2900 2901 { "core-ui-control", "create UI control service", 2902 "Create UI control service\r\n", 2903 NULL, do_create_core_ui_ctl_service, NULL }, 2904 #endif // CONFIG_STANDALONE_CORE 2905 2906 { NULL, NULL, NULL, NULL, NULL, NULL } 2907 }; 2908 2909 2910 /********************************************************************************************/ 2911 /********************************************************************************************/ 2912 /***** ******/ 2913 /***** M A I N C O M M A N D S ******/ 2914 /***** ******/ 2915 /********************************************************************************************/ 2916 /********************************************************************************************/ 2917 2918 static int 2919 do_kill( ControlClient client, char* args ) 2920 { 2921 control_write( client, "OK: killing emulator, bye bye\r\n" ); 2922 exit(0); 2923 } 2924 2925 static const CommandDefRec main_commands[] = 2926 { 2927 { "help|h|?", "print a list of commands", NULL, NULL, do_help, NULL }, 2928 2929 { "event", "simulate hardware events", 2930 "allows you to send fake hardware events to the kernel\r\n", NULL, 2931 NULL, event_commands }, 2932 2933 { "geo", "Geo-location commands", 2934 "allows you to change Geo-related settings, or to send GPS NMEA sentences\r\n", NULL, 2935 NULL, geo_commands }, 2936 2937 { "gsm", "GSM related commands", 2938 "allows you to change GSM-related settings, or to make a new inbound phone call\r\n", NULL, 2939 NULL, gsm_commands }, 2940 2941 { "cdma", "CDMA related commands", 2942 "allows you to change CDMA-related settings\r\n", NULL, 2943 NULL, cdma_commands }, 2944 2945 { "kill", "kill the emulator instance", NULL, NULL, 2946 do_kill, NULL }, 2947 2948 { "network", "manage network settings", 2949 "allows you to manage the settings related to the network data connection of the\r\n" 2950 "emulated device.\r\n", NULL, 2951 NULL, network_commands }, 2952 2953 { "power", "power related commands", 2954 "allows to change battery and AC power status\r\n", NULL, 2955 NULL, power_commands }, 2956 2957 { "quit|exit", "quit control session", NULL, NULL, 2958 do_quit, NULL }, 2959 2960 { "redir", "manage port redirections", 2961 "allows you to add, list and remove UDP and/or PORT redirection from the host to the device\r\n" 2962 "as an example, 'redir tcp:5000:6000' will route any packet sent to the host's TCP port 5000\r\n" 2963 "to TCP port 6000 of the emulated device\r\n", NULL, 2964 NULL, redir_commands }, 2965 2966 { "sms", "SMS related commands", 2967 "allows you to simulate an inbound SMS\r\n", NULL, 2968 NULL, sms_commands }, 2969 2970 { "avd", "control virtual device execution", 2971 "allows you to control (e.g. start/stop) the execution of the virtual device\r\n", NULL, 2972 NULL, vm_commands }, 2973 2974 { "window", "manage emulator window", 2975 "allows you to modify the emulator window\r\n", NULL, 2976 NULL, window_commands }, 2977 2978 { "qemu", "QEMU-specific commands", 2979 "allows to connect to the QEMU virtual machine monitor\r\n", NULL, 2980 NULL, qemu_commands }, 2981 2982 { "sensor", "manage emulator sensors", 2983 "allows you to request the emulator sensors\r\n", NULL, 2984 NULL, sensor_commands }, 2985 2986 { NULL, NULL, NULL, NULL, NULL, NULL } 2987 }; 2988 2989 2990 static ControlGlobalRec _g_global; 2991 2992 int 2993 control_console_start( int port ) 2994 { 2995 return control_global_init( &_g_global, port ); 2996 } 2997