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
37extern int  control_console_start( int  port );  /* in control.c */
38
39/* Contains arguments for -android-ports option. */
40char* android_op_ports = NULL;
41/* Contains arguments for -android-port option. */
42char* android_op_port = NULL;
43/* Contains arguments for -android-report-console option. */
44char* android_op_report_console = NULL;
45/* Contains arguments for -http-proxy option. */
46char* op_http_proxy = NULL;
47/* Base port for the emulated system. */
48int    android_base_port;
49
50/* Strings describing the host system's OpenGL implementation */
51char android_gl_vendor[ANDROID_GLSTRING_BUF_SIZE];
52char android_gl_renderer[ANDROID_GLSTRING_BUF_SIZE];
53char android_gl_version[ANDROID_GLSTRING_BUF_SIZE];
54
55/*** APPLICATION DIRECTORY
56 *** Where are we ?
57 ***/
58
59const 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
71enum {
72    REPORT_CONSOLE_SERVER = (1 << 0),
73    REPORT_CONSOLE_MAX    = (1 << 1)
74};
75
76static int
77get_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
112static void
113report_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 */
227void  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