Home | History | Annotate | Download | only in android
      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