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