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