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 /* 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     = 16;
    230     int   base_port = 5554;
    231     int   adb_host_port = 5037; // adb's default
    232     int   success   = 0;
    233     int   s;
    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         int 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             if (legacy_adb) {
    324                 if ( slirp_redir( 0, base_port+1, guest_ip, 5555 ) < 0 )
    325                     continue;
    326             } else {
    327                 if (adb_server_init(base_port+1))
    328                     continue;
    329                 android_adb_service_init();
    330             }
    331 
    332             /* setup second redirection for the emulator console */
    333             if ( control_console_start( base_port ) < 0 ) {
    334                 if (legacy_adb) {
    335                     slirp_unredir( 0, base_port+1 );
    336                 }
    337                 continue;
    338             }
    339 
    340             D( "control console listening on port %d, ADB on port %d", base_port, base_port+1 );
    341             success = 1;
    342             break;
    343         }
    344 
    345         if (!success) {
    346             fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" );
    347             exit(1);
    348         }
    349     }
    350 
    351     if (android_op_report_console) {
    352         report_console(android_op_report_console, base_port);
    353     }
    354 
    355     android_modem_init( base_port );
    356 
    357     /* Save base port. */
    358     android_base_port = base_port;
    359 
    360    /* send a simple message to the ADB host server to tell it we just started.
    361     * it should be listening on port 5037. if we can't reach it, don't bother
    362     */
    363     do
    364     {
    365         SockAddress  addr;
    366         char         tmp[32];
    367 
    368         s = socket_create_inet( SOCKET_STREAM );
    369         if (s < 0) {
    370             D("can't create socket to talk to the ADB server");
    371             break;
    372         }
    373 
    374         sock_address_init_inet( &addr, SOCK_ADDRESS_INET_LOOPBACK, adb_host_port );
    375         if (socket_connect( s, &addr ) < 0) {
    376             D("can't connect to ADB server: %s", errno_str );
    377             break;
    378         }
    379 
    380         sprintf(tmp,"0012host:emulator:%d",base_port+1);
    381         socket_send(s, tmp, 18+4);
    382         D("sent '%s' to ADB server", tmp);
    383     }
    384     while (0);
    385 
    386     if (s >= 0)
    387         socket_close(s);
    388 
    389     /* setup the http proxy, if any */
    390     if (VERBOSE_CHECK(proxy))
    391         proxy_set_verbose(1);
    392 
    393     if (!op_http_proxy) {
    394         op_http_proxy = getenv("http_proxy");
    395     }
    396 
    397     do
    398     {
    399         const char*  env = op_http_proxy;
    400         int          envlen;
    401         ProxyOption  option_tab[4];
    402         ProxyOption* option = option_tab;
    403         char*        p;
    404         char*        q;
    405         const char*  proxy_name;
    406         int          proxy_name_len;
    407         int          proxy_port;
    408 
    409         if (!env)
    410             break;
    411 
    412         envlen = strlen(env);
    413 
    414         /* skip the 'http://' header, if present */
    415         if (envlen >= 7 && !memcmp(env, "http://", 7)) {
    416             env    += 7;
    417             envlen -= 7;
    418         }
    419 
    420         /* do we have a username:password pair ? */
    421         p = strchr(env, '@');
    422         if (p != 0) {
    423             q = strchr(env, ':');
    424             if (q == NULL) {
    425             BadHttpProxyFormat:
    426                 dprint("http_proxy format unsupported, try 'proxy:port' or 'username:password@proxy:port'");
    427                 break;
    428             }
    429 
    430             option->type       = PROXY_OPTION_AUTH_USERNAME;
    431             option->string     = env;
    432             option->string_len = q - env;
    433             option++;
    434 
    435             option->type       = PROXY_OPTION_AUTH_PASSWORD;
    436             option->string     = q+1;
    437             option->string_len = p - (q+1);
    438             option++;
    439 
    440             env = p+1;
    441         }
    442 
    443         p = strchr(env,':');
    444         if (p == NULL)
    445             goto BadHttpProxyFormat;
    446 
    447         proxy_name     = env;
    448         proxy_name_len = p - env;
    449         proxy_port     = atoi(p+1);
    450 
    451         D( "setting up http proxy:  server=%.*s port=%d",
    452                 proxy_name_len, proxy_name, proxy_port );
    453 
    454         /* Check that we can connect to the proxy in the next second.
    455          * If not, the proxy setting is probably garbage !!
    456          */
    457         if ( proxy_check_connection( proxy_name, proxy_name_len, proxy_port, 1000 ) < 0) {
    458             dprint("Could not connect to proxy at %.*s:%d: %s !",
    459                    proxy_name_len, proxy_name, proxy_port, errno_str);
    460             dprint("Proxy will be ignored !");
    461             break;
    462         }
    463 
    464         if ( proxy_http_setup( proxy_name, proxy_name_len, proxy_port,
    465                                option - option_tab, option_tab ) < 0 )
    466         {
    467             dprint( "Http proxy setup failed for '%.*s:%d': %s",
    468                     proxy_name_len, proxy_name, proxy_port, errno_str);
    469             dprint( "Proxy will be ignored !");
    470         }
    471     }
    472     while (0);
    473 
    474     /* initialize sensors, this must be done here due to timer issues */
    475     android_hw_sensors_init();
    476 
    477    /* cool, now try to run the "ddms ping" command, which will take care of pinging usage
    478     * if the user agreed for it. the emulator itself never sends anything to any outside
    479     * machine
    480     */
    481     {
    482 #ifdef _WIN32
    483 #  define  _ANDROID_PING_PROGRAM   "ddms.bat"
    484 #else
    485 #  define  _ANDROID_PING_PROGRAM   "ddms"
    486 #endif
    487 
    488         char         tmp[PATH_MAX];
    489         const char*  appdir = get_app_dir();
    490 
    491         const size_t ARGSLEN =
    492                 PATH_MAX +                    // max ping program path
    493                 10 +                          // max VERSION_STRING length
    494                 3*ANDROID_GLSTRING_BUF_SIZE + // max GL string lengths
    495                 29 +                          // static args characters
    496                 1;                            // NUL terminator
    497         char args[ARGSLEN];
    498 
    499         if (snprintf( tmp, PATH_MAX, "%s%s%s", appdir, PATH_SEP,
    500                       _ANDROID_PING_PROGRAM ) >= PATH_MAX) {
    501             dprint( "Application directory too long: %s", appdir);
    502             return;
    503         }
    504 
    505         /* if the program isn't there, don't bother */
    506         D( "ping program: %s", tmp);
    507         if (path_exists(tmp)) {
    508 #ifdef _WIN32
    509             STARTUPINFO           startup;
    510             PROCESS_INFORMATION   pinfo;
    511 
    512             ZeroMemory( &startup, sizeof(startup) );
    513             startup.cb = sizeof(startup);
    514             startup.dwFlags = STARTF_USESHOWWINDOW;
    515             startup.wShowWindow = SW_SHOWMINIMIZED;
    516 
    517             ZeroMemory( &pinfo, sizeof(pinfo) );
    518 
    519             char* comspec = getenv("COMSPEC");
    520             if (!comspec) comspec = "cmd.exe";
    521 
    522             // Run
    523             if (snprintf(args, ARGSLEN,
    524                     "/C \"%s\" ping emulator " VERSION_STRING " \"%s\" \"%s\" \"%s\"",
    525                     tmp, android_gl_vendor, android_gl_renderer, android_gl_version)
    526                 >= ARGSLEN)
    527             {
    528                 D( "DDMS command line too long: %s", args);
    529                 return;
    530             }
    531 
    532             CreateProcess(
    533                 comspec,                                      /* program path */
    534                 args,                                    /* command line args */
    535                 NULL,                    /* process handle is not inheritable */
    536                 NULL,                     /* thread handle is not inheritable */
    537                 FALSE,                       /* no, don't inherit any handles */
    538                 DETACHED_PROCESS,   /* the new process doesn't have a console */
    539                 NULL,                       /* use parent's environment block */
    540                 NULL,                      /* use parent's starting directory */
    541                 &startup,                   /* startup info, i.e. std handles */
    542                 &pinfo );
    543 
    544             D( "ping command: %s %s", comspec, args );
    545 #else
    546             int  pid;
    547 
    548             /* disable SIGALRM for the fork(), the periodic signal seems to
    549              * interefere badly with the fork() implementation on Linux running
    550              * under VMWare.
    551              */
    552             BEGIN_NOSIGALRM
    553                 pid = fork();
    554                 if (pid == 0) {
    555                     int  fd = open("/dev/null", O_WRONLY);
    556                     dup2(fd, 1);
    557                     dup2(fd, 2);
    558                     execl( tmp, _ANDROID_PING_PROGRAM, "ping", "emulator", VERSION_STRING,
    559                             android_gl_vendor, android_gl_renderer, android_gl_version,
    560                             NULL );
    561                 }
    562             END_NOSIGALRM
    563 
    564             /* don't do anything in the parent or in case of error */
    565             snprintf(args, ARGSLEN,
    566                     "%s ping emulator " VERSION_STRING " \"%s\" \"%s\" \"%s\"",
    567                     tmp, android_gl_vendor, android_gl_renderer, android_gl_version);
    568             D( "ping command: %s", args );
    569 #endif
    570         }
    571     }
    572 }
    573 
    574 
    575