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