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/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 /* Strings describing the host system's OpenGL implementation */ 51 char android_gl_vendor[ANDROID_GLSTRING_BUF_SIZE]; 52 char android_gl_renderer[ANDROID_GLSTRING_BUF_SIZE]; 53 char android_gl_version[ANDROID_GLSTRING_BUF_SIZE]; 54 55 /*** APPLICATION DIRECTORY 56 *** Where are we ? 57 ***/ 58 59 const 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 71 enum { 72 REPORT_CONSOLE_SERVER = (1 << 0), 73 REPORT_CONSOLE_MAX = (1 << 1) 74 }; 75 76 static int 77 get_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 112 static void 113 report_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 */ 227 void android_emulation_setup( void ) 228 { 229 int tries = MAX_ANDROID_EMULATORS; 230 int base_port = 5554; 231 int adb_host_port = 5037; // adb's default 232 int success = 0; 233 int adb_port = -1; 234 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 248 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 257 if (android_op_port && android_op_ports) { 258 fprintf( stderr, "options -port and -ports cannot be used together.\n"); 259 exit(1); 260 } 261 262 int legacy_adb = avdInfo_getAdbdCommunicationMode(android_avdInfo) ? 0 : 1; 263 264 if (android_op_ports) { 265 char* comma_location; 266 char* end; 267 int console_port = strtol( android_op_ports, &comma_location, 0 ); 268 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 274 adb_port = strtol( comma_location+1, &end, 0 ); 275 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. 288 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 } 294 if ( control_console_start( console_port ) < 0 ) { 295 if (legacy_adb) { 296 slirp_unredir( 0, adb_port ); 297 } 298 } 299 300 base_port = console_port; 301 } else { 302 if (android_op_port) { 303 char* end; 304 int port = strtol( android_op_port, &end, 0 ); 305 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 */ 323 adb_port = base_port + 1; 324 if (legacy_adb) { 325 if ( slirp_redir( 0, adb_port, guest_ip, 5555 ) < 0 ) 326 continue; 327 } else { 328 if (adb_server_init(adb_port)) 329 continue; 330 android_adb_service_init(); 331 } 332 333 /* setup second redirection for the emulator console */ 334 if ( control_console_start( base_port ) < 0 ) { 335 if (legacy_adb) { 336 slirp_unredir( 0, adb_port ); 337 } 338 continue; 339 } 340 341 D( "control console listening on port %d, ADB on port %d", base_port, adb_port ); 342 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 352 if (android_op_report_console) { 353 report_console(android_op_report_console, base_port); 354 } 355 356 android_modem_init( base_port ); 357 358 /* Save base port. */ 359 android_base_port = base_port; 360 361 /* 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 */ 364 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]; 370 371 // 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); 378 D("sent '%s' to ADB server", tmp); 379 380 socket_close(s); 381 } 382 383 /* setup the http proxy, if any */ 384 if (VERBOSE_CHECK(proxy)) 385 proxy_set_verbose(1); 386 387 if (!op_http_proxy) { 388 op_http_proxy = getenv("http_proxy"); 389 } 390 391 do 392 { 393 const char* env = op_http_proxy; 394 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 445 D( "setting up http proxy: server=%.*s port=%d", 446 proxy_name_len, proxy_name, proxy_port ); 447 448 /* 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 458 if ( proxy_http_setup( proxy_name, proxy_name_len, proxy_port, 459 option - option_tab, option_tab ) < 0 ) 460 { 461 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 !"); 464 } 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 485 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 493 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 517 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); 523 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); 552 execl( tmp, _ANDROID_PING_PROGRAM, "ping", "emulator", VERSION_STRING, 553 android_gl_vendor, android_gl_renderer, android_gl_version, 554 NULL ); 555 } 556 END_NOSIGALRM 557 558 /* don't do anything in the parent or in case of error */ 559 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 ); 563 #endif 564 } 565 } 566 } 567 568 569