• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
get_app_dir(void)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
get_report_console_options(char * end,int * maxtries)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
report_console(const char * proto_port,int console_port)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  */
android_emulation_setup(void)227 void  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