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
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     = 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