• 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.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 
get_app_dir(void)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
get_report_console_options(char * end,int * maxtries)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
report_console(const char * proto_port,int console_port)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  */
android_emulation_setup(void)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