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 
     27 #define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
     28 
     29 #ifdef ANDROID_SDK_TOOLS_REVISION
     30 #  define  VERSION_STRING  STRINGIFY(ANDROID_SDK_TOOLS_REVISION)".0"
     31 #else
     32 #  define  VERSION_STRING  "standalone"
     33 #endif
     34 
     35 extern int  control_console_start( int  port );  /* in control.c */
     36 
     37 /* Contains arguments for -android-ports option. */
     38 char* android_op_ports = NULL;
     39 /* Contains arguments for -android-port option. */
     40 char* android_op_port = NULL;
     41 /* Contains arguments for -android-report-console option. */
     42 char* android_op_report_console = NULL;
     43 /* Contains arguments for -http-proxy option. */
     44 char* op_http_proxy = NULL;
     45 /* Base port for the emulated system. */
     46 int    android_base_port;
     47 
     48 /*** APPLICATION DIRECTORY
     49  *** Where are we ?
     50  ***/
     51 
     52 const char*  get_app_dir(void)
     53 {
     54     char  buffer[1024];
     55     char* p   = buffer;
     56     char* end = p + sizeof(buffer);
     57     p = bufprint_app_dir(p, end);
     58     if (p >= end)
     59         return NULL;
     60 
     61     return strdup(buffer);
     62 }
     63 
     64 enum {
     65     REPORT_CONSOLE_SERVER = (1 << 0),
     66     REPORT_CONSOLE_MAX    = (1 << 1)
     67 };
     68 
     69 static int
     70 get_report_console_options( char*  end, int  *maxtries )
     71 {
     72     int    flags = 0;
     73 
     74     if (end == NULL || *end == 0)
     75         return 0;
     76 
     77     if (end[0] != ',') {
     78         derror( "socket port/path can be followed by [,<option>]+ only\n");
     79         exit(3);
     80     }
     81     end += 1;
     82     while (*end) {
     83         char*  p = strchr(end, ',');
     84         if (p == NULL)
     85             p = end + strlen(end);
     86 
     87         if (memcmp( end, "server", p-end ) == 0)
     88             flags |= REPORT_CONSOLE_SERVER;
     89         else if (memcmp( end, "max=", 4) == 0) {
     90             end  += 4;
     91             *maxtries = strtol( end, NULL, 10 );
     92             flags |= REPORT_CONSOLE_MAX;
     93         } else {
     94             derror( "socket port/path can be followed by [,server][,max=<count>] only\n");
     95             exit(3);
     96         }
     97 
     98         end = p;
     99         if (*end)
    100             end += 1;
    101     }
    102     return flags;
    103 }
    104 
    105 static void
    106 report_console( const char*  proto_port, int  console_port )
    107 {
    108     int   s = -1, s2;
    109     int   maxtries = 10;
    110     int   flags = 0;
    111     signal_state_t  sigstate;
    112 
    113     disable_sigalrm( &sigstate );
    114 
    115     if ( !strncmp( proto_port, "tcp:", 4) ) {
    116         char*  end;
    117         long   port = strtol(proto_port + 4, &end, 10);
    118 
    119         flags = get_report_console_options( end, &maxtries );
    120 
    121         if (flags & REPORT_CONSOLE_SERVER) {
    122             s = socket_loopback_server( port, SOCKET_STREAM );
    123             if (s < 0) {
    124                 fprintf(stderr, "could not create server socket on TCP:%ld: %s\n",
    125                         port, errno_str);
    126                 exit(3);
    127             }
    128         } else {
    129             for ( ; maxtries > 0; maxtries-- ) {
    130                 D("trying to find console-report client on tcp:%d", port);
    131                 s = socket_loopback_client( port, SOCKET_STREAM );
    132                 if (s >= 0)
    133                     break;
    134 
    135                 sleep_ms(1000);
    136             }
    137             if (s < 0) {
    138                 fprintf(stderr, "could not connect to server on TCP:%ld: %s\n",
    139                         port, errno_str);
    140                 exit(3);
    141             }
    142         }
    143     } else if ( !strncmp( proto_port, "unix:", 5) ) {
    144 #ifdef _WIN32
    145         fprintf(stderr, "sorry, the unix: protocol is not supported on Win32\n");
    146         exit(3);
    147 #else
    148         char*  path = strdup(proto_port+5);
    149         char*  end  = strchr(path, ',');
    150         if (end != NULL) {
    151             flags = get_report_console_options( end, &maxtries );
    152             *end  = 0;
    153         }
    154         if (flags & REPORT_CONSOLE_SERVER) {
    155             s = socket_unix_server( path, SOCKET_STREAM );
    156             if (s < 0) {
    157                 fprintf(stderr, "could not bind unix socket on '%s': %s\n",
    158                         proto_port+5, errno_str);
    159                 exit(3);
    160             }
    161         } else {
    162             for ( ; maxtries > 0; maxtries-- ) {
    163                 s = socket_unix_client( path, SOCKET_STREAM );
    164                 if (s >= 0)
    165                     break;
    166 
    167                 sleep_ms(1000);
    168             }
    169             if (s < 0) {
    170                 fprintf(stderr, "could not connect to unix socket on '%s': %s\n",
    171                         path, errno_str);
    172                 exit(3);
    173             }
    174         }
    175         free(path);
    176 #endif
    177     } else {
    178         fprintf(stderr, "-report-console must be followed by a 'tcp:<port>' or 'unix:<path>'\n");
    179         exit(3);
    180     }
    181 
    182     if (flags & REPORT_CONSOLE_SERVER) {
    183         int  tries = 3;
    184         D( "waiting for console-reporting client" );
    185         do {
    186             s2 = socket_accept(s, NULL);
    187         } while (s2 < 0 && --tries > 0);
    188 
    189         if (s2 < 0) {
    190             fprintf(stderr, "could not accept console-reporting client connection: %s\n",
    191                    errno_str);
    192             exit(3);
    193         }
    194 
    195         socket_close(s);
    196         s = s2;
    197     }
    198 
    199     /* simply send the console port in text */
    200     {
    201         char  temp[12];
    202         snprintf( temp, sizeof(temp), "%d", console_port );
    203 
    204         if (socket_send(s, temp, strlen(temp)) < 0) {
    205             fprintf(stderr, "could not send console number report: %d: %s\n",
    206                     errno, errno_str );
    207             exit(3);
    208         }
    209         socket_close(s);
    210     }
    211     D( "console port number sent to remote. resuming boot" );
    212 
    213     restore_sigalrm (&sigstate);
    214 }
    215 
    216 /* this function is called from qemu_main() once all arguments have been parsed
    217  * it should be used to setup any Android-specific items in the emulation before the
    218  * main loop runs
    219  */
    220 void  android_emulation_setup( void )
    221 {
    222     int   tries     = 16;
    223     int   base_port = 5554;
    224     int   adb_host_port = 5037; // adb's default
    225     int   success   = 0;
    226     int   s;
    227     uint32_t  guest_ip;
    228 
    229         /* Set the port where the emulator expects adb to run on the host
    230          * machine */
    231     char* adb_host_port_str = getenv( "ANDROID_ADB_SERVER_PORT" );
    232     if ( adb_host_port_str && strlen( adb_host_port_str ) > 0 ) {
    233         adb_host_port = (int) strtol( adb_host_port_str, NULL, 0 );
    234         if ( adb_host_port <= 0 ) {
    235             derror( "env var ANDROID_ADB_SERVER_PORT must be a number > 0. Got \"%s\"\n",
    236                     adb_host_port_str );
    237             exit(1);
    238         }
    239     }
    240 
    241     inet_strtoip("10.0.2.15", &guest_ip);
    242 
    243 #if 0
    244     if (opts->adb_port) {
    245         fprintf( stderr, "option -adb-port is obsolete, use -port instead\n" );
    246         exit(1);
    247     }
    248 #endif
    249 
    250     if (android_op_port && android_op_ports) {
    251         fprintf( stderr, "options -port and -ports cannot be used together.\n");
    252         exit(1);
    253     }
    254 
    255     if (android_op_ports) {
    256         char* comma_location;
    257         char* end;
    258         int console_port = strtol( android_op_ports, &comma_location, 0 );
    259 
    260         if ( comma_location == NULL || *comma_location != ',' ) {
    261             derror( "option -ports must be followed by two comma separated positive integer numbers" );
    262             exit(1);
    263         }
    264 
    265         int adb_port = strtol( comma_location+1, &end, 0 );
    266 
    267         if ( end == NULL || *end ) {
    268             derror( "option -ports must be followed by two comma separated positive integer numbers" );
    269             exit(1);
    270         }
    271 
    272         if ( console_port == adb_port ) {
    273             derror( "option -ports must be followed by two different integer numbers" );
    274             exit(1);
    275         }
    276 
    277         // Set up redirect from host to guest system. adbd on the guest listens
    278         // on 5555.
    279         slirp_redir( 0, adb_port, guest_ip, 5555 );
    280         if ( control_console_start( console_port ) < 0 ) {
    281             slirp_unredir( 0, adb_port );
    282         }
    283 
    284         base_port = console_port;
    285     } else {
    286         if (android_op_port) {
    287             char*  end;
    288             int    port = strtol( android_op_port, &end, 0 );
    289             if ( end == NULL || *end ||
    290                 (unsigned)((port - base_port) >> 1) >= (unsigned)tries ) {
    291                 derror( "option -port must be followed by an even integer number between %d and %d\n",
    292                         base_port, base_port + (tries-1)*2 );
    293                 exit(1);
    294             }
    295             if ( (port & 1) != 0 ) {
    296                 port &= ~1;
    297                 dwarning( "option -port must be followed by an even integer, using  port number %d\n",
    298                           port );
    299             }
    300             base_port = port;
    301             tries     = 1;
    302         }
    303 
    304         for ( ; tries > 0; tries--, base_port += 2 ) {
    305 
    306             /* setup first redirection for ADB, the Android Debug Bridge */
    307             if ( slirp_redir( 0, base_port+1, guest_ip, 5555 ) < 0 )
    308                 continue;
    309 
    310             /* setup second redirection for the emulator console */
    311             if ( control_console_start( base_port ) < 0 ) {
    312                 slirp_unredir( 0, base_port+1 );
    313                 continue;
    314             }
    315 
    316             D( "control console listening on port %d, ADB on port %d", base_port, base_port+1 );
    317             success = 1;
    318             break;
    319         }
    320 
    321         if (!success) {
    322             fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" );
    323             exit(1);
    324         }
    325     }
    326 
    327     if (android_op_report_console) {
    328         report_console(android_op_report_console, base_port);
    329     }
    330 
    331     android_modem_init( base_port );
    332 
    333     /* Save base port. */
    334     android_base_port = base_port;
    335 
    336    /* send a simple message to the ADB host server to tell it we just started.
    337     * it should be listening on port 5037. if we can't reach it, don't bother
    338     */
    339     do
    340     {
    341         SockAddress  addr;
    342         char         tmp[32];
    343 
    344         s = socket_create_inet( SOCKET_STREAM );
    345         if (s < 0) {
    346             D("can't create socket to talk to the ADB server");
    347             break;
    348         }
    349 
    350         sock_address_init_inet( &addr, SOCK_ADDRESS_INET_LOOPBACK, adb_host_port );
    351         if (socket_connect( s, &addr ) < 0) {
    352             D("can't connect to ADB server: %s", errno_str );
    353             break;
    354         }
    355 
    356         sprintf(tmp,"0012host:emulator:%d",base_port+1);
    357         socket_send(s, tmp, 18+4);
    358         D("sent '%s' to ADB server", tmp);
    359     }
    360     while (0);
    361 
    362     if (s >= 0)
    363         socket_close(s);
    364 
    365     /* setup the http proxy, if any */
    366     if (VERBOSE_CHECK(proxy))
    367         proxy_set_verbose(1);
    368 
    369     if (!op_http_proxy) {
    370         op_http_proxy = getenv("http_proxy");
    371     }
    372 
    373     do
    374     {
    375         const char*  env = op_http_proxy;
    376         int          envlen;
    377         ProxyOption  option_tab[4];
    378         ProxyOption* option = option_tab;
    379         char*        p;
    380         char*        q;
    381         const char*  proxy_name;
    382         int          proxy_name_len;
    383         int          proxy_port;
    384 
    385         if (!env)
    386             break;
    387 
    388         envlen = strlen(env);
    389 
    390         /* skip the 'http://' header, if present */
    391         if (envlen >= 7 && !memcmp(env, "http://", 7)) {
    392             env    += 7;
    393             envlen -= 7;
    394         }
    395 
    396         /* do we have a username:password pair ? */
    397         p = strchr(env, '@');
    398         if (p != 0) {
    399             q = strchr(env, ':');
    400             if (q == NULL) {
    401             BadHttpProxyFormat:
    402                 dprint("http_proxy format unsupported, try 'proxy:port' or 'username:password@proxy:port'");
    403                 break;
    404             }
    405 
    406             option->type       = PROXY_OPTION_AUTH_USERNAME;
    407             option->string     = env;
    408             option->string_len = q - env;
    409             option++;
    410 
    411             option->type       = PROXY_OPTION_AUTH_PASSWORD;
    412             option->string     = q+1;
    413             option->string_len = p - (q+1);
    414             option++;
    415 
    416             env = p+1;
    417         }
    418 
    419         p = strchr(env,':');
    420         if (p == NULL)
    421             goto BadHttpProxyFormat;
    422 
    423         proxy_name     = env;
    424         proxy_name_len = p - env;
    425         proxy_port     = atoi(p+1);
    426 
    427         D( "setting up http proxy:  server=%.*s port=%d",
    428                 proxy_name_len, proxy_name, proxy_port );
    429 
    430         /* Check that we can connect to the proxy in the next second.
    431          * If not, the proxy setting is probably garbage !!
    432          */
    433         if ( proxy_check_connection( proxy_name, proxy_name_len, proxy_port, 1000 ) < 0) {
    434             dprint("Could not connect to proxy at %.*s:%d: %s !",
    435                    proxy_name_len, proxy_name, proxy_port, errno_str);
    436             dprint("Proxy will be ignored !");
    437             break;
    438         }
    439 
    440         if ( proxy_http_setup( proxy_name, proxy_name_len, proxy_port,
    441                                option - option_tab, option_tab ) < 0 )
    442         {
    443             dprint( "Http proxy setup failed for '%.*s:%d': %s",
    444                     proxy_name_len, proxy_name, proxy_port, errno_str);
    445             dprint( "Proxy will be ignored !");
    446         }
    447     }
    448     while (0);
    449 
    450     /* initialize sensors, this must be done here due to timer issues */
    451     android_hw_sensors_init();
    452 
    453    /* cool, now try to run the "ddms ping" command, which will take care of pinging usage
    454     * if the user agreed for it. the emulator itself never sends anything to any outside
    455     * machine
    456     */
    457     {
    458 #ifdef _WIN32
    459 #  define  _ANDROID_PING_PROGRAM   "ddms.bat"
    460 #else
    461 #  define  _ANDROID_PING_PROGRAM   "ddms"
    462 #endif
    463 
    464         char         tmp[PATH_MAX];
    465         const char*  appdir = get_app_dir();
    466 
    467         if (snprintf( tmp, PATH_MAX, "%s%s%s", appdir, PATH_SEP,
    468                       _ANDROID_PING_PROGRAM ) >= PATH_MAX) {
    469             dprint( "Application directory too long: %s", appdir);
    470             return;
    471         }
    472 
    473         /* if the program isn't there, don't bother */
    474         D( "ping program: %s", tmp);
    475         if (path_exists(tmp)) {
    476 #ifdef _WIN32
    477             STARTUPINFO           startup;
    478             PROCESS_INFORMATION   pinfo;
    479 
    480             ZeroMemory( &startup, sizeof(startup) );
    481             startup.cb = sizeof(startup);
    482             startup.dwFlags = STARTF_USESHOWWINDOW;
    483             startup.wShowWindow = SW_SHOWMINIMIZED;
    484 
    485             ZeroMemory( &pinfo, sizeof(pinfo) );
    486 
    487             char* comspec = getenv("COMSPEC");
    488             if (!comspec) comspec = "cmd.exe";
    489 
    490             // Run
    491             char args[PATH_MAX + 30];
    492             if (snprintf( args, PATH_MAX, "/C \"%s\" ping emulator " VERSION_STRING,
    493                           tmp) >= PATH_MAX ) {
    494                 D( "DDMS path too long: %s", tmp);
    495                 return;
    496             }
    497 
    498             CreateProcess(
    499                 comspec,                                      /* program path */
    500                 args,                                    /* command line args */
    501                 NULL,                    /* process handle is not inheritable */
    502                 NULL,                     /* thread handle is not inheritable */
    503                 FALSE,                       /* no, don't inherit any handles */
    504                 DETACHED_PROCESS,   /* the new process doesn't have a console */
    505                 NULL,                       /* use parent's environment block */
    506                 NULL,                      /* use parent's starting directory */
    507                 &startup,                   /* startup info, i.e. std handles */
    508                 &pinfo );
    509 
    510             D( "ping command: %s %s", comspec, args );
    511 #else
    512             int  pid;
    513 
    514             /* disable SIGALRM for the fork(), the periodic signal seems to
    515              * interefere badly with the fork() implementation on Linux running
    516              * under VMWare.
    517              */
    518             BEGIN_NOSIGALRM
    519                 pid = fork();
    520                 if (pid == 0) {
    521                     int  fd = open("/dev/null", O_WRONLY);
    522                     dup2(fd, 1);
    523                     dup2(fd, 2);
    524                     execl( tmp, _ANDROID_PING_PROGRAM, "ping", "emulator", VERSION_STRING, NULL );
    525                 }
    526             END_NOSIGALRM
    527 
    528             /* don't do anything in the parent or in case of error */
    529             strncat( tmp, " ping emulator " VERSION_STRING, PATH_MAX - strlen(tmp) );
    530             D( "ping command: %s", tmp );
    531 #endif
    532         }
    533     }
    534 }
    535 
    536 
    537