blob: 4765f319b5a0d997e0d38ebc7e006732a18c72ff [file] [log] [blame]
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -07001/* 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"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010015#include "sysemu/sysemu.h"
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -070016#include "modem_driver.h"
17#include "proxy_http.h"
18
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -070019#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"
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -080026#include "android/adb-server.h"
27#include "android/adb-qemud.h"
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -070028
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
37extern int control_console_start( int port ); /* in control.c */
38
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -070039/* Contains arguments for -android-ports option. */
40char* android_op_ports = NULL;
41/* Contains arguments for -android-port option. */
42char* android_op_port = NULL;
43/* Contains arguments for -android-report-console option. */
44char* android_op_report_console = NULL;
45/* Contains arguments for -http-proxy option. */
46char* op_http_proxy = NULL;
Vladimir Chtchetkine2fa51732010-07-16 11:19:48 -070047/* Base port for the emulated system. */
48int android_base_port;
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -070049
Jesse Hall733fffa2012-04-26 11:07:32 -070050/* Strings describing the host system's OpenGL implementation */
51char android_gl_vendor[ANDROID_GLSTRING_BUF_SIZE];
52char android_gl_renderer[ANDROID_GLSTRING_BUF_SIZE];
53char android_gl_version[ANDROID_GLSTRING_BUF_SIZE];
54
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -070055/*** APPLICATION DIRECTORY
56 *** Where are we ?
57 ***/
58
59const char* get_app_dir(void)
60{
61 char buffer[1024];
62 char* p = buffer;
63 char* end = p + sizeof(buffer);
64 p = bufprint_app_dir(p, end);
65 if (p >= end)
66 return NULL;
67
68 return strdup(buffer);
69}
70
71enum {
72 REPORT_CONSOLE_SERVER = (1 << 0),
73 REPORT_CONSOLE_MAX = (1 << 1)
74};
75
76static int
77get_report_console_options( char* end, int *maxtries )
78{
79 int flags = 0;
80
81 if (end == NULL || *end == 0)
82 return 0;
83
84 if (end[0] != ',') {
85 derror( "socket port/path can be followed by [,<option>]+ only\n");
86 exit(3);
87 }
88 end += 1;
89 while (*end) {
90 char* p = strchr(end, ',');
91 if (p == NULL)
92 p = end + strlen(end);
93
94 if (memcmp( end, "server", p-end ) == 0)
95 flags |= REPORT_CONSOLE_SERVER;
96 else if (memcmp( end, "max=", 4) == 0) {
97 end += 4;
98 *maxtries = strtol( end, NULL, 10 );
99 flags |= REPORT_CONSOLE_MAX;
100 } else {
101 derror( "socket port/path can be followed by [,server][,max=<count>] only\n");
102 exit(3);
103 }
104
105 end = p;
106 if (*end)
107 end += 1;
108 }
109 return flags;
110}
111
112static void
113report_console( const char* proto_port, int console_port )
114{
115 int s = -1, s2;
116 int maxtries = 10;
117 int flags = 0;
118 signal_state_t sigstate;
119
120 disable_sigalrm( &sigstate );
121
122 if ( !strncmp( proto_port, "tcp:", 4) ) {
123 char* end;
124 long port = strtol(proto_port + 4, &end, 10);
125
126 flags = get_report_console_options( end, &maxtries );
127
128 if (flags & REPORT_CONSOLE_SERVER) {
129 s = socket_loopback_server( port, SOCKET_STREAM );
130 if (s < 0) {
131 fprintf(stderr, "could not create server socket on TCP:%ld: %s\n",
132 port, errno_str);
133 exit(3);
134 }
135 } else {
136 for ( ; maxtries > 0; maxtries-- ) {
137 D("trying to find console-report client on tcp:%d", port);
138 s = socket_loopback_client( port, SOCKET_STREAM );
139 if (s >= 0)
140 break;
141
142 sleep_ms(1000);
143 }
144 if (s < 0) {
145 fprintf(stderr, "could not connect to server on TCP:%ld: %s\n",
146 port, errno_str);
147 exit(3);
148 }
149 }
150 } else if ( !strncmp( proto_port, "unix:", 5) ) {
151#ifdef _WIN32
152 fprintf(stderr, "sorry, the unix: protocol is not supported on Win32\n");
153 exit(3);
154#else
155 char* path = strdup(proto_port+5);
156 char* end = strchr(path, ',');
157 if (end != NULL) {
158 flags = get_report_console_options( end, &maxtries );
159 *end = 0;
160 }
161 if (flags & REPORT_CONSOLE_SERVER) {
162 s = socket_unix_server( path, SOCKET_STREAM );
163 if (s < 0) {
164 fprintf(stderr, "could not bind unix socket on '%s': %s\n",
165 proto_port+5, errno_str);
166 exit(3);
167 }
168 } else {
169 for ( ; maxtries > 0; maxtries-- ) {
170 s = socket_unix_client( path, SOCKET_STREAM );
171 if (s >= 0)
172 break;
173
174 sleep_ms(1000);
175 }
176 if (s < 0) {
177 fprintf(stderr, "could not connect to unix socket on '%s': %s\n",
178 path, errno_str);
179 exit(3);
180 }
181 }
182 free(path);
183#endif
184 } else {
185 fprintf(stderr, "-report-console must be followed by a 'tcp:<port>' or 'unix:<path>'\n");
186 exit(3);
187 }
188
189 if (flags & REPORT_CONSOLE_SERVER) {
190 int tries = 3;
191 D( "waiting for console-reporting client" );
192 do {
193 s2 = socket_accept(s, NULL);
194 } while (s2 < 0 && --tries > 0);
195
196 if (s2 < 0) {
197 fprintf(stderr, "could not accept console-reporting client connection: %s\n",
198 errno_str);
199 exit(3);
200 }
201
202 socket_close(s);
203 s = s2;
204 }
205
206 /* simply send the console port in text */
207 {
208 char temp[12];
209 snprintf( temp, sizeof(temp), "%d", console_port );
210
211 if (socket_send(s, temp, strlen(temp)) < 0) {
212 fprintf(stderr, "could not send console number report: %d: %s\n",
213 errno, errno_str );
214 exit(3);
215 }
216 socket_close(s);
217 }
218 D( "console port number sent to remote. resuming boot" );
219
220 restore_sigalrm (&sigstate);
221}
222
223/* this function is called from qemu_main() once all arguments have been parsed
224 * it should be used to setup any Android-specific items in the emulation before the
225 * main loop runs
226 */
227void android_emulation_setup( void )
228{
229 int tries = 16;
230 int base_port = 5554;
231 int adb_host_port = 5037; // adb's default
232 int success = 0;
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100233 int adb_port = -1;
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700234 uint32_t guest_ip;
235
236 /* Set the port where the emulator expects adb to run on the host
237 * machine */
238 char* adb_host_port_str = getenv( "ANDROID_ADB_SERVER_PORT" );
239 if ( adb_host_port_str && strlen( adb_host_port_str ) > 0 ) {
240 adb_host_port = (int) strtol( adb_host_port_str, NULL, 0 );
241 if ( adb_host_port <= 0 ) {
242 derror( "env var ANDROID_ADB_SERVER_PORT must be a number > 0. Got \"%s\"\n",
243 adb_host_port_str );
244 exit(1);
245 }
246 }
247
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700248 inet_strtoip("10.0.2.15", &guest_ip);
249
250#if 0
251 if (opts->adb_port) {
252 fprintf( stderr, "option -adb-port is obsolete, use -port instead\n" );
253 exit(1);
254 }
255#endif
256
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -0700257 if (android_op_port && android_op_ports) {
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700258 fprintf( stderr, "options -port and -ports cannot be used together.\n");
259 exit(1);
260 }
261
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -0800262 int legacy_adb = avdInfo_getAdbdCommunicationMode(android_avdInfo) ? 0 : 1;
263
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -0700264 if (android_op_ports) {
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700265 char* comma_location;
266 char* end;
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -0700267 int console_port = strtol( android_op_ports, &comma_location, 0 );
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700268
269 if ( comma_location == NULL || *comma_location != ',' ) {
270 derror( "option -ports must be followed by two comma separated positive integer numbers" );
271 exit(1);
272 }
273
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100274 adb_port = strtol( comma_location+1, &end, 0 );
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700275
276 if ( end == NULL || *end ) {
277 derror( "option -ports must be followed by two comma separated positive integer numbers" );
278 exit(1);
279 }
280
281 if ( console_port == adb_port ) {
282 derror( "option -ports must be followed by two different integer numbers" );
283 exit(1);
284 }
285
286 // Set up redirect from host to guest system. adbd on the guest listens
287 // on 5555.
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -0800288 if (legacy_adb) {
289 slirp_redir( 0, adb_port, guest_ip, 5555 );
290 } else {
291 adb_server_init(adb_port);
292 android_adb_service_init();
293 }
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700294 if ( control_console_start( console_port ) < 0 ) {
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -0800295 if (legacy_adb) {
296 slirp_unredir( 0, adb_port );
297 }
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700298 }
299
300 base_port = console_port;
301 } else {
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -0700302 if (android_op_port) {
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700303 char* end;
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -0700304 int port = strtol( android_op_port, &end, 0 );
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700305 if ( end == NULL || *end ||
306 (unsigned)((port - base_port) >> 1) >= (unsigned)tries ) {
307 derror( "option -port must be followed by an even integer number between %d and %d\n",
308 base_port, base_port + (tries-1)*2 );
309 exit(1);
310 }
311 if ( (port & 1) != 0 ) {
312 port &= ~1;
313 dwarning( "option -port must be followed by an even integer, using port number %d\n",
314 port );
315 }
316 base_port = port;
317 tries = 1;
318 }
319
320 for ( ; tries > 0; tries--, base_port += 2 ) {
321
322 /* setup first redirection for ADB, the Android Debug Bridge */
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100323 adb_port = base_port + 1;
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -0800324 if (legacy_adb) {
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100325 if ( slirp_redir( 0, adb_port, guest_ip, 5555 ) < 0 )
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -0800326 continue;
327 } else {
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100328 if (adb_server_init(adb_port))
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -0800329 continue;
330 android_adb_service_init();
331 }
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700332
333 /* setup second redirection for the emulator console */
334 if ( control_console_start( base_port ) < 0 ) {
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -0800335 if (legacy_adb) {
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100336 slirp_unredir( 0, adb_port );
Vladimir Chtchetkined86c7242011-12-09 15:45:46 -0800337 }
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700338 continue;
339 }
340
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100341 D( "control console listening on port %d, ADB on port %d", base_port, adb_port );
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700342 success = 1;
343 break;
344 }
345
346 if (!success) {
347 fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" );
348 exit(1);
349 }
350 }
351
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -0700352 if (android_op_report_console) {
353 report_console(android_op_report_console, base_port);
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700354 }
355
356 android_modem_init( base_port );
357
Vladimir Chtchetkine57584042011-01-20 16:15:30 -0800358 /* Save base port. */
Vladimir Chtchetkinecefa7442010-09-01 09:17:11 -0700359 android_base_port = base_port;
David 'Digit' Turner3cf34f22010-07-30 16:53:39 -0700360
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700361 /* send a simple message to the ADB host server to tell it we just started.
362 * it should be listening on port 5037. if we can't reach it, don't bother
363 */
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100364 int s = socket_loopback_client(adb_host_port, SOCKET_STREAM);
365 if (s < 0) {
366 D("can't connect to ADB server: %s", errno_str );
367 } else {
368 char tmp[32];
369 char header[5];
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700370
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100371 // Expected format: <hex4>host:emulator:<port>
372 // Where <port> is the decimal adb port number, and <hex4> is the length
373 // of the payload that follows it in hex.
374 int len = snprintf(tmp, sizeof tmp, "0000host:emulator:%d", adb_port);
375 snprintf(header, sizeof header, "%04x", len - 4);
376 memcpy(tmp, header, 4);
377 socket_send(s, tmp, len);
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700378 D("sent '%s' to ADB server", tmp);
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700379
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700380 socket_close(s);
David 'Digit' Turner3237fe02014-01-21 02:18:12 +0100381 }
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700382
383 /* setup the http proxy, if any */
384 if (VERBOSE_CHECK(proxy))
385 proxy_set_verbose(1);
386
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -0700387 if (!op_http_proxy) {
388 op_http_proxy = getenv("http_proxy");
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700389 }
390
391 do
392 {
Vladimir Chtchetkined81e6d12010-06-15 16:46:32 -0700393 const char* env = op_http_proxy;
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700394 int envlen;
395 ProxyOption option_tab[4];
396 ProxyOption* option = option_tab;
397 char* p;
398 char* q;
399 const char* proxy_name;
400 int proxy_name_len;
401 int proxy_port;
402
403 if (!env)
404 break;
405
406 envlen = strlen(env);
407
408 /* skip the 'http://' header, if present */
409 if (envlen >= 7 && !memcmp(env, "http://", 7)) {
410 env += 7;
411 envlen -= 7;
412 }
413
414 /* do we have a username:password pair ? */
415 p = strchr(env, '@');
416 if (p != 0) {
417 q = strchr(env, ':');
418 if (q == NULL) {
419 BadHttpProxyFormat:
420 dprint("http_proxy format unsupported, try 'proxy:port' or 'username:password@proxy:port'");
421 break;
422 }
423
424 option->type = PROXY_OPTION_AUTH_USERNAME;
425 option->string = env;
426 option->string_len = q - env;
427 option++;
428
429 option->type = PROXY_OPTION_AUTH_PASSWORD;
430 option->string = q+1;
431 option->string_len = p - (q+1);
432 option++;
433
434 env = p+1;
435 }
436
437 p = strchr(env,':');
438 if (p == NULL)
439 goto BadHttpProxyFormat;
440
441 proxy_name = env;
442 proxy_name_len = p - env;
443 proxy_port = atoi(p+1);
444
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700445 D( "setting up http proxy: server=%.*s port=%d",
446 proxy_name_len, proxy_name, proxy_port );
447
David 'Digit' Turner9b98dbd2010-07-30 15:35:00 -0700448 /* Check that we can connect to the proxy in the next second.
449 * If not, the proxy setting is probably garbage !!
450 */
451 if ( proxy_check_connection( proxy_name, proxy_name_len, proxy_port, 1000 ) < 0) {
452 dprint("Could not connect to proxy at %.*s:%d: %s !",
453 proxy_name_len, proxy_name, proxy_port, errno_str);
454 dprint("Proxy will be ignored !");
455 break;
456 }
457
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700458 if ( proxy_http_setup( proxy_name, proxy_name_len, proxy_port,
459 option - option_tab, option_tab ) < 0 )
460 {
David 'Digit' Turner9b98dbd2010-07-30 15:35:00 -0700461 dprint( "Http proxy setup failed for '%.*s:%d': %s",
462 proxy_name_len, proxy_name, proxy_port, errno_str);
463 dprint( "Proxy will be ignored !");
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700464 }
465 }
466 while (0);
467
468 /* initialize sensors, this must be done here due to timer issues */
469 android_hw_sensors_init();
470
471 /* cool, now try to run the "ddms ping" command, which will take care of pinging usage
472 * if the user agreed for it. the emulator itself never sends anything to any outside
473 * machine
474 */
475 {
476#ifdef _WIN32
477# define _ANDROID_PING_PROGRAM "ddms.bat"
478#else
479# define _ANDROID_PING_PROGRAM "ddms"
480#endif
481
482 char tmp[PATH_MAX];
483 const char* appdir = get_app_dir();
484
Jesse Hall733fffa2012-04-26 11:07:32 -0700485 const size_t ARGSLEN =
486 PATH_MAX + // max ping program path
487 10 + // max VERSION_STRING length
488 3*ANDROID_GLSTRING_BUF_SIZE + // max GL string lengths
489 29 + // static args characters
490 1; // NUL terminator
491 char args[ARGSLEN];
492
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700493 if (snprintf( tmp, PATH_MAX, "%s%s%s", appdir, PATH_SEP,
494 _ANDROID_PING_PROGRAM ) >= PATH_MAX) {
495 dprint( "Application directory too long: %s", appdir);
496 return;
497 }
498
499 /* if the program isn't there, don't bother */
500 D( "ping program: %s", tmp);
501 if (path_exists(tmp)) {
502#ifdef _WIN32
503 STARTUPINFO startup;
504 PROCESS_INFORMATION pinfo;
505
506 ZeroMemory( &startup, sizeof(startup) );
507 startup.cb = sizeof(startup);
508 startup.dwFlags = STARTF_USESHOWWINDOW;
509 startup.wShowWindow = SW_SHOWMINIMIZED;
510
511 ZeroMemory( &pinfo, sizeof(pinfo) );
512
513 char* comspec = getenv("COMSPEC");
514 if (!comspec) comspec = "cmd.exe";
515
516 // Run
Jesse Hall733fffa2012-04-26 11:07:32 -0700517 if (snprintf(args, ARGSLEN,
518 "/C \"%s\" ping emulator " VERSION_STRING " \"%s\" \"%s\" \"%s\"",
519 tmp, android_gl_vendor, android_gl_renderer, android_gl_version)
520 >= ARGSLEN)
521 {
522 D( "DDMS command line too long: %s", args);
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700523 return;
524 }
525
526 CreateProcess(
527 comspec, /* program path */
528 args, /* command line args */
529 NULL, /* process handle is not inheritable */
530 NULL, /* thread handle is not inheritable */
531 FALSE, /* no, don't inherit any handles */
532 DETACHED_PROCESS, /* the new process doesn't have a console */
533 NULL, /* use parent's environment block */
534 NULL, /* use parent's starting directory */
535 &startup, /* startup info, i.e. std handles */
536 &pinfo );
537
538 D( "ping command: %s %s", comspec, args );
539#else
540 int pid;
541
542 /* disable SIGALRM for the fork(), the periodic signal seems to
543 * interefere badly with the fork() implementation on Linux running
544 * under VMWare.
545 */
546 BEGIN_NOSIGALRM
547 pid = fork();
548 if (pid == 0) {
549 int fd = open("/dev/null", O_WRONLY);
550 dup2(fd, 1);
551 dup2(fd, 2);
Jesse Hall733fffa2012-04-26 11:07:32 -0700552 execl( tmp, _ANDROID_PING_PROGRAM, "ping", "emulator", VERSION_STRING,
553 android_gl_vendor, android_gl_renderer, android_gl_version,
554 NULL );
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700555 }
556 END_NOSIGALRM
557
558 /* don't do anything in the parent or in case of error */
Jesse Hall733fffa2012-04-26 11:07:32 -0700559 snprintf(args, ARGSLEN,
560 "%s ping emulator " VERSION_STRING " \"%s\" \"%s\" \"%s\"",
561 tmp, android_gl_vendor, android_gl_renderer, android_gl_version);
562 D( "ping command: %s", args );
Vladimir Chtchetkined27aca12010-05-13 11:04:42 -0700563#endif
564 }
565 }
566}
567
568