1 /* Copyright (C) 2006-2010 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 #include "libslirp.h"
14 #include "qemu-common.h"
15 #include "sysemu.h"
16 #include "modem_driver.h"
17 #include "proxy_http.h"
18
19 #include "android/android.h"
20 #include "android/globals.h"
21 #include "android/hw-sensors.h"
22 #include "android/utils/debug.h"
23 #include "android/utils/path.h"
24 #include "android/utils/system.h"
25 #include "android/utils/bufprint.h"
26 #include "android/adb-server.h"
27 #include "android/adb-qemud.h"
28
29 #define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
30
31 #ifdef ANDROID_SDK_TOOLS_REVISION
32 # define VERSION_STRING STRINGIFY(ANDROID_SDK_TOOLS_REVISION)".0"
33 #else
34 # define VERSION_STRING "standalone"
35 #endif
36
37 extern int control_console_start( int port ); /* in control.c */
38
39 /* Contains arguments for -android-ports option. */
40 char* android_op_ports = NULL;
41 /* Contains arguments for -android-port option. */
42 char* android_op_port = NULL;
43 /* Contains arguments for -android-report-console option. */
44 char* android_op_report_console = NULL;
45 /* Contains arguments for -http-proxy option. */
46 char* op_http_proxy = NULL;
47 /* Base port for the emulated system. */
48 int android_base_port;
49
50 /*** APPLICATION DIRECTORY
51 *** Where are we ?
52 ***/
53
get_app_dir(void)54 const char* get_app_dir(void)
55 {
56 char buffer[1024];
57 char* p = buffer;
58 char* end = p + sizeof(buffer);
59 p = bufprint_app_dir(p, end);
60 if (p >= end)
61 return NULL;
62
63 return strdup(buffer);
64 }
65
66 enum {
67 REPORT_CONSOLE_SERVER = (1 << 0),
68 REPORT_CONSOLE_MAX = (1 << 1)
69 };
70
71 static int
get_report_console_options(char * end,int * maxtries)72 get_report_console_options( char* end, int *maxtries )
73 {
74 int flags = 0;
75
76 if (end == NULL || *end == 0)
77 return 0;
78
79 if (end[0] != ',') {
80 derror( "socket port/path can be followed by [,<option>]+ only\n");
81 exit(3);
82 }
83 end += 1;
84 while (*end) {
85 char* p = strchr(end, ',');
86 if (p == NULL)
87 p = end + strlen(end);
88
89 if (memcmp( end, "server", p-end ) == 0)
90 flags |= REPORT_CONSOLE_SERVER;
91 else if (memcmp( end, "max=", 4) == 0) {
92 end += 4;
93 *maxtries = strtol( end, NULL, 10 );
94 flags |= REPORT_CONSOLE_MAX;
95 } else {
96 derror( "socket port/path can be followed by [,server][,max=<count>] only\n");
97 exit(3);
98 }
99
100 end = p;
101 if (*end)
102 end += 1;
103 }
104 return flags;
105 }
106
107 static void
report_console(const char * proto_port,int console_port)108 report_console( const char* proto_port, int console_port )
109 {
110 int s = -1, s2;
111 int maxtries = 10;
112 int flags = 0;
113 signal_state_t sigstate;
114
115 disable_sigalrm( &sigstate );
116
117 if ( !strncmp( proto_port, "tcp:", 4) ) {
118 char* end;
119 long port = strtol(proto_port + 4, &end, 10);
120
121 flags = get_report_console_options( end, &maxtries );
122
123 if (flags & REPORT_CONSOLE_SERVER) {
124 s = socket_loopback_server( port, SOCKET_STREAM );
125 if (s < 0) {
126 fprintf(stderr, "could not create server socket on TCP:%ld: %s\n",
127 port, errno_str);
128 exit(3);
129 }
130 } else {
131 for ( ; maxtries > 0; maxtries-- ) {
132 D("trying to find console-report client on tcp:%d", port);
133 s = socket_loopback_client( port, SOCKET_STREAM );
134 if (s >= 0)
135 break;
136
137 sleep_ms(1000);
138 }
139 if (s < 0) {
140 fprintf(stderr, "could not connect to server on TCP:%ld: %s\n",
141 port, errno_str);
142 exit(3);
143 }
144 }
145 } else if ( !strncmp( proto_port, "unix:", 5) ) {
146 #ifdef _WIN32
147 fprintf(stderr, "sorry, the unix: protocol is not supported on Win32\n");
148 exit(3);
149 #else
150 char* path = strdup(proto_port+5);
151 char* end = strchr(path, ',');
152 if (end != NULL) {
153 flags = get_report_console_options( end, &maxtries );
154 *end = 0;
155 }
156 if (flags & REPORT_CONSOLE_SERVER) {
157 s = socket_unix_server( path, SOCKET_STREAM );
158 if (s < 0) {
159 fprintf(stderr, "could not bind unix socket on '%s': %s\n",
160 proto_port+5, errno_str);
161 exit(3);
162 }
163 } else {
164 for ( ; maxtries > 0; maxtries-- ) {
165 s = socket_unix_client( path, SOCKET_STREAM );
166 if (s >= 0)
167 break;
168
169 sleep_ms(1000);
170 }
171 if (s < 0) {
172 fprintf(stderr, "could not connect to unix socket on '%s': %s\n",
173 path, errno_str);
174 exit(3);
175 }
176 }
177 free(path);
178 #endif
179 } else {
180 fprintf(stderr, "-report-console must be followed by a 'tcp:<port>' or 'unix:<path>'\n");
181 exit(3);
182 }
183
184 if (flags & REPORT_CONSOLE_SERVER) {
185 int tries = 3;
186 D( "waiting for console-reporting client" );
187 do {
188 s2 = socket_accept(s, NULL);
189 } while (s2 < 0 && --tries > 0);
190
191 if (s2 < 0) {
192 fprintf(stderr, "could not accept console-reporting client connection: %s\n",
193 errno_str);
194 exit(3);
195 }
196
197 socket_close(s);
198 s = s2;
199 }
200
201 /* simply send the console port in text */
202 {
203 char temp[12];
204 snprintf( temp, sizeof(temp), "%d", console_port );
205
206 if (socket_send(s, temp, strlen(temp)) < 0) {
207 fprintf(stderr, "could not send console number report: %d: %s\n",
208 errno, errno_str );
209 exit(3);
210 }
211 socket_close(s);
212 }
213 D( "console port number sent to remote. resuming boot" );
214
215 restore_sigalrm (&sigstate);
216 }
217
218 /* this function is called from qemu_main() once all arguments have been parsed
219 * it should be used to setup any Android-specific items in the emulation before the
220 * main loop runs
221 */
android_emulation_setup(void)222 void android_emulation_setup( void )
223 {
224 int tries = 16;
225 int base_port = 5554;
226 int adb_host_port = 5037; // adb's default
227 int success = 0;
228 int s;
229 uint32_t guest_ip;
230
231 /* Set the port where the emulator expects adb to run on the host
232 * machine */
233 char* adb_host_port_str = getenv( "ANDROID_ADB_SERVER_PORT" );
234 if ( adb_host_port_str && strlen( adb_host_port_str ) > 0 ) {
235 adb_host_port = (int) strtol( adb_host_port_str, NULL, 0 );
236 if ( adb_host_port <= 0 ) {
237 derror( "env var ANDROID_ADB_SERVER_PORT must be a number > 0. Got \"%s\"\n",
238 adb_host_port_str );
239 exit(1);
240 }
241 }
242
243 inet_strtoip("10.0.2.15", &guest_ip);
244
245 #if 0
246 if (opts->adb_port) {
247 fprintf( stderr, "option -adb-port is obsolete, use -port instead\n" );
248 exit(1);
249 }
250 #endif
251
252 if (android_op_port && android_op_ports) {
253 fprintf( stderr, "options -port and -ports cannot be used together.\n");
254 exit(1);
255 }
256
257 int legacy_adb = avdInfo_getAdbdCommunicationMode(android_avdInfo) ? 0 : 1;
258
259 if (android_op_ports) {
260 char* comma_location;
261 char* end;
262 int console_port = strtol( android_op_ports, &comma_location, 0 );
263
264 if ( comma_location == NULL || *comma_location != ',' ) {
265 derror( "option -ports must be followed by two comma separated positive integer numbers" );
266 exit(1);
267 }
268
269 int adb_port = strtol( comma_location+1, &end, 0 );
270
271 if ( end == NULL || *end ) {
272 derror( "option -ports must be followed by two comma separated positive integer numbers" );
273 exit(1);
274 }
275
276 if ( console_port == adb_port ) {
277 derror( "option -ports must be followed by two different integer numbers" );
278 exit(1);
279 }
280
281 // Set up redirect from host to guest system. adbd on the guest listens
282 // on 5555.
283 if (legacy_adb) {
284 slirp_redir( 0, adb_port, guest_ip, 5555 );
285 } else {
286 adb_server_init(adb_port);
287 android_adb_service_init();
288 }
289 if ( control_console_start( console_port ) < 0 ) {
290 if (legacy_adb) {
291 slirp_unredir( 0, adb_port );
292 }
293 }
294
295 base_port = console_port;
296 } else {
297 if (android_op_port) {
298 char* end;
299 int port = strtol( android_op_port, &end, 0 );
300 if ( end == NULL || *end ||
301 (unsigned)((port - base_port) >> 1) >= (unsigned)tries ) {
302 derror( "option -port must be followed by an even integer number between %d and %d\n",
303 base_port, base_port + (tries-1)*2 );
304 exit(1);
305 }
306 if ( (port & 1) != 0 ) {
307 port &= ~1;
308 dwarning( "option -port must be followed by an even integer, using port number %d\n",
309 port );
310 }
311 base_port = port;
312 tries = 1;
313 }
314
315 for ( ; tries > 0; tries--, base_port += 2 ) {
316
317 /* setup first redirection for ADB, the Android Debug Bridge */
318 if (legacy_adb) {
319 if ( slirp_redir( 0, base_port+1, guest_ip, 5555 ) < 0 )
320 continue;
321 } else {
322 if (adb_server_init(base_port+1))
323 continue;
324 android_adb_service_init();
325 }
326
327 /* setup second redirection for the emulator console */
328 if ( control_console_start( base_port ) < 0 ) {
329 if (legacy_adb) {
330 slirp_unredir( 0, base_port+1 );
331 }
332 continue;
333 }
334
335 D( "control console listening on port %d, ADB on port %d", base_port, base_port+1 );
336 success = 1;
337 break;
338 }
339
340 if (!success) {
341 fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" );
342 exit(1);
343 }
344 }
345
346 if (android_op_report_console) {
347 report_console(android_op_report_console, base_port);
348 }
349
350 android_modem_init( base_port );
351
352 /* Save base port. */
353 android_base_port = base_port;
354
355 /* send a simple message to the ADB host server to tell it we just started.
356 * it should be listening on port 5037. if we can't reach it, don't bother
357 */
358 do
359 {
360 SockAddress addr;
361 char tmp[32];
362
363 s = socket_create_inet( SOCKET_STREAM );
364 if (s < 0) {
365 D("can't create socket to talk to the ADB server");
366 break;
367 }
368
369 sock_address_init_inet( &addr, SOCK_ADDRESS_INET_LOOPBACK, adb_host_port );
370 if (socket_connect( s, &addr ) < 0) {
371 D("can't connect to ADB server: %s", errno_str );
372 break;
373 }
374
375 sprintf(tmp,"0012host:emulator:%d",base_port+1);
376 socket_send(s, tmp, 18+4);
377 D("sent '%s' to ADB server", tmp);
378 }
379 while (0);
380
381 if (s >= 0)
382 socket_close(s);
383
384 /* setup the http proxy, if any */
385 if (VERBOSE_CHECK(proxy))
386 proxy_set_verbose(1);
387
388 if (!op_http_proxy) {
389 op_http_proxy = getenv("http_proxy");
390 }
391
392 do
393 {
394 const char* env = op_http_proxy;
395 int envlen;
396 ProxyOption option_tab[4];
397 ProxyOption* option = option_tab;
398 char* p;
399 char* q;
400 const char* proxy_name;
401 int proxy_name_len;
402 int proxy_port;
403
404 if (!env)
405 break;
406
407 envlen = strlen(env);
408
409 /* skip the 'http://' header, if present */
410 if (envlen >= 7 && !memcmp(env, "http://", 7)) {
411 env += 7;
412 envlen -= 7;
413 }
414
415 /* do we have a username:password pair ? */
416 p = strchr(env, '@');
417 if (p != 0) {
418 q = strchr(env, ':');
419 if (q == NULL) {
420 BadHttpProxyFormat:
421 dprint("http_proxy format unsupported, try 'proxy:port' or 'username:password@proxy:port'");
422 break;
423 }
424
425 option->type = PROXY_OPTION_AUTH_USERNAME;
426 option->string = env;
427 option->string_len = q - env;
428 option++;
429
430 option->type = PROXY_OPTION_AUTH_PASSWORD;
431 option->string = q+1;
432 option->string_len = p - (q+1);
433 option++;
434
435 env = p+1;
436 }
437
438 p = strchr(env,':');
439 if (p == NULL)
440 goto BadHttpProxyFormat;
441
442 proxy_name = env;
443 proxy_name_len = p - env;
444 proxy_port = atoi(p+1);
445
446 D( "setting up http proxy: server=%.*s port=%d",
447 proxy_name_len, proxy_name, proxy_port );
448
449 /* Check that we can connect to the proxy in the next second.
450 * If not, the proxy setting is probably garbage !!
451 */
452 if ( proxy_check_connection( proxy_name, proxy_name_len, proxy_port, 1000 ) < 0) {
453 dprint("Could not connect to proxy at %.*s:%d: %s !",
454 proxy_name_len, proxy_name, proxy_port, errno_str);
455 dprint("Proxy will be ignored !");
456 break;
457 }
458
459 if ( proxy_http_setup( proxy_name, proxy_name_len, proxy_port,
460 option - option_tab, option_tab ) < 0 )
461 {
462 dprint( "Http proxy setup failed for '%.*s:%d': %s",
463 proxy_name_len, proxy_name, proxy_port, errno_str);
464 dprint( "Proxy will be ignored !");
465 }
466 }
467 while (0);
468
469 /* initialize sensors, this must be done here due to timer issues */
470 android_hw_sensors_init();
471
472 /* cool, now try to run the "ddms ping" command, which will take care of pinging usage
473 * if the user agreed for it. the emulator itself never sends anything to any outside
474 * machine
475 */
476 {
477 #ifdef _WIN32
478 # define _ANDROID_PING_PROGRAM "ddms.bat"
479 #else
480 # define _ANDROID_PING_PROGRAM "ddms"
481 #endif
482
483 char tmp[PATH_MAX];
484 const char* appdir = get_app_dir();
485
486 if (snprintf( tmp, PATH_MAX, "%s%s%s", appdir, PATH_SEP,
487 _ANDROID_PING_PROGRAM ) >= PATH_MAX) {
488 dprint( "Application directory too long: %s", appdir);
489 return;
490 }
491
492 /* if the program isn't there, don't bother */
493 D( "ping program: %s", tmp);
494 if (path_exists(tmp)) {
495 #ifdef _WIN32
496 STARTUPINFO startup;
497 PROCESS_INFORMATION pinfo;
498
499 ZeroMemory( &startup, sizeof(startup) );
500 startup.cb = sizeof(startup);
501 startup.dwFlags = STARTF_USESHOWWINDOW;
502 startup.wShowWindow = SW_SHOWMINIMIZED;
503
504 ZeroMemory( &pinfo, sizeof(pinfo) );
505
506 char* comspec = getenv("COMSPEC");
507 if (!comspec) comspec = "cmd.exe";
508
509 // Run
510 char args[PATH_MAX + 30];
511 if (snprintf( args, PATH_MAX, "/C \"%s\" ping emulator " VERSION_STRING,
512 tmp) >= PATH_MAX ) {
513 D( "DDMS path too long: %s", tmp);
514 return;
515 }
516
517 CreateProcess(
518 comspec, /* program path */
519 args, /* command line args */
520 NULL, /* process handle is not inheritable */
521 NULL, /* thread handle is not inheritable */
522 FALSE, /* no, don't inherit any handles */
523 DETACHED_PROCESS, /* the new process doesn't have a console */
524 NULL, /* use parent's environment block */
525 NULL, /* use parent's starting directory */
526 &startup, /* startup info, i.e. std handles */
527 &pinfo );
528
529 D( "ping command: %s %s", comspec, args );
530 #else
531 int pid;
532
533 /* disable SIGALRM for the fork(), the periodic signal seems to
534 * interefere badly with the fork() implementation on Linux running
535 * under VMWare.
536 */
537 BEGIN_NOSIGALRM
538 pid = fork();
539 if (pid == 0) {
540 int fd = open("/dev/null", O_WRONLY);
541 dup2(fd, 1);
542 dup2(fd, 2);
543 execl( tmp, _ANDROID_PING_PROGRAM, "ping", "emulator", VERSION_STRING, NULL );
544 }
545 END_NOSIGALRM
546
547 /* don't do anything in the parent or in case of error */
548 strncat( tmp, " ping emulator " VERSION_STRING, PATH_MAX - strlen(tmp) );
549 D( "ping command: %s", tmp );
550 #endif
551 }
552 }
553 }
554
555
556