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