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