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