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