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