blob: 05a2cb0021c289ca678511f20da6d3da6f700b95 [file] [log] [blame]
David 'Digit' Turnerf8456272011-02-02 12:34:14 +01001/* Copyright (C) 2011 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#include <signal.h>
13#include <unistd.h>
14#include <string.h>
15#include <sys/time.h>
16#include <errno.h>
17#include <fcntl.h>
18#ifdef _WIN32
19#include <process.h>
20#endif
21
22#include <SDL.h>
23#include <SDL_syswm.h>
24
25#include "console.h"
26
27#include "android/utils/debug.h"
28#include "android/utils/path.h"
29#include "android/utils/bufprint.h"
Vladimir Chtchetkine83ffd662011-02-11 12:40:59 -080030#include "android/utils/dirscanner.h"
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010031#include "android/main-common.h"
32#include "android/globals.h"
33#include "android/resource.h"
34#include "android/user-config.h"
Xavier Ducrohetfc8ed802011-02-09 18:04:23 -080035#include "android/qemulator.h"
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010036#include "android/display.h"
Xavier Ducrohetfc8ed802011-02-09 18:04:23 -080037#include "android/skin/image.h"
38#include "android/skin/trackball.h"
39#include "android/skin/keyboard.h"
40#include "android/skin/file.h"
41#include "android/skin/window.h"
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010042
43
44
45/***********************************************************************/
46/***********************************************************************/
47/***** *****/
48/***** U T I L I T Y R O U T I N E S *****/
49/***** *****/
50/***********************************************************************/
51/***********************************************************************/
52
53#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
54
55/*** CONFIGURATION
56 ***/
57
58static AUserConfig* userConfig;
59
60void
David 'Digit' Turner755811e2011-02-07 13:38:25 +010061user_config_init( void )
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010062{
63 userConfig = auserConfig_new( android_avdInfo );
64}
65
66/* only call this function on normal exits, so that ^C doesn't save the configuration */
67void
David 'Digit' Turner755811e2011-02-07 13:38:25 +010068user_config_done( void )
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010069{
70 int win_x, win_y;
71
72 if (!userConfig) {
73 D("no user configuration?");
74 return;
75 }
76
77 SDL_WM_GetPos( &win_x, &win_y );
78 auserConfig_setWindowPos(userConfig, win_x, win_y);
79 auserConfig_save(userConfig);
80}
81
82void
David 'Digit' Turner755811e2011-02-07 13:38:25 +010083user_config_get_window_pos( int *window_x, int *window_y )
David 'Digit' Turnerf8456272011-02-02 12:34:14 +010084{
85 *window_x = *window_y = 10;
86
87 if (userConfig)
88 auserConfig_getWindowPos(userConfig, window_x, window_y);
89}
90
91unsigned convertBytesToMB( uint64_t size )
92{
93 if (size == 0)
94 return 0;
95
96 size = (size + ONE_MB-1) >> 20;
97 if (size > UINT_MAX)
98 size = UINT_MAX;
99
100 return (unsigned) size;
101}
102
103uint64_t convertMBToBytes( unsigned megaBytes )
104{
105 return ((uint64_t)megaBytes << 20);
106}
107
108
109/***********************************************************************/
110/***********************************************************************/
111/***** *****/
112/***** K E Y S E T R O U T I N E S *****/
113/***** *****/
114/***********************************************************************/
115/***********************************************************************/
116
117#define KEYSET_FILE "default.keyset"
118
119SkinKeyset* android_keyset = NULL;
120
121static int
122load_keyset(const char* path)
123{
124 if (path_can_read(path)) {
125 AConfig* root = aconfig_node("","");
126 if (!aconfig_load_file(root, path)) {
127 android_keyset = skin_keyset_new(root);
128 if (android_keyset != NULL) {
129 D( "keyset loaded from: %s", path);
130 return 0;
131 }
132 }
133 }
134 return -1;
135}
136
137void
138parse_keyset(const char* keyset, AndroidOptions* opts)
139{
140 char kname[MAX_PATH];
141 char temp[MAX_PATH];
142 char* p;
143 char* end;
144
145 /* append .keyset suffix if needed */
146 if (strchr(keyset, '.') == NULL) {
147 p = kname;
148 end = p + sizeof(kname);
149 p = bufprint(p, end, "%s.keyset", keyset);
150 if (p >= end) {
151 derror( "keyset name too long: '%s'\n", keyset);
152 exit(1);
153 }
154 keyset = kname;
155 }
156
157 /* look for a the keyset file */
158 p = temp;
159 end = p + sizeof(temp);
160 p = bufprint_config_file(p, end, keyset);
161 if (p < end && load_keyset(temp) == 0)
162 return;
163
164 p = temp;
165 p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->sysdir, keyset);
166 if (p < end && load_keyset(temp) == 0)
167 return;
168
169 p = temp;
170 p = bufprint_app_dir(p, end);
171 p = bufprint(p, end, PATH_SEP "keysets" PATH_SEP "%s", keyset);
172 if (p < end && load_keyset(temp) == 0)
173 return;
174
175 return;
176}
177
178void
179write_default_keyset( void )
180{
181 char path[MAX_PATH];
182
183 bufprint_config_file( path, path+sizeof(path), KEYSET_FILE );
184
185 /* only write if there is no file here */
186 if ( !path_exists(path) ) {
187 int fd = open( path, O_WRONLY | O_CREAT, 0666 );
188 int ret;
189 const char* ks = skin_keyset_get_default();
190
191
192 D( "writing default keyset file to %s", path );
193
194 if (fd < 0) {
195 D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) );
196 return;
197 }
198 CHECKED(ret, write(fd, ks, strlen(ks)));
199 close(fd);
200 }
201}
202
Xavier Ducrohetfc8ed802011-02-09 18:04:23 -0800203
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100204
205/***********************************************************************/
206/***********************************************************************/
207/***** *****/
208/***** S D L S U P P O R T *****/
209/***** *****/
210/***********************************************************************/
211/***********************************************************************/
212
213void *readpng(const unsigned char* base, size_t size, unsigned *_width, unsigned *_height);
214
215#ifdef CONFIG_DARWIN
216# define ANDROID_ICON_PNG "android_icon_256.png"
217#else
218# define ANDROID_ICON_PNG "android_icon_16.png"
219#endif
220
221static void
222sdl_set_window_icon( void )
223{
224 static int window_icon_set;
225
226 if (!window_icon_set)
227 {
228#ifdef _WIN32
229 HANDLE handle = GetModuleHandle( NULL );
230 HICON icon = LoadIcon( handle, MAKEINTRESOURCE(1) );
231 SDL_SysWMinfo wminfo;
232
233 SDL_GetWMInfo(&wminfo);
234
235 SetClassLong( wminfo.window, GCL_HICON, (LONG)icon );
236#else /* !_WIN32 */
237 unsigned icon_w, icon_h;
238 size_t icon_bytes;
239 const unsigned char* icon_data;
240 void* icon_pixels;
241
242 window_icon_set = 1;
243
244 icon_data = android_icon_find( ANDROID_ICON_PNG, &icon_bytes );
245 if ( !icon_data )
246 return;
247
248 icon_pixels = readpng( icon_data, icon_bytes, &icon_w, &icon_h );
249 if ( !icon_pixels )
250 return;
251
252 /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
253 * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
254 * on our CPU endianess
255 */
256 {
257 unsigned* d = icon_pixels;
258 unsigned* d_end = d + icon_w*icon_h;
259
260 for ( ; d < d_end; d++ ) {
261 unsigned pix = d[0];
262#if HOST_WORDS_BIGENDIAN
263 /* R,G,B,A read as RGBA => ARGB */
264 pix = ((pix >> 8) & 0xffffff) | (pix << 24);
265#else
266 /* R,G,B,A read as ABGR => ARGB */
267 pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
268#endif
269 d[0] = pix;
270 }
271 }
272
273 SDL_Surface* icon = sdl_surface_from_argb32( icon_pixels, icon_w, icon_h );
274 if (icon != NULL) {
275 SDL_WM_SetIcon(icon, NULL);
276 SDL_FreeSurface(icon);
277 free( icon_pixels );
278 }
279#endif /* !_WIN32 */
280 }
281}
282
283/***********************************************************************/
284/***********************************************************************/
285/***** *****/
286/***** S K I N S U P P O R T *****/
287/***** *****/
288/***********************************************************************/
289/***********************************************************************/
290
291const char* skin_network_speed = NULL;
292const char* skin_network_delay = NULL;
293
Xavier Ducrohetfc8ed802011-02-09 18:04:23 -0800294
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100295static void sdl_at_exit(void)
296{
David 'Digit' Turner755811e2011-02-07 13:38:25 +0100297 user_config_done();
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100298 qemulator_done(qemulator_get());
299 SDL_Quit();
300}
301
302
303void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
304{
305 QEmulator* emulator = qemulator_get();
306 SkinDisplay* disp = skin_layout_get_display(emulator->layout);
307 int width, height;
308 char buf[128];
309
310 if (disp->rotation & 1) {
311 width = disp->rect.size.h;
312 height = disp->rect.size.w;
313 } else {
314 width = disp->rect.size.w;
315 height = disp->rect.size.h;
316 }
317
318 snprintf(buf, sizeof buf, "width=%d,height=%d", width, height);
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100319#if !defined(CONFIG_STANDALONE_UI) && !defined(CONFIG_STANDALONE_CORE)
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100320 android_display_init(ds, qframebuffer_fifo_get());
David 'Digit' Turner07db3492011-02-02 17:36:34 +0100321#endif
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100322}
323
324/* list of skin aliases */
325static const struct {
326 const char* name;
327 const char* alias;
328} skin_aliases[] = {
329 { "QVGA-L", "320x240" },
330 { "QVGA-P", "240x320" },
331 { "HVGA-L", "480x320" },
332 { "HVGA-P", "320x480" },
333 { "QVGA", "320x240" },
334 { "HVGA", "320x480" },
335 { NULL, NULL }
336};
337
338/* this is used by hw/events_device.c to send the charmap name to the system */
339const char* android_skin_keycharmap = NULL;
340
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100341void
342parse_skin_files(const char* skinDirPath,
343 const char* skinName,
344 AndroidOptions* opts,
David 'Digit' Turner2507cab2011-02-10 16:29:17 +0100345 AndroidHwConfig* hwConfig,
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100346 AConfig* *skinConfig,
347 char* *skinPath)
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100348{
349 char tmp[1024];
350 AConfig* root;
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100351 const char* path = NULL;
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100352 AConfig* n;
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100353
354 root = aconfig_node("", "");
355
356 if (skinName == NULL)
357 goto DEFAULT_SKIN;
358
359 /* Support skin aliases like QVGA-H QVGA-P, etc...
360 But first we check if it's a directory that exist before applying
361 the alias */
362 int checkAlias = 1;
363
364 if (skinDirPath != NULL) {
365 bufprint(tmp, tmp+sizeof(tmp), "%s/%s", skinDirPath, skinName);
366 if (path_exists(tmp)) {
367 checkAlias = 0;
368 } else {
369 D("there is no '%s' skin in '%s'", skinName, skinDirPath);
370 }
371 }
372
373 if (checkAlias) {
374 int nn;
375
376 for (nn = 0; ; nn++ ) {
377 const char* skin_name = skin_aliases[nn].name;
378 const char* skin_alias = skin_aliases[nn].alias;
379
380 if (!skin_name)
381 break;
382
383 if (!strcasecmp( skin_name, skinName )) {
384 D("skin name '%s' aliased to '%s'", skinName, skin_alias);
385 skinName = skin_alias;
386 break;
387 }
388 }
389 }
390
391 /* Magically support skins like "320x240" or "320x240x16" */
392 if(isdigit(skinName[0])) {
393 char *x = strchr(skinName, 'x');
394 if(x && isdigit(x[1])) {
395 int width = atoi(skinName);
396 int height = atoi(x+1);
397 int bpp = 16;
398 char* y = strchr(x+1, 'x');
399 if (y && isdigit(y[1])) {
400 bpp = atoi(y+1);
401 }
402 snprintf(tmp, sizeof tmp,
403 "display {\n width %d\n height %d\n bpp %d}\n",
404 width, height,bpp);
405 aconfig_load(root, strdup(tmp));
406 path = ":";
407 D("found magic skin width=%d height=%d bpp=%d\n", width, height, bpp);
408 goto FOUND_SKIN;
409 }
410 }
411
412 if (skinDirPath == NULL) {
413 derror("unknown skin name '%s'", skinName);
414 exit(1);
415 }
416
417 snprintf(tmp, sizeof tmp, "%s/%s/layout", skinDirPath, skinName);
418 D("trying to load skin file '%s'", tmp);
419
420 if(aconfig_load_file(root, tmp) < 0) {
421 dwarning("could not load skin file '%s', using built-in one\n",
422 tmp);
423 goto DEFAULT_SKIN;
424 }
425
426 snprintf(tmp, sizeof tmp, "%s/%s/", skinDirPath, skinName);
427 path = tmp;
428 goto FOUND_SKIN;
429
430FOUND_SKIN:
431 /* the default network speed and latency can now be specified by the device skin */
432 n = aconfig_find(root, "network");
433 if (n != NULL) {
434 skin_network_speed = aconfig_str(n, "speed", 0);
435 skin_network_delay = aconfig_str(n, "delay", 0);
436 }
437
David 'Digit' Turner2507cab2011-02-10 16:29:17 +0100438 /* extract framebuffer information from the skin.
439 *
440 * for version 1 of the skin format, they are in the top-level
441 * 'display' element.
442 *
443 * for version 2 of the skin format, they are under parts.device.display
444 */
445 n = aconfig_find(root, "display");
446 if (n == NULL) {
447 n = aconfig_find(root, "parts");
448 if (n != NULL) {
David 'Digit' Turner50142ee2011-03-25 16:18:58 +0100449 n = aconfig_find(n, "device");
David 'Digit' Turner2507cab2011-02-10 16:29:17 +0100450 if (n != NULL) {
David 'Digit' Turner50142ee2011-03-25 16:18:58 +0100451 n = aconfig_find(n, "display");
David 'Digit' Turner2507cab2011-02-10 16:29:17 +0100452 }
453 }
454 }
455
456 if (n != NULL) {
457 int width = aconfig_int(n, "width", hwConfig->hw_lcd_width);
458 int height = aconfig_int(n, "height", hwConfig->hw_lcd_height);
459 int depth = aconfig_int(n, "bpp", hwConfig->hw_lcd_depth);
460
461 if (width > 0 && height > 0) {
462 /* The emulated framebuffer wants sizes that are multiples of 4 */
463 if (((width|height) & 3) != 0) {
464 width = (width+3) & ~3;
465 height = (height+3) & ~3;
466 D("adjusting LCD dimensions to (%dx%dx)", width, height);
467 }
468
469 /* only depth values of 16 and 32 are correct. 16 is the default. */
470 if (depth != 32 && depth != 16) {
471 depth = 16;
472 D("adjusting LCD bit depth to %d", depth);
473 }
474
475 hwConfig->hw_lcd_width = width;
476 hwConfig->hw_lcd_height = height;
477 hwConfig->hw_lcd_depth = depth;
478 }
479 else {
480 D("ignoring invalid skin LCD dimensions (%dx%dx%d)",
481 width, height, depth);
482 }
483 }
484
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100485 *skinConfig = root;
486 *skinPath = strdup(path);
487 return;
488
489DEFAULT_SKIN:
490 {
491 const unsigned char* layout_base;
492 size_t layout_size;
493 char* base;
494
495 skinName = "<builtin>";
496
497 layout_base = android_resource_find( "layout", &layout_size );
498 if (layout_base == NULL) {
499 fprintf(stderr, "Couldn't load builtin skin\n");
500 exit(1);
501 }
502 base = malloc( layout_size+1 );
503 memcpy( base, layout_base, layout_size );
504 base[layout_size] = 0;
505
506 D("parsing built-in skin layout file (%d bytes)", (int)layout_size);
507 aconfig_load(root, base);
508 path = ":";
509 }
510 goto FOUND_SKIN;
511}
512
513
514void
515init_sdl_ui(AConfig* skinConfig,
516 const char* skinPath,
517 AndroidOptions* opts)
518{
519 int win_x, win_y, flags;
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100520
521 signal(SIGINT, SIG_DFL);
522#ifndef _WIN32
523 signal(SIGQUIT, SIG_DFL);
524#endif
525
526 /* we're not a game, so allow the screensaver to run */
527 putenv("SDL_VIDEO_ALLOW_SCREENSAVER=1");
528
529 flags = SDL_INIT_NOPARACHUTE;
530 if (!opts->no_window)
531 flags |= SDL_INIT_VIDEO;
532
533 if(SDL_Init(flags)){
534 fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
535 exit(1);
536 }
537
538 if (!opts->no_window) {
539 SDL_EnableUNICODE(!opts->raw_keys);
540 SDL_EnableKeyRepeat(0,0);
541
542 sdl_set_window_icon();
543 }
544 else
545 {
546#ifndef _WIN32
547 /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
548 * able to run the emulator in the background (e.g. "emulator &").
549 * despite the fact that the emulator should not grab input or try to
550 * write to the output in normal cases, we're stopped on some systems
551 * (e.g. OS X)
552 */
553 signal(SIGTTIN, SIG_IGN);
554 signal(SIGTTOU, SIG_IGN);
555#endif
556 }
557 atexit(sdl_at_exit);
558
David 'Digit' Turner755811e2011-02-07 13:38:25 +0100559 user_config_get_window_pos(&win_x, &win_y);
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100560
David 'Digit' Turner74d7ace2011-02-02 13:21:03 +0100561 if ( qemulator_init(qemulator_get(), skinConfig, skinPath, win_x, win_y, opts) < 0 ) {
562 fprintf(stderr, "### Error: could not load emulator skin from '%s'\n", skinPath);
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100563 exit(1);
564 }
565
566 android_skin_keycharmap = skin_keyboard_charmap_name(qemulator_get()->keyboard);
567
David 'Digit' Turnerf8456272011-02-02 12:34:14 +0100568 /* add an onion overlay image if needed */
569 if (opts->onion) {
570 SkinImage* onion = skin_image_find_simple( opts->onion );
571 int alpha, rotate;
572
573 if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
574 alpha = (256*alpha)/100;
575 } else
576 alpha = 128;
577
578 if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
579 rotate &= 3;
580 } else
581 rotate = SKIN_ROTATION_0;
582
583 qemulator_get()->onion = onion;
584 qemulator_get()->onion_alpha = alpha;
585 qemulator_get()->onion_rotation = rotate;
586 }
587}
Vladimir Chtchetkine83ffd662011-02-11 12:40:59 -0800588
589/* this function is used to perform auto-detection of the
590 * system directory in the case of a SDK installation.
591 *
592 * we want to deal with several historical usages, hence
593 * the slightly complicated logic.
594 *
595 * NOTE: the function returns the path to the directory
596 * containing 'fileName'. this is *not* the full
597 * path to 'fileName'.
598 */
599static char*
600_getSdkImagePath( const char* fileName )
601{
602 char temp[MAX_PATH];
603 char* p = temp;
604 char* end = p + sizeof(temp);
605 char* q;
606 char* app;
607
608 static const char* const searchPaths[] = {
609 "", /* program's directory */
610 "/lib/images", /* this is for SDK 1.0 */
611 "/../platforms/android-1.1/images", /* this is for SDK 1.1 */
612 NULL
613 };
614
615 app = bufprint_app_dir(temp, end);
616 if (app >= end)
617 return NULL;
618
619 do {
620 int nn;
621
622 /* first search a few well-known paths */
623 for (nn = 0; searchPaths[nn] != NULL; nn++) {
624 p = bufprint(app, end, "%s", searchPaths[nn]);
625 q = bufprint(p, end, "/%s", fileName);
626 if (q < end && path_exists(temp)) {
627 *p = 0;
628 goto FOUND_IT;
629 }
630 }
631
632 /* hmmm. let's assume that we are in a post-1.1 SDK
633 * scan ../platforms if it exists
634 */
635 p = bufprint(app, end, "/../platforms");
636 if (p < end) {
637 DirScanner* scanner = dirScanner_new(temp);
638 if (scanner != NULL) {
639 int found = 0;
640 const char* subdir;
641
642 for (;;) {
643 subdir = dirScanner_next(scanner);
644 if (!subdir) break;
645
646 q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
647 if (q >= end || !path_exists(temp))
648 continue;
649
650 found = 1;
651 p = bufprint(p, end, "/%s/images", subdir);
652 break;
653 }
654 dirScanner_free(scanner);
655 if (found)
656 break;
657 }
658 }
659
660 /* I'm out of ideas */
661 return NULL;
662
663 } while (0);
664
665FOUND_IT:
666 //D("image auto-detection: %s/%s", temp, fileName);
667 return android_strdup(temp);
668}
669
670static char*
671_getSdkImage( const char* path, const char* file )
672{
673 char temp[MAX_PATH];
674 char *p = temp, *end = p + sizeof(temp);
675
676 p = bufprint(temp, end, "%s/%s", path, file);
677 if (p >= end || !path_exists(temp))
678 return NULL;
679
680 return android_strdup(temp);
681}
682
683static char*
684_getSdkSystemImage( const char* path, const char* optionName, const char* file )
685{
686 char* image = _getSdkImage(path, file);
687
688 if (image == NULL) {
689 derror("Your system directory is missing the '%s' image file.\n"
690 "Please specify one with the '%s <filepath>' option",
691 file, optionName);
692 exit(2);
693 }
694 return image;
695}
696
David 'Digit' Turner25eb6552011-02-25 15:07:11 +0100697void sanitizeOptions( AndroidOptions* opts )
Vladimir Chtchetkine83ffd662011-02-11 12:40:59 -0800698{
Vladimir Chtchetkine83ffd662011-02-11 12:40:59 -0800699 /* legacy support: we used to use -system <dir> and -image <file>
700 * instead of -sysdir <dir> and -system <file>, so handle this by checking
701 * whether the options point to directories or files.
702 */
703 if (opts->image != NULL) {
704 if (opts->system != NULL) {
705 if (opts->sysdir != NULL) {
706 derror( "You can't use -sysdir, -system and -image at the same time.\n"
707 "You should probably use '-sysdir <path> -system <file>'.\n" );
708 exit(2);
709 }
710 }
711 dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
712 "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
713 opts->sysdir = opts->system;
714 opts->system = opts->image;
715 opts->image = NULL;
716 }
717 else if (opts->system != NULL && path_is_dir(opts->system)) {
718 if (opts->sysdir != NULL) {
719 derror( "Option -system should now be followed by a file path, not a directory one.\n"
720 "Please use '-sysdir <path>' to point to the system directory.\n" );
721 exit(1);
722 }
723 dwarning( "Please note that the -system option should now be used to point to the initial\n"
724 "system image (like the obsolete -image option). To point to the system directory\n"
725 "please now use '-sysdir <path>' instead.\n" );
726
727 opts->sysdir = opts->system;
728 opts->system = NULL;
729 }
730
David 'Digit' Turner25eb6552011-02-25 15:07:11 +0100731 if (opts->nojni) {
732 opts->no_jni = opts->nojni;
733 opts->nojni = 0;
734 }
735
736 if (opts->nocache) {
737 opts->no_cache = opts->nocache;
738 opts->nocache = 0;
739 }
740
741 if (opts->noaudio) {
742 opts->no_audio = opts->noaudio;
743 opts->noaudio = 0;
744 }
745
746 if (opts->noskin) {
747 opts->no_skin = opts->noskin;
748 opts->noskin = 0;
749 }
750
751 /* If -no-cache is used, ignore any -cache argument */
752 if (opts->no_cache) {
753 opts->cache = 0;
754 }
755
756 /* the purpose of -no-audio is to disable sound output from the emulator,
757 * not to disable Audio emulation. So simply force the 'none' backends */
758 if (opts->no_audio)
759 opts->audio = "none";
760
761 /* we don't accept -skindir without -skin now
762 * to simplify the autoconfig stuff with virtual devices
763 */
764 if (opts->no_skin) {
765 opts->skin = "320x480";
766 opts->skindir = NULL;
767 }
768
769 if (opts->skindir) {
770 if (!opts->skin) {
771 derror( "the -skindir <path> option requires a -skin <name> option");
772 exit(1);
773 }
774 }
David 'Digit' Turner0b019492011-03-01 14:02:42 +0100775
776 if (opts->bootchart) {
777 char* end;
778 int timeout = strtol(opts->bootchart, &end, 10);
779 if (timeout == 0)
780 opts->bootchart = NULL;
781 else if (timeout < 0 || timeout > 15*60) {
782 derror( "timeout specified for -bootchart option is invalid.\n"
783 "please use integers between 1 and 900\n");
784 exit(1);
785 }
786 }
David 'Digit' Turner25eb6552011-02-25 15:07:11 +0100787}
788
789AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild)
790{
791 AvdInfo* ret = NULL;
792 char tmp[MAX_PATH];
793 char* tmpend = tmp + sizeof(tmp);
794 char* android_build_root = NULL;
795 char* android_build_out = NULL;
796
Vladimir Chtchetkine83ffd662011-02-11 12:40:59 -0800797 /* If no AVD name was given, try to find the top of the
798 * Android build tree
799 */
800 if (opts->avd == NULL) {
801 do {
802 char* out = getenv("ANDROID_PRODUCT_OUT");
803
804 if (out == NULL || out[0] == 0)
805 break;
806
807 if (!path_exists(out)) {
808 derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
809 "You need to build the Android system before launching the emulator",
810 out);
811 exit(2);
812 }
813
814 android_build_root = path_parent( out, 4 );
815 if (android_build_root == NULL || !path_exists(android_build_root)) {
816 derror("Can't find the Android build root from '%s'\n"
817 "Please check the definition of the ANDROID_PRODUCT_OUT variable.\n"
818 "It should point to your product-specific build output directory.\n",
819 out );
820 exit(2);
821 }
822 android_build_out = out;
823 D( "found Android build root: %s", android_build_root );
824 D( "found Android build out: %s", android_build_out );
825 } while (0);
826 }
827 /* if no virtual device name is given, and we're not in the
828 * Android build system, we'll need to perform some auto-detection
829 * magic :-)
830 */
831 if (opts->avd == NULL && !android_build_out)
832 {
833 char dataDirIsSystem = 0;
834
835 if (!opts->sysdir) {
836 opts->sysdir = _getSdkImagePath("system.img");
837 if (!opts->sysdir) {
838 derror(
839 "You did not specify a virtual device name, and the system\n"
840 "directory could not be found.\n\n"
841 "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
842 "to start a given virtual device (see -help-avd for details).\n\n"
843
844 "Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
845 );
846 exit(2);
847 }
848 D("autoconfig: -sysdir %s", opts->sysdir);
849 }
850
851 if (!opts->system) {
852 opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
853 D("autoconfig: -image %s", opts->image);
854 }
855
856 if (!opts->kernel) {
857 opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
858 D("autoconfig: -kernel %s", opts->kernel);
859 }
860
861 if (!opts->ramdisk) {
862 opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
863 D("autoconfig: -ramdisk %s", opts->ramdisk);
864 }
865
866 /* if no data directory is specified, use the system directory */
867 if (!opts->datadir) {
868 opts->datadir = android_strdup(opts->sysdir);
869 dataDirIsSystem = 1;
870 D("autoconfig: -datadir %s", opts->sysdir);
871 }
872
873 if (!opts->data) {
874 /* check for userdata-qemu.img in the data directory */
875 bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
876 if (!path_exists(tmp)) {
877 derror(
878 "You did not provide the name of an Android Virtual Device\n"
879 "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
880
881 "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
882 "to specify a data partition image file (I hope you know what you're doing).\n"
883 );
884 exit(2);
885 }
886
887 opts->data = android_strdup(tmp);
888 D("autoconfig: -data %s", opts->data);
889 }
890
Vladimir Chtchetkine83ffd662011-02-11 12:40:59 -0800891 if (!opts->snapstorage && opts->datadir) {
892 bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir);
893 if (path_exists(tmp)) {
894 opts->snapstorage = android_strdup(tmp);
895 D("autoconfig: -snapstorage %s", opts->snapstorage);
896 }
897 }
Vladimir Chtchetkine83ffd662011-02-11 12:40:59 -0800898 }
899
Vladimir Chtchetkine83ffd662011-02-11 12:40:59 -0800900 /* setup the virtual device differently depending on whether
901 * we are in the Android build system or not
902 */
903 if (opts->avd != NULL)
904 {
905 ret = avdInfo_new( opts->avd, android_avdParams );
906 if (ret == NULL) {
907 /* an error message has already been printed */
908 dprint("could not find virtual device named '%s'", opts->avd);
909 exit(1);
910 }
911 }
912 else
913 {
914 if (!android_build_out) {
915 android_build_out = android_build_root = opts->sysdir;
916 }
917 ret = avdInfo_newForAndroidBuild(
918 android_build_root,
919 android_build_out,
920 android_avdParams );
921
922 if(ret == NULL) {
923 D("could not start virtual device\n");
924 exit(1);
925 }
926 }
927
928 if (android_build_out) {
929 *inAndroidBuild = 1;
930 } else {
931 *inAndroidBuild = 0;
932 }
933
934 return ret;
935}
936
David 'Digit' Turnerbdb6f2d2011-02-23 15:57:25 +0100937
938
939
940#ifdef CONFIG_STANDALONE_UI
941
942#include "android/protocol/core-connection.h"
943#include "android/protocol/fb-updates-impl.h"
944#include "android/protocol/user-events-proxy.h"
945#include "android/protocol/core-commands-proxy.h"
946#include "android/protocol/ui-commands-impl.h"
947#include "android/protocol/attach-ui-impl.h"
948
949/* Emulator's core port. */
950int android_base_port = 0;
951
952// Base console port
953#define CORE_BASE_PORT 5554
954
955// Maximum number of core porocesses running simultaneously on a machine.
956#define MAX_CORE_PROCS 16
957
958// Socket timeout in millisec (set to 5 seconds)
959#define CORE_PORT_TIMEOUT_MS 5000
960
961#include "android/async-console.h"
962
963typedef struct {
964 LoopIo io[1];
965 int port;
966 int ok;
967 AsyncConsoleConnector connector[1];
968} CoreConsole;
969
970static void
971coreconsole_io_func(void* opaque, int fd, unsigned events)
972{
973 CoreConsole* cc = opaque;
974 AsyncStatus status;
David 'Digit' Turnerf9e333a2011-03-17 14:57:51 +0100975 status = asyncConsoleConnector_run(cc->connector);
David 'Digit' Turnerbdb6f2d2011-02-23 15:57:25 +0100976 if (status == ASYNC_COMPLETE) {
977 cc->ok = 1;
978 }
979}
980
981static void
982coreconsole_init(CoreConsole* cc, const SockAddress* address, Looper* looper)
983{
984 int fd = socket_create_inet(SOCKET_STREAM);
985 AsyncStatus status;
986 cc->port = sock_address_get_port(address);
987 cc->ok = 0;
988 loopIo_init(cc->io, looper, fd, coreconsole_io_func, cc);
989 if (fd >= 0) {
990 status = asyncConsoleConnector_connect(cc->connector, address, cc->io);
991 if (status == ASYNC_ERROR) {
992 cc->ok = 0;
993 }
994 }
995}
996
997static void
998coreconsole_done(CoreConsole* cc)
999{
1000 socket_close(cc->io->fd);
1001 loopIo_done(cc->io);
1002}
1003
1004/* List emulator core processes running on the given machine.
1005 * This routine is called from main() if -list-cores parameter is set in the
1006 * command line.
1007 * Param:
1008 * host Value passed with -list-core parameter. Must be either "localhost", or
1009 * an IP address of a machine where core processes must be enumerated.
1010 */
1011static void
1012list_running_cores(const char* host)
1013{
1014 Looper* looper;
1015 CoreConsole cores[MAX_CORE_PROCS];
1016 SockAddress address;
1017 int nn, found;
1018
1019 if (sock_address_init_resolve(&address, host, CORE_BASE_PORT, 0) < 0) {
1020 derror("Unable to resolve hostname %s: %s", host, errno_str);
1021 return;
1022 }
1023
1024 looper = looper_newGeneric();
1025
1026 for (nn = 0; nn < MAX_CORE_PROCS; nn++) {
1027 int port = CORE_BASE_PORT + nn*2;
1028 sock_address_set_port(&address, port);
1029 coreconsole_init(&cores[nn], &address, looper);
1030 }
1031
1032 looper_runWithTimeout(looper, CORE_PORT_TIMEOUT_MS*2);
1033
1034 found = 0;
1035 for (nn = 0; nn < MAX_CORE_PROCS; nn++) {
1036 int port = CORE_BASE_PORT + nn*2;
1037 if (cores[nn].ok) {
1038 if (found == 0) {
1039 fprintf(stdout, "Running emulator core processes:\n");
1040 }
1041 fprintf(stdout, "Emulator console port %d\n", port);
1042 found++;
1043 }
1044 coreconsole_done(&cores[nn]);
1045 }
1046 looper_free(looper);
1047
1048 if (found == 0) {
1049 fprintf(stdout, "There were no running emulator core processes found on %s.\n",
1050 host);
1051 }
1052}
1053
1054/* Attaches starting UI to a running core process.
1055 * This routine is called from main() when -attach-core parameter is set,
1056 * indicating that this UI instance should attach to a running core, rather than
1057 * start a new core process.
1058 * Param:
1059 * opts Android options containing non-NULL attach_core.
1060 * Return:
1061 * 0 on success, or -1 on failure.
1062 */
1063static int
1064attach_to_core(AndroidOptions* opts) {
1065 int iter;
1066 SockAddress console_socket;
1067 SockAddress** sockaddr_list;
1068 QEmulator* emulator;
1069
1070 // Parse attach_core param extracting the host name, and the port name.
1071 char* console_address = strdup(opts->attach_core);
1072 char* host_name = console_address;
1073 char* port_num = strchr(console_address, ':');
1074 if (port_num == NULL) {
1075 // The host name is ommited, indicating the localhost
1076 host_name = "localhost";
1077 port_num = console_address;
1078 } else if (port_num == console_address) {
1079 // Invalid.
1080 derror("Invalid value %s for -attach-core parameter\n",
1081 opts->attach_core);
1082 return -1;
1083 } else {
1084 *port_num = '\0';
1085 port_num++;
1086 if (*port_num == '\0') {
1087 // Invalid.
1088 derror("Invalid value %s for -attach-core parameter\n",
1089 opts->attach_core);
1090 return -1;
1091 }
1092 }
1093
1094 /* Create socket address list for the given address, and pull appropriate
1095 * address to use for connection. Note that we're fine copying that address
1096 * out of the list, since INET and IN6 will entirely fit into SockAddress
1097 * structure. */
1098 sockaddr_list =
1099 sock_address_list_create(host_name, port_num, SOCKET_LIST_FORCE_INET);
1100 free(console_address);
1101 if (sockaddr_list == NULL) {
1102 derror("Unable to resolve address %s: %s\n",
1103 opts->attach_core, errno_str);
1104 return -1;
1105 }
1106 for (iter = 0; sockaddr_list[iter] != NULL; iter++) {
1107 if (sock_address_get_family(sockaddr_list[iter]) == SOCKET_INET ||
1108 sock_address_get_family(sockaddr_list[iter]) == SOCKET_IN6) {
1109 memcpy(&console_socket, sockaddr_list[iter], sizeof(SockAddress));
1110 break;
1111 }
1112 }
1113 if (sockaddr_list[iter] == NULL) {
1114 derror("Unable to resolve address %s. Note that 'port' parameter passed to -attach-core\n"
1115 "must be resolvable into an IP address.\n", opts->attach_core);
1116 sock_address_list_free(sockaddr_list);
1117 return -1;
1118 }
1119 sock_address_list_free(sockaddr_list);
1120
1121 if (attachUiImpl_create(&console_socket)) {
1122 return -1;
1123 }
1124
1125 // Save core's port, and set the title.
1126 android_base_port = sock_address_get_port(&console_socket);
1127 emulator = qemulator_get();
1128 qemulator_set_title(emulator);
1129
1130 return 0;
1131}
1132
1133
1134void handle_ui_options( AndroidOptions* opts )
1135{
1136 // Lets see if user just wants to list core process.
1137 if (opts->list_cores) {
1138 fprintf(stdout, "Enumerating running core processes.\n");
1139 list_running_cores(opts->list_cores);
1140 exit(0);
1141 }
1142}
1143
1144int attach_ui_to_core( AndroidOptions* opts )
1145{
1146 // Lets see if we're attaching to a running core process here.
1147 if (opts->attach_core) {
1148 if (attach_to_core(opts)) {
1149 return -1;
1150 }
1151 // Connect to the core's UI control services.
1152 if (coreCmdProxy_create(attachUiImpl_get_console_socket())) {
1153 return -1;
1154 }
1155 // Connect to the core's user events service.
1156 if (userEventsProxy_create(attachUiImpl_get_console_socket())) {
1157 return -1;
1158 }
1159 }
1160 return 0;
1161}
1162
1163#else /* !CONFIG_STANDALONE_UI */
1164
1165void handle_ui_options( AndroidOptions* opts )
1166{
1167 return;
1168}
1169
1170int attach_ui_to_core( AndroidOptions* opts )
1171{
1172 return 0;
1173}
1174
1175#endif /* CONFIG_STANDALONE_UI */