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 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 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 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 */ 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