console.c revision 43552dc4fa64aad0c9fdb8f4c92ae7ac79406596
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 "sockets.h" 29#include "cpu.h" 30#include "hw/goldfish_device.h" 31#include "hw/power_supply.h" 32#include "shaper.h" 33#include "modem_driver.h" 34#include "android/gps.h" 35#include "android/globals.h" 36#include "android/utils/bufprint.h" 37#include "android/utils/debug.h" 38#include "android/utils/stralloc.h" 39#include "tcpdump.h" 40#include "net.h" 41 42#include <stdlib.h> 43#include <stdio.h> 44#include <stdarg.h> 45#include <string.h> 46#include <unistd.h> 47#include <fcntl.h> 48#include "android/hw-events.h" 49#include "user-events.h" 50#include "android/keycode-array.h" 51#include "android/charmap.h" 52#include "android/core-ui-protocol.h" 53 54#if defined(CONFIG_SLIRP) 55#include "libslirp.h" 56#endif 57 58/* set to 1 to use the i/o and event functions 59 * defined in "telephony/sysdeps.h" 60 */ 61#define USE_SYSDEPS 0 62 63#include "sysdeps.h" 64 65#define DEBUG 1 66 67#if 1 68# define D_ACTIVE VERBOSE_CHECK(console) 69#else 70# define D_ACTIVE DEBUG 71#endif 72 73#if DEBUG 74# define D(x) do { if (D_ACTIVE) ( printf x , fflush(stdout) ); } while (0) 75#else 76# define D(x) do{}while(0) 77#endif 78 79typedef struct ControlGlobalRec_* ControlGlobal; 80 81typedef struct ControlClientRec_* ControlClient; 82 83typedef struct { 84 int host_port; 85 int host_udp; 86 unsigned int guest_ip; 87 int guest_port; 88} RedirRec, *Redir; 89 90 91#if USE_SYSDEPS 92typedef SysChannel Socket; 93#else /* !USE_SYSDEPS */ 94typedef int Socket; 95#endif /* !USE_SYSDEPS */ 96 97 98typedef struct ControlClientRec_ 99{ 100 struct ControlClientRec_* next; /* next client in list */ 101 Socket sock; /* socket used for communication */ 102 ControlGlobal global; 103 char finished; 104 char buff[ 4096 ]; 105 int buff_len; 106 107} ControlClientRec; 108 109 110typedef struct ControlGlobalRec_ 111{ 112 /* listening socket */ 113 Socket listen_fd; 114 115 /* the list of current clients */ 116 ControlClient clients; 117 118 /* the list of redirections currently active */ 119 Redir redirs; 120 int num_redirs; 121 int max_redirs; 122 123} ControlGlobalRec; 124 125 126static int 127control_global_add_redir( ControlGlobal global, 128 int host_port, 129 int host_udp, 130 unsigned int guest_ip, 131 int guest_port ) 132{ 133 Redir redir; 134 135 if (global->num_redirs >= global->max_redirs) 136 { 137 int old_max = global->max_redirs; 138 int new_max = old_max + (old_max >> 1) + 4; 139 140 Redir new_redirs = realloc( global->redirs, new_max*sizeof(global->redirs[0]) ); 141 if (new_redirs == NULL) 142 return -1; 143 144 global->redirs = new_redirs; 145 global->max_redirs = new_max; 146 } 147 148 redir = &global->redirs[ global->num_redirs++ ]; 149 150 redir->host_port = host_port; 151 redir->host_udp = host_udp; 152 redir->guest_ip = guest_ip; 153 redir->guest_port = guest_port; 154 155 return 0; 156} 157 158static int 159control_global_del_redir( ControlGlobal global, 160 int host_port, 161 int host_udp ) 162{ 163 int nn; 164 165 for (nn = 0; nn < global->num_redirs; nn++) 166 { 167 Redir redir = &global->redirs[nn]; 168 169 if ( redir->host_port == host_port && 170 redir->host_udp == host_udp ) 171 { 172 memmove( redir, redir + 1, ((global->num_redirs - nn)-1)*sizeof(*redir) ); 173 global->num_redirs -= 1; 174 return 0; 175 } 176 } 177 /* we didn't find it */ 178 return -1; 179} 180 181static void 182control_client_destroy( ControlClient client ) 183{ 184 ControlGlobal global = client->global; 185 ControlClient *pnode = &global->clients; 186 187 D(( "destroying control client %p\n", client )); 188 189#if USE_SYSDEPS 190 sys_channel_on( client->sock, 0, NULL, NULL ); 191#else 192 qemu_set_fd_handler( client->sock, NULL, NULL, NULL ); 193#endif 194 195 for ( ;; ) { 196 ControlClient node = *pnode; 197 if ( node == NULL ) 198 break; 199 if ( node == client ) { 200 *pnode = node->next; 201 node->next = NULL; 202 break; 203 } 204 pnode = &node->next; 205 } 206 207#if USE_SYSDEPS 208 sys_channel_close( client->sock ); 209 client->sock = NULL; 210#else 211 socket_close( client->sock ); 212 client->sock = -1; 213#endif 214 215 free( client ); 216} 217 218static void control_client_read( void* _client ); /* forward */ 219 220 221static void control_control_write( ControlClient client, const char* buff, int len ) 222{ 223 int ret; 224 225 if (len < 0) 226 len = strlen(buff); 227 228 while (len > 0) { 229#if USE_SYSDEPS 230 ret = sys_channel_write( client->sock, buff, len ); 231#else 232 ret = socket_send( client->sock, buff, len); 233#endif 234 if (ret < 0) { 235 if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN) 236 return; 237 } else { 238 buff += ret; 239 len -= ret; 240 } 241 } 242} 243 244static void control_write( ControlClient client, const char* format, ... ) 245{ 246 static char temp[1024]; 247 va_list args; 248 249 va_start(args, format); 250 vsnprintf( temp, sizeof(temp), format, args ); 251 va_end(args); 252 253 temp[ sizeof(temp)-1 ] = 0; 254 255 control_control_write( client, temp, -1 ); 256} 257 258 259static ControlClient 260control_client_create( Socket socket, 261 ControlGlobal global ) 262{ 263 ControlClient client = calloc( sizeof(*client), 1 ); 264 265 if (client) { 266#if !USE_SYSDEPS 267 socket_set_nodelay( socket ); 268 socket_set_nonblock( socket ); 269#endif 270 client->finished = 0; 271 client->global = global; 272 client->sock = socket; 273 client->next = global->clients; 274 global->clients = client; 275 276#if USE_SYSDEPS 277 sys_channel_on( socket, SYS_EVENT_READ, 278 (SysChannelCallback) control_client_read, 279 client ); 280#else 281 qemu_set_fd_handler( socket, control_client_read, NULL, client ); 282#endif 283 } 284 return client; 285} 286 287typedef const struct CommandDefRec_ *CommandDef; 288 289typedef struct CommandDefRec_ { 290 const char* names; 291 const char* abstract; 292 const char* description; 293 void (*descriptor)( ControlClient client ); 294 int (*handler)( ControlClient client, char* args ); 295 CommandDef subcommands; /* if handler is NULL */ 296 297} CommandDefRec; 298 299static const CommandDefRec main_commands[]; /* forward */ 300 301static CommandDef 302find_command( char* input, CommandDef commands, char* *pend, char* *pargs ) 303{ 304 int nn; 305 char* args = strchr(input, ' '); 306 307 if (args != NULL) { 308 while (*args == ' ') 309 args++; 310 311 if (args[0] == 0) 312 args = NULL; 313 } 314 315 for (nn = 0; commands[nn].names != NULL; nn++) 316 { 317 const char* name = commands[nn].names; 318 const char* sep; 319 320 do { 321 int len, c; 322 323 sep = strchr( name, '|' ); 324 if (sep) 325 len = sep - name; 326 else 327 len = strlen(name); 328 329 c = input[len]; 330 if ( !memcmp( name, input, len ) && (c == ' ' || c == 0) ) { 331 *pend = input + len; 332 *pargs = args; 333 return &commands[nn]; 334 } 335 336 if (sep) 337 name = sep + 1; 338 339 } while (sep != NULL && *name); 340 } 341 /* NOTE: don't touch *pend and *pargs if no command is found */ 342 return NULL; 343} 344 345static void 346dump_help( ControlClient client, 347 CommandDef cmd, 348 const char* prefix ) 349{ 350 if (cmd->description) { 351 control_write( client, "%s", cmd->description ); 352 } else if (cmd->descriptor) { 353 cmd->descriptor( client ); 354 } else 355 control_write( client, "%s\r\n", cmd->abstract ); 356 357 if (cmd->subcommands) { 358 cmd = cmd->subcommands; 359 control_write( client, "\r\navailable sub-commands:\r\n" ); 360 for ( ; cmd->names != NULL; cmd++ ) { 361 control_write( client, " %s %-15s %s\r\n", prefix, cmd->names, cmd->abstract ); 362 } 363 control_write( client, "\r\n" ); 364 } 365} 366 367static void 368control_client_do_command( ControlClient client ) 369{ 370 char* line = client->buff; 371 char* args = NULL; 372 CommandDef commands = main_commands; 373 char* cmdend = client->buff; 374 CommandDef cmd = find_command( line, commands, &cmdend, &args ); 375 376 if (cmd == NULL) { 377 control_write( client, "KO: unknown command, try 'help'\r\n" ); 378 return; 379 } 380 381 for (;;) { 382 CommandDef subcmd; 383 384 if (cmd->handler) { 385 if ( !cmd->handler( client, args ) ) 386 control_write( client, "OK\r\n" ); 387 break; 388 } 389 390 /* no handler means we should have sub-commands */ 391 if (cmd->subcommands == NULL) { 392 control_write( client, "KO: internal error: buggy command table for '%.*s'\r\n", 393 cmdend - client->buff, client->buff ); 394 break; 395 } 396 397 /* we need a sub-command here */ 398 if ( !args ) { 399 dump_help( client, cmd, "" ); 400 control_write( client, "KO: missing sub-command\r\n" ); 401 break; 402 } 403 404 line = args; 405 commands = cmd->subcommands; 406 subcmd = find_command( line, commands, &cmdend, &args ); 407 if (subcmd == NULL) { 408 dump_help( client, cmd, "" ); 409 control_write( client, "KO: bad sub-command\r\n" ); 410 break; 411 } 412 cmd = subcmd; 413 } 414} 415 416/* implement the 'help' command */ 417static int 418do_help( ControlClient client, char* args ) 419{ 420 char* line; 421 char* start = args; 422 char* end = start; 423 CommandDef cmd = main_commands; 424 425 /* without arguments, simply dump all commands */ 426 if (args == NULL) { 427 control_write( client, "Android console command help:\r\n\r\n" ); 428 for ( ; cmd->names != NULL; cmd++ ) { 429 control_write( client, " %-15s %s\r\n", cmd->names, cmd->abstract ); 430 } 431 control_write( client, "\r\ntry 'help <command>' for command-specific help\r\n" ); 432 return 0; 433 } 434 435 /* with an argument, find the corresponding command */ 436 for (;;) { 437 CommandDef subcmd; 438 439 line = args; 440 subcmd = find_command( line, cmd, &end, &args ); 441 if (subcmd == NULL) { 442 control_write( client, "try one of these instead:\r\n\r\n" ); 443 for ( ; cmd->names != NULL; cmd++ ) { 444 control_write( client, " %.*s %s\r\n", 445 end - start, start, cmd->names ); 446 } 447 control_write( client, "\r\nKO: unknown command\r\n" ); 448 return -1; 449 } 450 451 if ( !args || !subcmd->subcommands ) { 452 dump_help( client, subcmd, start ); 453 return 0; 454 } 455 cmd = subcmd->subcommands; 456 } 457} 458 459 460static void 461control_client_read_byte( ControlClient client, unsigned char ch ) 462{ 463 if (ch == '\r') 464 { 465 /* filter them out */ 466 } 467 else if (ch == '\n') 468 { 469 client->buff[ client->buff_len ] = 0; 470 control_client_do_command( client ); 471 if (client->finished) 472 return; 473 474 client->buff_len = 0; 475 } 476 else 477 { 478 if (client->buff_len >= sizeof(client->buff)-1) 479 client->buff_len = 0; 480 481 client->buff[ client->buff_len++ ] = ch; 482 } 483} 484 485static void 486control_client_read( void* _client ) 487{ 488 ControlClient client = _client; 489 unsigned char buf[4096]; 490 int size; 491 492 D(( "in control_client read: " )); 493#if USE_SYSDEPS 494 size = sys_channel_read( client->sock, buf, sizeof(buf) ); 495#else 496 size = socket_recv( client->sock, buf, sizeof(buf) ); 497#endif 498 if (size < 0) { 499 D(( "size < 0, exiting with %d: %s\n", errno, errno_str )); 500 if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) 501 control_client_destroy( client ); 502 return; 503 } 504 505 if (size == 0) { 506 /* end of connection */ 507 D(( "end of connection detected !!\n" )); 508 control_client_destroy( client ); 509 } 510 else { 511 int nn; 512#ifdef _WIN32 513# if DEBUG 514 char temp[16]; 515 int count = size > sizeof(temp)-1 ? sizeof(temp)-1 : size; 516 for (nn = 0; nn < count; nn++) { 517 int c = buf[nn]; 518 if (c == '\n') 519 temp[nn] = '!'; 520 else if (c < 32) 521 temp[nn] = '.'; 522 else 523 temp[nn] = (char)c; 524 } 525 temp[nn] = 0; 526 D(( "received %d bytes: %s\n", size, temp )); 527# endif 528#else 529 D(( "received %.*s\n", size, buf )); 530#endif 531 for (nn = 0; nn < size; nn++) { 532 control_client_read_byte( client, buf[nn] ); 533 if (client->finished) { 534 control_client_destroy(client); 535 return; 536 } 537 } 538 } 539} 540 541 542/* this function is called on each new client connection */ 543static void 544control_global_accept( void* _global ) 545{ 546 ControlGlobal global = _global; 547 ControlClient client; 548 Socket fd; 549 550 D(( "control_global_accept: just in (fd=%p)\n", (void*)global->listen_fd )); 551 552#if USE_SYSDEPS 553 fd = sys_channel_create_tcp_handler( global->listen_fd ); 554 if (fd == NULL) { 555 perror("accept"); 556 return; 557 } 558#else 559 for(;;) { 560 fd = socket_accept( global->listen_fd, NULL ); 561 if (fd < 0 && errno != EINTR) { 562 D(( "problem in accept: %d: %s\n", errno, errno_str )); 563 perror("accept"); 564 return; 565 } else if (fd >= 0) { 566 break; 567 } 568 D(( "relooping in accept()\n" )); 569 } 570 571 socket_set_xreuseaddr( fd ); 572#endif 573 574 D(( "control_global_accept: creating new client\n" )); 575 client = control_client_create( fd, global ); 576 if (client) { 577 D(( "control_global_accept: new client %p\n", client )); 578 control_write( client, "Android Console: type 'help' for a list of commands\r\n" ); 579 control_write( client, "OK\r\n" ); 580 } 581} 582 583 584static int 585control_global_init( ControlGlobal global, 586 int control_port ) 587{ 588 Socket fd; 589#if !USE_SYSDEPS 590 int ret; 591 SockAddress sockaddr; 592#endif 593 594 memset( global, 0, sizeof(*global) ); 595 596 sys_main_init(); 597 598#if USE_SYSDEPS 599 fd = sys_channel_create_tcp_server( control_port ); 600 if (fd == NULL) { 601 return -1; 602 } 603 604 D(("global fd=%p\n", fd)); 605 606 global->listen_fd = fd; 607 sys_channel_on( fd, SYS_EVENT_READ, 608 (SysChannelCallback) control_global_accept, 609 global ); 610#else 611 fd = socket_create_inet( SOCKET_STREAM ); 612 if (fd < 0) { 613 perror("socket"); 614 return -1; 615 } 616 617 socket_set_xreuseaddr( fd ); 618 619 sock_address_init_inet( &sockaddr, SOCK_ADDRESS_INET_LOOPBACK, control_port ); 620 621 ret = socket_bind(fd, &sockaddr ); 622 if (ret < 0) { 623 perror("bind"); 624 socket_close( fd ); 625 return -1; 626 } 627 628 ret = socket_listen(fd, 0); 629 if (ret < 0) { 630 perror("listen"); 631 socket_close( fd ); 632 return -1; 633 } 634 635 socket_set_nonblock(fd); 636 637 global->listen_fd = fd; 638 639 qemu_set_fd_handler( fd, control_global_accept, NULL, global ); 640#endif 641 return 0; 642} 643 644 645 646static int 647do_quit( ControlClient client, char* args ) 648{ 649 client->finished = 1; 650 return -1; 651} 652 653/********************************************************************************************/ 654/********************************************************************************************/ 655/***** ******/ 656/***** N E T W O R K S E T T I N G S ******/ 657/***** ******/ 658/********************************************************************************************/ 659/********************************************************************************************/ 660 661static int 662do_network_status( ControlClient client, char* args ) 663{ 664 control_write( client, "Current network status:\r\n" ); 665 666 control_write( client, " download speed: %8d bits/s (%.1f KB/s)\r\n", 667 (long)qemu_net_download_speed, qemu_net_download_speed/8192. ); 668 669 control_write( client, " upload speed: %8d bits/s (%.1f KB/s)\r\n", 670 (long)qemu_net_upload_speed, qemu_net_upload_speed/8192. ); 671 672 control_write( client, " minimum latency: %ld ms\r\n", qemu_net_min_latency ); 673 control_write( client, " maximum latency: %ld ms\r\n", qemu_net_max_latency ); 674 return 0; 675} 676 677static void 678dump_network_speeds( ControlClient client ) 679{ 680 const NetworkSpeed* speed = android_netspeeds; 681 const char* const format = " %-8s %s\r\n"; 682 for ( ; speed->name; speed++ ) { 683 control_write( client, format, speed->name, speed->display ); 684 } 685 control_write( client, format, "<num>", "selects both upload and download speed" ); 686 control_write( client, format, "<up>:<down>", "select individual upload/download speeds" ); 687} 688 689 690static int 691do_network_speed( ControlClient client, char* args ) 692{ 693 if ( !args ) { 694 control_write( client, "KO: missing <speed> argument, see 'help network speed'\r\n" ); 695 return -1; 696 } 697 if ( android_parse_network_speed( args ) < 0 ) { 698 control_write( client, "KO: invalid <speed> argument, see 'help network speed' for valid values\r\n" ); 699 return -1; 700 } 701 702 netshaper_set_rate( slirp_shaper_in, qemu_net_download_speed ); 703 netshaper_set_rate( slirp_shaper_out, qemu_net_upload_speed ); 704 705 if (android_modem) { 706 amodem_set_data_network_type( android_modem, 707 android_parse_network_type( args ) ); 708 } 709 return 0; 710} 711 712static void 713describe_network_speed( ControlClient client ) 714{ 715 control_write( client, 716 "'network speed <speed>' allows you to dynamically change the speed of the emulated\r\n" 717 "network on the device, where <speed> is one of the following:\r\n\r\n" ); 718 dump_network_speeds( client ); 719} 720 721static int 722do_network_delay( ControlClient client, char* args ) 723{ 724 if ( !args ) { 725 control_write( client, "KO: missing <delay> argument, see 'help network delay'\r\n" ); 726 return -1; 727 } 728 if ( android_parse_network_latency( args ) < 0 ) { 729 control_write( client, "KO: invalid <delay> argument, see 'help network delay' for valid values\r\n" ); 730 return -1; 731 } 732 netdelay_set_latency( slirp_delay_in, qemu_net_min_latency, qemu_net_max_latency ); 733 return 0; 734} 735 736static void 737describe_network_delay( ControlClient client ) 738{ 739 control_write( client, 740 "'network delay <latency>' allows you to dynamically change the latency of the emulated\r\n" 741 "network on the device, where <latency> is one of the following:\r\n\r\n" ); 742 /* XXX: TODO */ 743} 744 745static int 746do_network_capture_start( ControlClient client, char* args ) 747{ 748 if ( !args ) { 749 control_write( client, "KO: missing <file> argument, see 'help network capture start'\r\n" ); 750 return -1; 751 } 752 if ( qemu_tcpdump_start(args) < 0) { 753 control_write( client, "KO: could not start capture: %s", strerror(errno) ); 754 return -1; 755 } 756 return 0; 757} 758 759static int 760do_network_capture_stop( ControlClient client, char* args ) 761{ 762 /* no need to return an error here */ 763 qemu_tcpdump_stop(); 764 return 0; 765} 766 767static const CommandDefRec network_capture_commands[] = 768{ 769 { "start", "start network capture", 770 "'network capture start <file>' starts a new capture of network packets\r\n" 771 "into a specific <file>. This will stop any capture already in progress.\r\n" 772 "the capture file can later be analyzed by tools like WireShark. It uses\r\n" 773 "the libpcap file format.\r\n\r\n" 774 "you can stop the capture anytime with 'network capture stop'\r\n", NULL, 775 do_network_capture_start, NULL }, 776 777 { "stop", "stop network capture", 778 "'network capture stop' stops a currently running packet capture, if any.\r\n" 779 "you can start one with 'network capture start <file>'\r\n", NULL, 780 do_network_capture_stop, NULL }, 781 782 { NULL, NULL, NULL, NULL, NULL, NULL } 783}; 784 785static const CommandDefRec network_commands[] = 786{ 787 { "status", "dump network status", NULL, NULL, 788 do_network_status, NULL }, 789 790 { "speed", "change network speed", NULL, describe_network_speed, 791 do_network_speed, NULL }, 792 793 { "delay", "change network latency", NULL, describe_network_delay, 794 do_network_delay, NULL }, 795 796 { "capture", "dump network packets to file", 797 "allows to start/stop capture of network packets to a file for later analysis\r\n", NULL, 798 NULL, network_capture_commands }, 799 800 { NULL, NULL, NULL, NULL, NULL, NULL } 801}; 802 803/********************************************************************************************/ 804/********************************************************************************************/ 805/***** ******/ 806/***** P O R T R E D I R E C T I O N S ******/ 807/***** ******/ 808/********************************************************************************************/ 809/********************************************************************************************/ 810 811static int 812do_redir_list( ControlClient client, char* args ) 813{ 814 ControlGlobal global = client->global; 815 816 if (global->num_redirs == 0) 817 control_write( client, "no active redirections\r\n" ); 818 else { 819 int nn; 820 for (nn = 0; nn < global->num_redirs; nn++) { 821 Redir redir = &global->redirs[nn]; 822 control_write( client, "%s:%-5d => %-5d\r\n", 823 redir->host_udp ? "udp" : "tcp", 824 redir->host_port, 825 redir->guest_port ); 826 } 827 } 828 return 0; 829} 830 831/* parse a protocol:port specification */ 832static int 833redir_parse_proto_port( char* args, int *pport, int *pproto ) 834{ 835 int proto = -1; 836 int len = 0; 837 char* end; 838 839 if ( !memcmp( args, "tcp:", 4 ) ) { 840 proto = 0; 841 len = 4; 842 } 843 else if ( !memcmp( args, "udp:", 4 ) ) { 844 proto = 1; 845 len = 4; 846 } 847 else 848 return 0; 849 850 args += len; 851 *pproto = proto; 852 *pport = strtol( args, &end, 10 ); 853 if (end == args) 854 return 0; 855 856 len += end - args; 857 return len; 858} 859 860static int 861redir_parse_guest_port( char* arg, int *pport ) 862{ 863 char* end; 864 865 *pport = strtoul( arg, &end, 10 ); 866 if (end == arg) 867 return 0; 868 869 return end - arg; 870} 871 872static Redir 873redir_find( ControlGlobal global, int port, int isudp ) 874{ 875 int nn; 876 877 for (nn = 0; nn < global->num_redirs; nn++) { 878 Redir redir = &global->redirs[nn]; 879 880 if (redir->host_port == port && redir->host_udp == isudp) 881 return redir; 882 } 883 return NULL; 884} 885 886 887static int 888do_redir_add( ControlClient client, char* args ) 889{ 890 int len, host_proto, host_port, guest_port; 891 uint32_t guest_ip; 892 Redir redir; 893 894 if ( !args ) 895 goto BadFormat; 896 897 if (!slirp_is_inited()) { 898 control_write( client, "KO: network emulation disabled\r\n"); 899 return -1; 900 } 901 902 len = redir_parse_proto_port( args, &host_port, &host_proto ); 903 if (len == 0 || args[len] != ':') 904 goto BadFormat; 905 906 args += len + 1; 907 len = redir_parse_guest_port( args, &guest_port ); 908 if (len == 0 || args[len] != 0) 909 goto BadFormat; 910 911 redir = redir_find( client->global, host_port, host_proto ); 912 if ( redir != NULL ) { 913 control_write( client, "KO: host port already active, use 'redir del' to remove first\r\n" ); 914 return -1; 915 } 916 917 if (inet_strtoip("10.0.2.15", &guest_ip) < 0) { 918 control_write( client, "KO: unexpected internal failure when resolving 10.0.2.15\r\n" ); 919 return -1; 920 } 921 922 D(("pattern hport=%d gport=%d proto=%d\n", host_port, guest_port, host_proto )); 923 if ( control_global_add_redir( client->global, host_port, host_proto, 924 guest_ip, guest_port ) < 0 ) 925 { 926 control_write( client, "KO: not enough memory to allocate redirection\r\n" ); 927 return -1; 928 } 929 930 if (slirp_redir(host_proto, host_port, guest_ip, guest_port) < 0) { 931 control_write( client, "KO: can't setup redirection, port probably used by another program on host\r\n" ); 932 control_global_del_redir( client->global, host_port, host_proto ); 933 return -1; 934 } 935 936 return 0; 937 938BadFormat: 939 control_write( client, "KO: bad redirection format, try (tcp|udp):hostport:guestport\r\n", -1 ); 940 return -1; 941} 942 943 944static int 945do_redir_del( ControlClient client, char* args ) 946{ 947 int len, proto, port; 948 Redir redir; 949 950 if ( !args ) 951 goto BadFormat; 952 len = redir_parse_proto_port( args, &port, &proto ); 953 if ( len == 0 || args[len] != 0 ) 954 goto BadFormat; 955 956 redir = redir_find( client->global, port, proto ); 957 if (redir == NULL) { 958 control_write( client, "KO: can't remove unknown redirection (%s:%d)\r\n", 959 proto ? "udp" : "tcp", port ); 960 return -1; 961 } 962 963 slirp_unredir( redir->host_udp, redir->host_port ); 964 control_global_del_redir( client->global, port, proto );\ 965 966 return 0; 967 968BadFormat: 969 control_write( client, "KO: bad redirection format, try (tcp|udp):hostport\r\n" ); 970 return -1; 971} 972 973static const CommandDefRec redir_commands[] = 974{ 975 { "list", "list current redirections", 976 "list current port redirections. use 'redir add' and 'redir del' to add and remove them\r\n", NULL, 977 do_redir_list, NULL }, 978 979 { "add", "add new redirection", 980 "add a new port redirection, arguments must be:\r\n\r\n" 981 " redir add <protocol>:<host-port>:<guest-port>\r\n\r\n" 982 "where: <protocol> is either 'tcp' or 'udp'\r\n" 983 " <host-port> a number indicating which port on the host to open\r\n" 984 " <guest-port> a number indicating which port to route to on the device\r\n" 985 "\r\nas an example, 'redir tcp:5000:6000' will allow any packets sent to\r\n" 986 "the host's TCP port 5000 to be routed to TCP port 6000 of the emulated device\r\n", NULL, 987 do_redir_add, NULL }, 988 989 { "del", "remove existing redirection", 990 "remove a port redirecion that was created with 'redir add', arguments must be:\r\n\r\n" 991 " redir del <protocol>:<host-port>\r\n\r\n" 992 "see the 'help redir add' for the meaning of <protocol> and <host-port>\r\n", NULL, 993 do_redir_del, NULL }, 994 995 { NULL, NULL, NULL, NULL, NULL, NULL } 996}; 997 998 999 1000/********************************************************************************************/ 1001/********************************************************************************************/ 1002/***** ******/ 1003/***** G S M M O D E M ******/ 1004/***** ******/ 1005/********************************************************************************************/ 1006/********************************************************************************************/ 1007 1008static const struct { 1009 const char* name; 1010 const char* display; 1011 ARegistrationState state; 1012} _gsm_states[] = { 1013 { "unregistered", "no network available", A_REGISTRATION_UNREGISTERED }, 1014 { "home", "on local network, non-roaming", A_REGISTRATION_HOME }, 1015 { "roaming", "on roaming network", A_REGISTRATION_ROAMING }, 1016 { "searching", "searching networks", A_REGISTRATION_SEARCHING }, 1017 { "denied", "emergency calls only", A_REGISTRATION_DENIED }, 1018 { "off", "same as 'unregistered'", A_REGISTRATION_UNREGISTERED }, 1019 { "on", "same as 'home'", A_REGISTRATION_HOME }, 1020 { NULL, NULL, A_REGISTRATION_UNREGISTERED } 1021}; 1022 1023static const char* 1024gsm_state_to_string( ARegistrationState state ) 1025{ 1026 int nn; 1027 for (nn = 0; _gsm_states[nn].name != NULL; nn++) { 1028 if (state == _gsm_states[nn].state) 1029 return _gsm_states[nn].name; 1030 } 1031 return "<unknown>"; 1032} 1033 1034static int 1035do_gsm_status( ControlClient client, char* args ) 1036{ 1037 if (args) { 1038 control_write( client, "KO: no argument required\r\n" ); 1039 return -1; 1040 } 1041 if (!android_modem) { 1042 control_write( client, "KO: modem emulation not running\r\n" ); 1043 return -1; 1044 } 1045 control_write( client, "gsm voice state: %s\r\n", 1046 gsm_state_to_string( 1047 amodem_get_voice_registration(android_modem) ) ); 1048 control_write( client, "gsm data state: %s\r\n", 1049 gsm_state_to_string( 1050 amodem_get_data_registration(android_modem) ) ); 1051 return 0; 1052} 1053 1054 1055static void 1056help_gsm_data( ControlClient client ) 1057{ 1058 int nn; 1059 control_write( client, 1060 "the 'gsm data <state>' allows you to change the state of your GPRS connection\r\n" 1061 "valid values for <state> are the following:\r\n\r\n" ); 1062 for (nn = 0; ; nn++) { 1063 const char* name = _gsm_states[nn].name; 1064 const char* display = _gsm_states[nn].display; 1065 1066 if (!name) 1067 break; 1068 1069 control_write( client, " %-15s %s\r\n", name, display ); 1070 } 1071 control_write( client, "\r\n" ); 1072} 1073 1074 1075static int 1076do_gsm_data( ControlClient client, char* args ) 1077{ 1078 int nn; 1079 1080 if (!args) { 1081 control_write( client, "KO: missing argument, try 'gsm data <state>'\r\n" ); 1082 return -1; 1083 } 1084 1085 for (nn = 0; ; nn++) { 1086 const char* name = _gsm_states[nn].name; 1087 ARegistrationState state = _gsm_states[nn].state; 1088 1089 if (!name) 1090 break; 1091 1092 if ( !strcmp( args, name ) ) { 1093 if (!android_modem) { 1094 control_write( client, "KO: modem emulation not running\r\n" ); 1095 return -1; 1096 } 1097 amodem_set_data_registration( android_modem, state ); 1098 qemu_net_disable = (state != A_REGISTRATION_HOME && 1099 state != A_REGISTRATION_ROAMING ); 1100 return 0; 1101 } 1102 } 1103 control_write( client, "KO: bad GSM data state name, try 'help gsm data' for list of valid values\r\n" ); 1104 return -1; 1105} 1106 1107static void 1108help_gsm_voice( ControlClient client ) 1109{ 1110 int nn; 1111 control_write( client, 1112 "the 'gsm voice <state>' allows you to change the state of your GPRS connection\r\n" 1113 "valid values for <state> are the following:\r\n\r\n" ); 1114 for (nn = 0; ; nn++) { 1115 const char* name = _gsm_states[nn].name; 1116 const char* display = _gsm_states[nn].display; 1117 1118 if (!name) 1119 break; 1120 1121 control_write( client, " %-15s %s\r\n", name, display ); 1122 } 1123 control_write( client, "\r\n" ); 1124} 1125 1126 1127static int 1128do_gsm_voice( ControlClient client, char* args ) 1129{ 1130 int nn; 1131 1132 if (!args) { 1133 control_write( client, "KO: missing argument, try 'gsm voice <state>'\r\n" ); 1134 return -1; 1135 } 1136 1137 for (nn = 0; ; nn++) { 1138 const char* name = _gsm_states[nn].name; 1139 ARegistrationState state = _gsm_states[nn].state; 1140 1141 if (!name) 1142 break; 1143 1144 if ( !strcmp( args, name ) ) { 1145 if (!android_modem) { 1146 control_write( client, "KO: modem emulation not running\r\n" ); 1147 return -1; 1148 } 1149 amodem_set_voice_registration( android_modem, state ); 1150 return 0; 1151 } 1152 } 1153 control_write( client, "KO: bad GSM data state name, try 'help gsm voice' for list of valid values\r\n" ); 1154 return -1; 1155} 1156 1157 1158static int 1159gsm_check_number( char* args ) 1160{ 1161 int nn; 1162 1163 for (nn = 0; args[nn] != 0; nn++) { 1164 int c = args[nn]; 1165 if ( !isdigit(c) && c != '+' && c != '#' ) { 1166 return -1; 1167 } 1168 } 1169 if (nn == 0) 1170 return -1; 1171 1172 return 0; 1173} 1174 1175static int 1176do_gsm_call( ControlClient client, char* args ) 1177{ 1178 /* check that we have a phone number made of digits */ 1179 if (!args) { 1180 control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" ); 1181 return -1; 1182 } 1183 1184 if (gsm_check_number(args)) { 1185 control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" ); 1186 return -1; 1187 } 1188 1189 if (!android_modem) { 1190 control_write( client, "KO: modem emulation not running\r\n" ); 1191 return -1; 1192 } 1193 amodem_add_inbound_call( android_modem, args ); 1194 return 0; 1195} 1196 1197static int 1198do_gsm_cancel( ControlClient client, char* args ) 1199{ 1200 if (!args) { 1201 control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" ); 1202 return -1; 1203 } 1204 if (gsm_check_number(args)) { 1205 control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" ); 1206 return -1; 1207 } 1208 if (!android_modem) { 1209 control_write( client, "KO: modem emulation not running\r\n" ); 1210 return -1; 1211 } 1212 if ( amodem_disconnect_call( android_modem, args ) < 0 ) { 1213 control_write( client, "KO: could not cancel this number\r\n" ); 1214 return -1; 1215 } 1216 return 0; 1217} 1218 1219 1220static const char* 1221call_state_to_string( ACallState state ) 1222{ 1223 switch (state) { 1224 case A_CALL_ACTIVE: return "active"; 1225 case A_CALL_HELD: return "held"; 1226 case A_CALL_ALERTING: return "ringing"; 1227 case A_CALL_WAITING: return "waiting"; 1228 case A_CALL_INCOMING: return "incoming"; 1229 default: return "unknown"; 1230 } 1231} 1232 1233static int 1234do_gsm_list( ControlClient client, char* args ) 1235{ 1236 /* check that we have a phone number made of digits */ 1237 int count = amodem_get_call_count( android_modem ); 1238 int nn; 1239 for (nn = 0; nn < count; nn++) { 1240 ACall call = amodem_get_call( android_modem, nn ); 1241 const char* dir; 1242 1243 if (call == NULL) 1244 continue; 1245 1246 if (call->dir == A_CALL_OUTBOUND) 1247 dir = "outbound to "; 1248 else 1249 dir = "inbound from"; 1250 1251 control_write( client, "%s %-10s : %s\r\n", dir, 1252 call->number, call_state_to_string(call->state) ); 1253 } 1254 return 0; 1255} 1256 1257static int 1258do_gsm_busy( ControlClient client, char* args ) 1259{ 1260 ACall call; 1261 1262 if (!args) { 1263 control_write( client, "KO: missing argument, try 'gsm busy <phonenumber>'\r\n" ); 1264 return -1; 1265 } 1266 call = amodem_find_call_by_number( android_modem, args ); 1267 if (call == NULL || call->dir != A_CALL_OUTBOUND) { 1268 control_write( client, "KO: no current outbound call to number '%s' (call %p)\r\n", args, call ); 1269 return -1; 1270 } 1271 if ( amodem_disconnect_call( android_modem, args ) < 0 ) { 1272 control_write( client, "KO: could not cancel this number\r\n" ); 1273 return -1; 1274 } 1275 return 0; 1276} 1277 1278static int 1279do_gsm_hold( ControlClient client, char* args ) 1280{ 1281 ACall call; 1282 1283 if (!args) { 1284 control_write( client, "KO: missing argument, try 'gsm out hold <phonenumber>'\r\n" ); 1285 return -1; 1286 } 1287 call = amodem_find_call_by_number( android_modem, args ); 1288 if (call == NULL) { 1289 control_write( client, "KO: no current call to/from number '%s'\r\n", args ); 1290 return -1; 1291 } 1292 if ( amodem_update_call( android_modem, args, A_CALL_HELD ) < 0 ) { 1293 control_write( client, "KO: could put this call on hold\r\n" ); 1294 return -1; 1295 } 1296 return 0; 1297} 1298 1299 1300static int 1301do_gsm_accept( ControlClient client, char* args ) 1302{ 1303 ACall call; 1304 1305 if (!args) { 1306 control_write( client, "KO: missing argument, try 'gsm accept <phonenumber>'\r\n" ); 1307 return -1; 1308 } 1309 call = amodem_find_call_by_number( android_modem, args ); 1310 if (call == NULL) { 1311 control_write( client, "KO: no current call to/from number '%s'\r\n", args ); 1312 return -1; 1313 } 1314 if ( amodem_update_call( android_modem, args, A_CALL_ACTIVE ) < 0 ) { 1315 control_write( client, "KO: could not activate this call\r\n" ); 1316 return -1; 1317 } 1318 return 0; 1319} 1320 1321 1322#if 0 1323static const CommandDefRec gsm_in_commands[] = 1324{ 1325 { "new", "create a new 'waiting' inbound call", 1326 "'gsm in create <phonenumber>' creates a new inbound phone call, placed in\r\n" 1327 "the 'waiting' state by default, until the system answers/holds/closes it\r\n", NULL 1328 do_gsm_in_create, NULL }, 1329 1330 { "hold", "change the state of an oubtound call to 'held'", 1331 "change the state of an outbound call to 'held'. this is only possible\r\n" 1332 "if the call in the 'waiting' or 'active' state\r\n", NULL, 1333 do_gsm_out_hold, NULL }, 1334 1335 { "accept", "change the state of an outbound call to 'active'", 1336 "change the state of an outbound call to 'active'. this is only possible\r\n" 1337 "if the call is in the 'waiting' or 'held' state\r\n", NULL, 1338 do_gsm_out_accept, NULL }, 1339 1340 { NULL, NULL, NULL, NULL, NULL, NULL } 1341}; 1342#endif 1343 1344 1345static const CommandDefRec gsm_commands[] = 1346{ 1347 { "list", "list current phone calls", 1348 "'gsm list' lists all inbound and outbound calls and their state\r\n", NULL, 1349 do_gsm_list, NULL }, 1350 1351 { "call", "create inbound phone call", 1352 "'gsm call <phonenumber>' allows you to simulate a new inbound call\r\n", NULL, 1353 do_gsm_call, NULL }, 1354 1355 { "busy", "close waiting outbound call as busy", 1356 "'gsm busy <remoteNumber>' closes an outbound call, reporting\r\n" 1357 "the remote phone as busy. only possible if the call is 'waiting'.\r\n", NULL, 1358 do_gsm_busy, NULL }, 1359 1360 { "hold", "change the state of an oubtound call to 'held'", 1361 "'gsm hold <remoteNumber>' change the state of a call to 'held'. this is only possible\r\n" 1362 "if the call in the 'waiting' or 'active' state\r\n", NULL, 1363 do_gsm_hold, NULL }, 1364 1365 { "accept", "change the state of an outbound call to 'active'", 1366 "'gsm accept <remoteNumber>' change the state of a call to 'active'. this is only possible\r\n" 1367 "if the call is in the 'waiting' or 'held' state\r\n", NULL, 1368 do_gsm_accept, NULL }, 1369 1370 { "cancel", "disconnect an inbound or outbound phone call", 1371 "'gsm cancel <phonenumber>' allows you to simulate the end of an inbound or outbound call\r\n", NULL, 1372 do_gsm_cancel, NULL }, 1373 1374 { "data", "modify data connection state", NULL, help_gsm_data, 1375 do_gsm_data, NULL }, 1376 1377 { "voice", "modify voice connection state", NULL, help_gsm_voice, 1378 do_gsm_voice, NULL }, 1379 1380 { "status", "display GSM status", 1381 "'gsm status' displays the current state of the GSM emulation\r\n", NULL, 1382 do_gsm_status, NULL }, 1383 1384 { NULL, NULL, NULL, NULL, NULL, NULL } 1385}; 1386 1387/********************************************************************************************/ 1388/********************************************************************************************/ 1389/***** ******/ 1390/***** S M S C O M M A N D ******/ 1391/***** ******/ 1392/********************************************************************************************/ 1393/********************************************************************************************/ 1394 1395static int 1396do_sms_send( ControlClient client, char* args ) 1397{ 1398 char* p; 1399 int textlen; 1400 SmsAddressRec sender; 1401 SmsPDU* pdus; 1402 int nn; 1403 1404 /* check that we have a phone number made of digits */ 1405 if (!args) { 1406 MissingArgument: 1407 control_write( client, "KO: missing argument, try 'sms send <phonenumber> <text message>'\r\n" ); 1408 return -1; 1409 } 1410 p = strchr( args, ' ' ); 1411 if (!p) { 1412 goto MissingArgument; 1413 } 1414 1415 if ( sms_address_from_str( &sender, args, p - args ) < 0 ) { 1416 control_write( client, "KO: bad phone number format, must be [+](0-9)*\r\n" ); 1417 return -1; 1418 } 1419 1420 1421 /* un-secape message text into proper utf-8 (conversion happens in-site) */ 1422 p += 1; 1423 textlen = strlen(p); 1424 textlen = sms_utf8_from_message_str( p, textlen, (unsigned char*)p, textlen ); 1425 if (textlen < 0) { 1426 control_write( client, "message must be utf8 and can use the following escapes:\r\n" 1427 " \\n for a newline\r\n" 1428 " \\xNN where NN are two hexadecimal numbers\r\n" 1429 " \\uNNNN where NNNN are four hexadecimal numbers\r\n" 1430 " \\\\ to send a '\\' character\r\n\r\n" 1431 " anything else is an error\r\n" 1432 "KO: badly formatted text\r\n" ); 1433 return -1; 1434 } 1435 1436 if (!android_modem) { 1437 control_write( client, "KO: modem emulation not running\r\n" ); 1438 return -1; 1439 } 1440 1441 /* create a list of SMS PDUs, then send them */ 1442 pdus = smspdu_create_deliver_utf8( (cbytes_t)p, textlen, &sender, NULL ); 1443 if (pdus == NULL) { 1444 control_write( client, "KO: internal error when creating SMS-DELIVER PDUs\n" ); 1445 return -1; 1446 } 1447 1448 for (nn = 0; pdus[nn] != NULL; nn++) 1449 amodem_receive_sms( android_modem, pdus[nn] ); 1450 1451 smspdu_free_list( pdus ); 1452 return 0; 1453} 1454 1455static int 1456do_sms_sendpdu( ControlClient client, char* args ) 1457{ 1458 SmsPDU pdu; 1459 1460 /* check that we have a phone number made of digits */ 1461 if (!args) { 1462 control_write( client, "KO: missing argument, try 'sms sendpdu <hexstring>'\r\n" ); 1463 return -1; 1464 } 1465 1466 if (!android_modem) { 1467 control_write( client, "KO: modem emulation not running\r\n" ); 1468 return -1; 1469 } 1470 1471 pdu = smspdu_create_from_hex( args, strlen(args) ); 1472 if (pdu == NULL) { 1473 control_write( client, "KO: badly formatted <hexstring>\r\n" ); 1474 return -1; 1475 } 1476 1477 amodem_receive_sms( android_modem, pdu ); 1478 smspdu_free( pdu ); 1479 return 0; 1480} 1481 1482static const CommandDefRec sms_commands[] = 1483{ 1484 { "send", "send inbound SMS text message", 1485 "'sms send <phonenumber> <message>' allows you to simulate a new inbound sms message\r\n", NULL, 1486 do_sms_send, NULL }, 1487 1488 { "pdu", "send inbound SMS PDU", 1489 "'sms pdu <hexstring>' allows you to simulate a new inbound sms PDU\r\n" 1490 "(used internally when one emulator sends SMS messages to another instance).\r\n" 1491 "you probably don't want to play with this at all\r\n", NULL, 1492 do_sms_sendpdu, NULL }, 1493 1494 { NULL, NULL, NULL, NULL, NULL, NULL } 1495}; 1496 1497static void 1498do_control_write(void* data, const char* string) 1499{ 1500 control_write((ControlClient)data, string); 1501} 1502 1503static int 1504do_power_display( ControlClient client, char* args ) 1505{ 1506 goldfish_battery_display(do_control_write, client); 1507 return 0; 1508} 1509 1510static int 1511do_ac_state( ControlClient client, char* args ) 1512{ 1513 if (args) { 1514 if (strcasecmp(args, "on") == 0) { 1515 goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 1); 1516 return 0; 1517 } 1518 if (strcasecmp(args, "off") == 0) { 1519 goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 0); 1520 return 0; 1521 } 1522 } 1523 1524 control_write( client, "KO: Usage: \"ac on\" or \"ac off\"\n" ); 1525 return -1; 1526} 1527 1528static int 1529do_battery_status( ControlClient client, char* args ) 1530{ 1531 if (args) { 1532 if (strcasecmp(args, "unknown") == 0) { 1533 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_UNKNOWN); 1534 return 0; 1535 } 1536 if (strcasecmp(args, "charging") == 0) { 1537 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_CHARGING); 1538 return 0; 1539 } 1540 if (strcasecmp(args, "discharging") == 0) { 1541 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_DISCHARGING); 1542 return 0; 1543 } 1544 if (strcasecmp(args, "not-charging") == 0) { 1545 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_NOT_CHARGING); 1546 return 0; 1547 } 1548 if (strcasecmp(args, "full") == 0) { 1549 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_FULL); 1550 return 0; 1551 } 1552 } 1553 1554 control_write( client, "KO: Usage: \"status unknown|charging|discharging|not-charging|full\"\n" ); 1555 return -1; 1556} 1557 1558static int 1559do_battery_present( ControlClient client, char* args ) 1560{ 1561 if (args) { 1562 if (strcasecmp(args, "true") == 0) { 1563 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 1); 1564 return 0; 1565 } 1566 if (strcasecmp(args, "false") == 0) { 1567 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 0); 1568 return 0; 1569 } 1570 } 1571 1572 control_write( client, "KO: Usage: \"present true\" or \"present false\"\n" ); 1573 return -1; 1574} 1575 1576static int 1577do_battery_health( ControlClient client, char* args ) 1578{ 1579 if (args) { 1580 if (strcasecmp(args, "unknown") == 0) { 1581 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNKNOWN); 1582 return 0; 1583 } 1584 if (strcasecmp(args, "good") == 0) { 1585 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_GOOD); 1586 return 0; 1587 } 1588 if (strcasecmp(args, "overheat") == 0) { 1589 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERHEAT); 1590 return 0; 1591 } 1592 if (strcasecmp(args, "dead") == 0) { 1593 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_DEAD); 1594 return 0; 1595 } 1596 if (strcasecmp(args, "overvoltage") == 0) { 1597 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERVOLTAGE); 1598 return 0; 1599 } 1600 if (strcasecmp(args, "failure") == 0) { 1601 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNSPEC_FAILURE); 1602 return 0; 1603 } 1604 } 1605 1606 control_write( client, "KO: Usage: \"health unknown|good|overheat|dead|overvoltage|failure\"\n" ); 1607 return -1; 1608} 1609 1610static int 1611do_battery_capacity( ControlClient client, char* args ) 1612{ 1613 if (args) { 1614 int capacity; 1615 1616 if (sscanf(args, "%d", &capacity) == 1 && capacity >= 0 && capacity <= 100) { 1617 goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_CAPACITY, capacity); 1618 return 0; 1619 } 1620 } 1621 1622 control_write( client, "KO: Usage: \"capacity <percentage>\"\n" ); 1623 return -1; 1624} 1625 1626 1627static const CommandDefRec power_commands[] = 1628{ 1629 { "display", "display battery and charger state", 1630 "display battery and charger state\r\n", NULL, 1631 do_power_display, NULL }, 1632 1633 { "ac", "set AC charging state", 1634 "'ac on|off' allows you to set the AC charging state to on or off\r\n", NULL, 1635 do_ac_state, NULL }, 1636 1637 { "status", "set battery status", 1638 "'status unknown|charging|discharging|not-charging|full' allows you to set battery status\r\n", NULL, 1639 do_battery_status, NULL }, 1640 1641 { "present", "set battery present state", 1642 "'present true|false' allows you to set battery present state to true or false\r\n", NULL, 1643 do_battery_present, NULL }, 1644 1645 { "health", "set battery health state", 1646 "'health unknown|good|overheat|dead|overvoltage|failure' allows you to set battery health state\r\n", NULL, 1647 do_battery_health, NULL }, 1648 1649 { "capacity", "set battery capacity state", 1650 "'capacity <percentage>' allows you to set battery capacity to a value 0 - 100\r\n", NULL, 1651 do_battery_capacity, NULL }, 1652 1653 { NULL, NULL, NULL, NULL, NULL, NULL } 1654}; 1655 1656/********************************************************************************************/ 1657/********************************************************************************************/ 1658/***** ******/ 1659/***** E V E N T C O M M A N D S ******/ 1660/***** ******/ 1661/********************************************************************************************/ 1662/********************************************************************************************/ 1663 1664 1665static int 1666do_event_send( ControlClient client, char* args ) 1667{ 1668 char* p; 1669 1670 if (!args) { 1671 control_write( client, "KO: Usage: event send <type>:<code>:<value> ...\r\n" ); 1672 return -1; 1673 } 1674 1675 p = args; 1676 while (*p) { 1677 char* q; 1678 int type, code, value, ret; 1679 1680 p += strspn( args, " \t" ); /* skip spaces */ 1681 if (*p == 0) 1682 break; 1683 1684 q = p + strcspn( p, " \t" ); 1685 1686 if (q == p) 1687 break; 1688 1689 ret = android_event_from_str( p, &type, &code, &value ); 1690 if (ret < 0) { 1691 if (ret == -1) { 1692 control_write( client, 1693 "KO: invalid event type in '%.*s', try 'event list types' for valid values\r\n", 1694 q-p, p ); 1695 } else if (ret == -2) { 1696 control_write( client, 1697 "KO: invalid event code in '%.*s', try 'event list codes <type>' for valid values\r\n", 1698 q-p, p ); 1699 } else { 1700 control_write( client, 1701 "KO: invalid event value in '%.*s', must be an integer\r\n", 1702 q-p, p); 1703 } 1704 return -1; 1705 } 1706 1707 user_event_generic( type, code, value ); 1708 p = q; 1709 } 1710 return 0; 1711} 1712 1713static int 1714do_event_types( ControlClient client, char* args ) 1715{ 1716 int count = android_event_get_type_count(); 1717 int nn; 1718 1719 control_write( client, "event <type> can be an integer or one of the following aliases\r\n" ); 1720 for (nn = 0; nn < count; nn++) { 1721 char tmp[16]; 1722 char* p = tmp; 1723 char* end = p + sizeof(tmp); 1724 int count2 = android_event_get_code_count( nn );; 1725 1726 p = android_event_bufprint_type_str( p, end, nn ); 1727 1728 control_write( client, " %-8s", tmp ); 1729 if (count2 > 0) 1730 control_write( client, " (%d code aliases)", count2 ); 1731 1732 control_write( client, "\r\n" ); 1733 } 1734 return 0; 1735} 1736 1737static int 1738do_event_codes( ControlClient client, char* args ) 1739{ 1740 int count; 1741 int nn, type, dummy; 1742 1743 if (!args) { 1744 control_write( client, "KO: argument missing, try 'event codes <type>'\r\n" ); 1745 return -1; 1746 } 1747 1748 if ( android_event_from_str( args, &type, &dummy, &dummy ) < 0 ) { 1749 control_write( client, "KO: bad argument, see 'event types' for valid values\r\n" ); 1750 return -1; 1751 } 1752 1753 count = android_event_get_code_count( type ); 1754 if (count == 0) { 1755 control_write( client, "no code aliases defined for this type\r\n" ); 1756 } else { 1757 control_write( client, "type '%s' accepts the following <code> aliases:\r\n", 1758 args ); 1759 for (nn = 0; nn < count; nn++) { 1760 char temp[20], *p = temp, *end = p + sizeof(temp); 1761 android_event_bufprint_code_str( p, end, type, nn ); 1762 control_write( client, " %-12s\r\n", temp ); 1763 } 1764 } 1765 1766 return 0; 1767} 1768 1769static __inline__ int 1770utf8_next( unsigned char* *pp, unsigned char* end ) 1771{ 1772 unsigned char* p = *pp; 1773 int result = -1; 1774 1775 if (p < end) { 1776 int c= *p++; 1777 if (c >= 128) { 1778 if ((c & 0xe0) == 0xc0) 1779 c &= 0x1f; 1780 else if ((c & 0xf0) == 0xe0) 1781 c &= 0x0f; 1782 else 1783 c &= 0x07; 1784 1785 while (p < end && (p[0] & 0xc0) == 0x80) { 1786 c = (c << 6) | (p[0] & 0x3f); 1787 } 1788 } 1789 result = c; 1790 *pp = p; 1791 } 1792 return result; 1793} 1794 1795static int 1796do_event_text( ControlClient client, char* args ) 1797{ 1798 AKeycodeBuffer keycodes; 1799 unsigned char* p = (unsigned char*) args; 1800 unsigned char* end = p + strlen(args); 1801 int textlen; 1802 const AKeyCharmap* charmap; 1803 1804 if (!args) { 1805 control_write( client, "KO: argument missing, try 'event text <message>'\r\n" ); 1806 return -1; 1807 } 1808 1809 /* Get default charmap. */ 1810 charmap = android_get_default_charmap(); 1811 if (charmap == NULL) { 1812 control_write( client, "KO: no character map active in current device layout/config\r\n" ); 1813 return -1; 1814 } 1815 1816 keycodes.keycode_count = 0; 1817 1818 /* un-secape message text into proper utf-8 (conversion happens in-site) */ 1819 textlen = strlen((char*)p); 1820 textlen = sms_utf8_from_message_str( args, textlen, (unsigned char*)p, textlen ); 1821 if (textlen < 0) { 1822 control_write( client, "message must be utf8 and can use the following escapes:\r\n" 1823 " \\n for a newline\r\n" 1824 " \\xNN where NN are two hexadecimal numbers\r\n" 1825 " \\uNNNN where NNNN are four hexadecimal numbers\r\n" 1826 " \\\\ to send a '\\' character\r\n\r\n" 1827 " anything else is an error\r\n" 1828 "KO: badly formatted text\r\n" ); 1829 return -1; 1830 } 1831 1832 end = p + textlen; 1833 while (p < end) { 1834 int c = utf8_next( &p, end ); 1835 if (c <= 0) 1836 break; 1837 1838 android_charmap_reverse_map_unicode( NULL, (unsigned)c, 1, &keycodes ); 1839 android_charmap_reverse_map_unicode( NULL, (unsigned)c, 0, &keycodes ); 1840 android_keycodes_flush( &keycodes ); 1841 } 1842 1843 return 0; 1844} 1845 1846static const CommandDefRec event_commands[] = 1847{ 1848 { "send", "send a series of events to the kernel", 1849 "'event send <type>:<code>:<value> ...' allows your to send one or more hardware events\r\n" 1850 "to the Android kernel. you can use text names or integers for <type> and <code>\r\n", NULL, 1851 do_event_send, NULL }, 1852 1853 { "types", "list all <type> aliases", 1854 "'event types' list all <type> string aliases supported by the 'event' subcommands\r\n", 1855 NULL, do_event_types, NULL }, 1856 1857 { "codes", "list all <code> aliases for a given <type>", 1858 "'event codes <type>' lists all <code> string aliases for a given event <type>\r\n", 1859 NULL, do_event_codes, NULL }, 1860 1861 { "text", "simulate keystrokes from a given text", 1862 "'event text <message>' allows you to simulate keypresses to generate a given text\r\n" 1863 "message. <message> must be an utf-8 string. Unicode points will be reverse-mapped\r\n" 1864 "according to the current device keyboard. unsupported characters will be discarded\r\n" 1865 "silently\r\n", NULL, do_event_text, NULL }, 1866 1867 { NULL, NULL, NULL, NULL, NULL, NULL } 1868}; 1869 1870 1871/********************************************************************************************/ 1872/********************************************************************************************/ 1873/***** ******/ 1874/***** V M C O M M A N D S ******/ 1875/***** ******/ 1876/********************************************************************************************/ 1877/********************************************************************************************/ 1878 1879static int 1880do_avd_stop( ControlClient client, char* args ) 1881{ 1882 if (!vm_running) { 1883 control_write( client, "KO: virtual device already stopped\r\n" ); 1884 return -1; 1885 } 1886 vm_stop(EXCP_INTERRUPT); 1887 return 0; 1888} 1889 1890static int 1891do_avd_start( ControlClient client, char* args ) 1892{ 1893 if (vm_running) { 1894 control_write( client, "KO: virtual device already running\r\n" ); 1895 return -1; 1896 } 1897 vm_start(); 1898 return 0; 1899} 1900 1901static int 1902do_avd_status( ControlClient client, char* args ) 1903{ 1904 control_write( client, "virtual device is %s\r\n", vm_running ? "running" : "stopped" ); 1905 return 0; 1906} 1907 1908static int 1909do_avd_name( ControlClient client, char* args ) 1910{ 1911 control_write( client, "%s\r\n", avdInfo_getName(android_avdInfo) ); 1912 return 0; 1913} 1914 1915static const CommandDefRec vm_commands[] = 1916{ 1917 { "stop", "stop the virtual device", 1918 "'avd stop' stops the virtual device immediately, use 'avd start' to continue execution\r\n", 1919 NULL, do_avd_stop, NULL }, 1920 1921 { "start", "start/restart the virtual device", 1922 "'avd start' will start or continue the virtual device, use 'avd stop' to stop it\r\n", 1923 NULL, do_avd_start, NULL }, 1924 1925 { "status", "query virtual device status", 1926 "'avd status' will indicate wether the virtual device is running or not\r\n", 1927 NULL, do_avd_status, NULL }, 1928 1929 { "name", "query virtual device name", 1930 "'avd name' will return the name of this virtual device\r\n", 1931 NULL, do_avd_name, NULL }, 1932 1933 { NULL, NULL, NULL, NULL, NULL, NULL } 1934}; 1935 1936/********************************************************************************************/ 1937/********************************************************************************************/ 1938/***** ******/ 1939/***** G E O C O M M A N D S ******/ 1940/***** ******/ 1941/********************************************************************************************/ 1942/********************************************************************************************/ 1943 1944static int 1945do_geo_nmea( ControlClient client, char* args ) 1946{ 1947 if (!args) { 1948 control_write( client, "KO: NMEA sentence missing, try 'help geo nmea'\r\n" ); 1949 return -1; 1950 } 1951 if (!android_gps_cs) { 1952 control_write( client, "KO: no GPS emulation in this virtual device\r\n" ); 1953 return -1; 1954 } 1955 android_gps_send_nmea( args ); 1956 return 0; 1957} 1958 1959static int 1960do_geo_fix( ControlClient client, char* args ) 1961{ 1962#define MAX_GEO_PARAMS 3 1963 char* p = args; 1964 int n_params = 0; 1965 double params[ MAX_GEO_PARAMS ]; 1966 1967 static int last_time = 0; 1968 static double last_altitude = 0.; 1969 1970 if (!p) 1971 p = ""; 1972 1973 /* tokenize */ 1974 while (*p) { 1975 char* end; 1976 double val = strtod( p, &end ); 1977 1978 if (end == p) { 1979 control_write( client, "KO: argument '%s' is not a number\n", p ); 1980 return -1; 1981 } 1982 1983 params[n_params++] = val; 1984 if (n_params >= MAX_GEO_PARAMS) 1985 break; 1986 1987 p = end; 1988 while (*p && (p[0] == ' ' || p[0] == '\t')) 1989 p += 1; 1990 } 1991 1992 /* sanity check */ 1993 if (n_params < 2) { 1994 control_write( client, "KO: not enough arguments: see 'help geo fix' for details\r\n" ); 1995 return -1; 1996 } 1997 1998 /* generate an NMEA sentence for this fix */ 1999 { 2000 STRALLOC_DEFINE(s); 2001 double val; 2002 int deg, min; 2003 char hemi; 2004 2005 /* first, the time */ 2006 stralloc_add_format( s, "$GPGGA,%06d", last_time ); 2007 last_time ++; 2008 2009 /* then the latitude */ 2010 hemi = 'N'; 2011 val = params[1]; 2012 if (val < 0) { 2013 hemi = 'S'; 2014 val = -val; 2015 } 2016 deg = (int) val; 2017 min = 60*(val - deg); 2018 val = val - min/60.; 2019 stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)(val * 10000), hemi ); 2020 2021 /* the longitude */ 2022 hemi = 'E'; 2023 val = params[0]; 2024 if (val < 0) { 2025 hemi = 'W'; 2026 val = -val; 2027 } 2028 deg = (int) val; 2029 min = 60*(val - deg); 2030 val = val - min/60.; 2031 stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)(val * 10000), hemi ); 2032 2033 /* bogus fix quality, empty satellite count and dilutions */ 2034 stralloc_add_str( s, ",1,,,," ); 2035 2036 /* optional altitude */ 2037 if (n_params >= 3) { 2038 stralloc_add_format( s, "%.1g", params[2] ); 2039 last_altitude = params[2]; 2040 } else { 2041 stralloc_add_str( s, "," ); 2042 } 2043 /* bogus rest and checksum */ 2044 stralloc_add_str( s, ",,,*47" ); 2045 2046 /* send it, then free */ 2047 android_gps_send_nmea( stralloc_cstr(s) ); 2048 stralloc_reset( s ); 2049 } 2050 return 0; 2051} 2052 2053static const CommandDefRec geo_commands[] = 2054{ 2055 { "nmea", "send an GPS NMEA sentence", 2056 "'geo nema <sentence>' sends a NMEA 0183 sentence to the emulated device, as\r\n" 2057 "if it came from an emulated GPS modem. <sentence> must begin with '$GP'. only\r\n" 2058 "'$GPGGA' and '$GPRCM' sentences are supported at the moment.\r\n", 2059 NULL, do_geo_nmea, NULL }, 2060 2061 { "fix", "send a simple GPS fix", 2062 "'geo fix <longitude> <latitude> [<altitude>]' allows you to send a\r\n" 2063 "simple GPS fix to the emulated system. the parameters are:\r\n\r\n" 2064 " <longitude> longitude, in decimal degrees\r\n" 2065 " <latitude> latitude, in decimal degrees\r\n" 2066 " <altitude> optional altitude in meters\r\n" 2067 "\r\n", 2068 NULL, do_geo_fix, NULL }, 2069 2070 { NULL, NULL, NULL, NULL, NULL, NULL } 2071}; 2072 2073 2074/********************************************************************************************/ 2075/********************************************************************************************/ 2076/***** ******/ 2077/***** M A I N C O M M A N D S ******/ 2078/***** ******/ 2079/********************************************************************************************/ 2080/********************************************************************************************/ 2081 2082static int 2083do_window_scale( ControlClient client, char* args ) 2084{ 2085 double scale; 2086 int is_dpi = 0; 2087 char* end; 2088 2089 if (!args) { 2090 control_write( client, "KO: argument missing, try 'window scale <scale>'\r\n" ); 2091 return -1; 2092 } 2093 2094 scale = strtol( args, &end, 10 ); 2095 if (end > args && !memcmp( end, "dpi", 4 )) { 2096 is_dpi = 1; 2097 } 2098 else { 2099 scale = strtod( args, &end ); 2100 if (end == args || end[0]) { 2101 control_write( client, "KO: argument <scale> must be a real number, or an integer followed by 'dpi'\r\n" ); 2102 return -1; 2103 } 2104 } 2105 2106 android_ui_set_window_scale( scale, is_dpi ); 2107 return 0; 2108} 2109 2110static const CommandDefRec window_commands[] = 2111{ 2112 { "scale", "change the window scale", 2113 "'window scale <scale>' allows you to change the scale of the emulator window at runtime\r\n" 2114 "<scale> must be either a real number between 0.1 and 3.0, or an integer followed by\r\n" 2115 "the 'dpi' prefix (as in '120dpi')\r\n", 2116 NULL, do_window_scale, NULL }, 2117 2118 { NULL, NULL, NULL, NULL, NULL, NULL } 2119}; 2120 2121/********************************************************************************************/ 2122/********************************************************************************************/ 2123/***** ******/ 2124/***** M A I N C O M M A N D S ******/ 2125/***** ******/ 2126/********************************************************************************************/ 2127/********************************************************************************************/ 2128 2129static int 2130do_kill( ControlClient client, char* args ) 2131{ 2132 control_write( client, "OK: killing emulator, bye bye\r\n" ); 2133 exit(0); 2134} 2135 2136static const CommandDefRec main_commands[] = 2137{ 2138 { "help|h|?", "print a list of commands", NULL, NULL, do_help, NULL }, 2139 2140 { "event", "simulate hardware events", 2141 "allows you to send fake hardware events to the kernel\r\n", NULL, 2142 NULL, event_commands }, 2143 2144 { "geo", "Geo-location commands", 2145 "allows you to change Geo-related settings, or to send GPS NMEA sentences\r\n", NULL, 2146 NULL, geo_commands }, 2147 2148 { "gsm", "GSM related commands", 2149 "allows you to change GSM-related settings, or to make a new inbound phone call\r\n", NULL, 2150 NULL, gsm_commands }, 2151 2152 { "kill", "kill the emulator instance", NULL, NULL, 2153 do_kill, NULL }, 2154 2155 { "network", "manage network settings", 2156 "allows you to manage the settings related to the network data connection of the\r\n" 2157 "emulated device.\r\n", NULL, 2158 NULL, network_commands }, 2159 2160 { "power", "power related commands", 2161 "allows to change battery and AC power status\r\n", NULL, 2162 NULL, power_commands }, 2163 2164 { "quit|exit", "quit control session", NULL, NULL, 2165 do_quit, NULL }, 2166 2167 { "redir", "manage port redirections", 2168 "allows you to add, list and remove UDP and/or PORT redirection from the host to the device\r\n" 2169 "as an example, 'redir tcp:5000:6000' will route any packet sent to the host's TCP port 5000\r\n" 2170 "to TCP port 6000 of the emulated device\r\n", NULL, 2171 NULL, redir_commands }, 2172 2173 { "sms", "SMS related commands", 2174 "allows you to simulate an inbound SMS\r\n", NULL, 2175 NULL, sms_commands }, 2176 2177 { "avd", "manager virtual device state", 2178 "allows to change (e.g. start/stop) the virtual device state\r\n", NULL, 2179 NULL, vm_commands }, 2180 2181 { "window", "manage emulator window", 2182 "allows you to modify the emulator window\r\n", NULL, 2183 NULL, window_commands }, 2184 2185 { NULL, NULL, NULL, NULL, NULL, NULL } 2186}; 2187 2188 2189static ControlGlobalRec _g_global; 2190 2191int 2192control_console_start( int port ) 2193{ 2194 return control_global_init( &_g_global, port ); 2195} 2196