main.c revision 34f2974ce7ec7c71beb47b5daf9089d5c8c40c79
1/* Copyright (C) 2006-2008 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 <signal.h>
14#include <unistd.h>
15#include <string.h>
16#include <sys/time.h>
17#ifdef _WIN32
18#include <process.h>
19#endif
20#include "libslirp.h"
21#include "sockets.h"
22
23#include "android/android.h"
24#include "qemu-common.h"
25#include "sysemu.h"
26#include "console.h"
27#include "user-events.h"
28
29#include <SDL.h>
30#include <SDL_syswm.h>
31
32#include "math.h"
33
34#include "android/charmap.h"
35#include "modem_driver.h"
36#include "shaper.h"
37#include "proxy_http.h"
38
39#include "android/utils/debug.h"
40#include "android/resource.h"
41#include "android/config.h"
42#include "android/config/config.h"
43
44#include "android/skin/image.h"
45#include "android/skin/trackball.h"
46#include "android/skin/keyboard.h"
47#include "android/skin/file.h"
48#include "android/skin/window.h"
49#include "android/skin/keyset.h"
50
51#include "android/gps.h"
52#include "android/hw-qemud.h"
53#include "android/hw-kmsg.h"
54#include "android/hw-lcd.h"
55#include "android/hw-control.h"
56#include "android/hw-sensors.h"
57#include "android/boot-properties.h"
58#include "android/user-config.h"
59#include "android/utils/bufprint.h"
60#include "android/utils/dirscanner.h"
61#include "android/utils/path.h"
62#include "android/utils/timezone.h"
63
64#include "android/cmdline-option.h"
65#include "android/help.h"
66#include "hw/goldfish_nand.h"
67#ifdef CONFIG_MEMCHECK
68#include "memcheck/memcheck.h"
69#endif  // CONFIG_MEMCHECK
70
71#include "android/globals.h"
72#include "tcpdump.h"
73
74#include "android/qemulator.h"
75
76/* in vl.c */
77extern void  qemu_help(int  code);
78
79#include "framebuffer.h"
80AndroidRotation  android_framebuffer_rotation;
81
82#define  STRINGIFY(x)   _STRINGIFY(x)
83#define  _STRINGIFY(x)  #x
84
85#ifdef ANDROID_SDK_TOOLS_REVISION
86#  define  VERSION_STRING  STRINGIFY(ANDROID_SDK_TOOLS_REVISION)".0"
87#else
88#  define  VERSION_STRING  "standalone"
89#endif
90
91#define  KEYSET_FILE    "default.keyset"
92SkinKeyset*      android_keyset;
93
94#define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
95
96extern int  control_console_start( int  port );  /* in control.c */
97
98extern int qemu_milli_needed;
99
100/* the default device DPI if none is specified by the skin
101 */
102#define  DEFAULT_DEVICE_DPI  165
103
104int    android_base_port;
105
106#if 0
107static int  opts->flashkeys;      /* forward */
108#endif
109
110static void  handle_key_command( void*  opaque, SkinKeyCommand  command, int  param );
111
112#ifdef CONFIG_TRACE
113extern void  start_tracing(void);
114extern void  stop_tracing(void);
115#endif
116
117unsigned long   android_verbose;
118
119int   qemu_cpu_delay = 0;
120int   qemu_cpu_delay_count;
121
122/***********************************************************************/
123/***********************************************************************/
124/*****                                                             *****/
125/*****            U T I L I T Y   R O U T I N E S                  *****/
126/*****                                                             *****/
127/***********************************************************************/
128/***********************************************************************/
129
130/***  CONFIGURATION
131 ***/
132
133static AUserConfig*  userConfig;
134
135void
136emulator_config_init( void )
137{
138    userConfig = auserConfig_new( android_avdInfo );
139}
140
141/* only call this function on normal exits, so that ^C doesn't save the configuration */
142void
143emulator_config_done( void )
144{
145    int  win_x, win_y;
146
147    if (!userConfig) {
148        D("no user configuration?");
149        return;
150    }
151
152    SDL_WM_GetPos( &win_x, &win_y );
153    auserConfig_setWindowPos(userConfig, win_x, win_y);
154    auserConfig_save(userConfig);
155}
156
157void *loadpng(const char *fn, unsigned *_width, unsigned *_height);
158void *readpng(const unsigned char*  base, size_t  size, unsigned *_width, unsigned *_height);
159
160#ifdef CONFIG_DARWIN
161#  define  ANDROID_ICON_PNG  "android_icon_256.png"
162#else
163#  define  ANDROID_ICON_PNG  "android_icon_16.png"
164#endif
165
166static void
167sdl_set_window_icon( void )
168{
169    static int  window_icon_set;
170
171    if (!window_icon_set)
172    {
173#ifdef _WIN32
174        HANDLE         handle = GetModuleHandle( NULL );
175        HICON          icon   = LoadIcon( handle, MAKEINTRESOURCE(1) );
176        SDL_SysWMinfo  wminfo;
177
178        SDL_GetWMInfo(&wminfo);
179
180        SetClassLong( wminfo.window, GCL_HICON, (LONG)icon );
181#else  /* !_WIN32 */
182        unsigned              icon_w, icon_h;
183        size_t                icon_bytes;
184        const unsigned char*  icon_data;
185        void*                 icon_pixels;
186
187        window_icon_set = 1;
188
189        icon_data = android_icon_find( ANDROID_ICON_PNG, &icon_bytes );
190        if ( !icon_data )
191            return;
192
193        icon_pixels = readpng( icon_data, icon_bytes, &icon_w, &icon_h );
194        if ( !icon_pixels )
195            return;
196
197       /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
198        * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
199        * on our CPU endianess
200        */
201        {
202            unsigned*  d     = icon_pixels;
203            unsigned*  d_end = d + icon_w*icon_h;
204
205            for ( ; d < d_end; d++ ) {
206                unsigned  pix = d[0];
207#if HOST_WORDS_BIGENDIAN
208                /* R,G,B,A read as RGBA => ARGB */
209                pix = ((pix >> 8) & 0xffffff) | (pix << 24);
210#else
211                /* R,G,B,A read as ABGR => ARGB */
212                pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
213#endif
214                d[0] = pix;
215            }
216        }
217
218        SDL_Surface* icon = sdl_surface_from_argb32( icon_pixels, icon_w, icon_h );
219        if (icon != NULL) {
220            SDL_WM_SetIcon(icon, NULL);
221            SDL_FreeSurface(icon);
222            free( icon_pixels );
223        }
224#endif	/* !_WIN32 */
225    }
226}
227
228/* see http://en.wikipedia.org/wiki/List_of_device_bandwidths or a complete list */
229const NetworkSpeed  android_netspeeds[] = {
230    { "gsm", "GSM/CSD", 14400, 14400 },
231    { "hscsd", "HSCSD", 14400, 43200 },
232    { "gprs", "GPRS", 40000, 80000 },
233    { "edge", "EDGE/EGPRS", 118400, 236800 },
234    { "umts", "UMTS/3G", 128000, 1920000 },
235    { "hsdpa", "HSDPA", 348000, 14400000 },
236    { "full", "no limit", 0, 0 },
237    { NULL, NULL, 0, 0 }
238};
239
240const NetworkLatency  android_netdelays[] = {
241    /* FIXME: these numbers are totally imaginary */
242    { "gprs", "GPRS", 150, 550 },
243    { "edge", "EDGE/EGPRS", 80, 400 },
244    { "umts", "UMTS/3G", 35, 200 },
245    { "none", "no latency", 0, 0 },
246    { NULL, NULL, 0, 0 }
247};
248
249
250
251
252#define  ONE_MB  (1024*1024)
253
254unsigned convertBytesToMB( uint64_t  size )
255{
256    if (size == 0)
257        return 0;
258
259    size = (size + ONE_MB-1) >> 20;
260    if (size > UINT_MAX)
261        size = UINT_MAX;
262
263    return (unsigned) size;
264}
265
266uint64_t  convertMBToBytes( unsigned  megaBytes )
267{
268    return ((uint64_t)megaBytes << 20);
269}
270
271/***********************************************************************/
272/***********************************************************************/
273/*****                                                             *****/
274/*****            S K I N   I M A G E S                            *****/
275/*****                                                             *****/
276/***********************************************************************/
277/***********************************************************************/
278
279/* called by the emulated framebuffer device each time the content of the
280 * framebuffer has changed. the rectangle is the bounding box of all changes
281 */
282static void
283sdl_update(DisplayState *ds, int x, int y, int w, int h)
284{
285    /* this function is being called from the console code that is currently inactive
286    ** simple totally ignore it...
287    */
288    (void)ds;
289    (void)x;
290    (void)y;
291    (void)w;
292    (void)h;
293}
294
295
296
297
298/* called by the emulated framebuffer device each time the framebuffer
299 * is resized or rotated */
300static void
301sdl_resize(DisplayState *ds)
302{
303    //fprintf(stderr, "weird, sdl_resize being called with framebuffer interface\n");
304    //exit(1);
305}
306
307
308/* called periodically to poll for user input events */
309static void sdl_refresh(DisplayState *ds)
310{
311    QEmulator*     emulator = ds->opaque;
312    SDL_Event      ev;
313    SkinWindow*    window   = emulator->window;
314    SkinKeyboard*  keyboard = emulator->keyboard;
315
316   /* this will eventually call sdl_update if the content of the VGA framebuffer
317    * has changed */
318    qframebuffer_check_updates();
319
320    if (window == NULL)
321        return;
322
323    while(SDL_PollEvent(&ev)){
324        switch(ev.type){
325        case SDL_VIDEOEXPOSE:
326            skin_window_redraw( window, NULL );
327            break;
328
329        case SDL_KEYDOWN:
330#ifdef _WIN32
331            /* special code to deal with Alt-F4 properly */
332            if (ev.key.keysym.sym == SDLK_F4 &&
333                ev.key.keysym.mod & KMOD_ALT) {
334              goto CleanExit;
335            }
336#endif
337#ifdef __APPLE__
338            /* special code to deal with Command-Q properly */
339            if (ev.key.keysym.sym == SDLK_q &&
340                ev.key.keysym.mod & KMOD_META) {
341              goto CleanExit;
342            }
343#endif
344            skin_keyboard_process_event( keyboard, &ev, 1 );
345            break;
346
347        case SDL_KEYUP:
348            skin_keyboard_process_event( keyboard, &ev, 0 );
349            break;
350
351        case SDL_MOUSEMOTION:
352            skin_window_process_event( window, &ev );
353            break;
354
355        case SDL_MOUSEBUTTONDOWN:
356        case SDL_MOUSEBUTTONUP:
357            {
358                int  down = (ev.type == SDL_MOUSEBUTTONDOWN);
359                if (ev.button.button == 4)
360                {
361                    /* scroll-wheel simulates DPad up */
362                    AndroidKeyCode  kcode;
363
364                    kcode = // qemulator_rotate_keycode(kKeyCodeDpadUp);
365                        android_keycode_rotate(kKeyCodeDpadUp,
366                            skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
367                    user_event_key( kcode, down );
368                }
369                else if (ev.button.button == 5)
370                {
371                    /* scroll-wheel simulates DPad down */
372                    AndroidKeyCode  kcode;
373
374                    kcode = // qemulator_rotate_keycode(kKeyCodeDpadDown);
375                        android_keycode_rotate(kKeyCodeDpadDown,
376                            skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
377                    user_event_key( kcode, down );
378                }
379                else if (ev.button.button == SDL_BUTTON_LEFT) {
380                    skin_window_process_event( window, &ev );
381                }
382#if 0
383                else {
384                fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n",
385                                down ? "down" : "up  ",
386                                ev.button.button, ev.button.state, ev.button.x, ev.button.y);
387                }
388#endif
389            }
390            break;
391
392        case SDL_QUIT:
393#if defined _WIN32 || defined __APPLE__
394        CleanExit:
395#endif
396            /* only save emulator config through clean exit */
397            qemulator_done(qemulator_get());
398            qemu_system_shutdown_request();
399            return;
400        }
401    }
402
403    skin_keyboard_flush( keyboard );
404}
405
406
407/* used to respond to a given keyboard command shortcut
408 */
409static void
410handle_key_command( void*  opaque, SkinKeyCommand  command, int  down )
411{
412    static const struct { SkinKeyCommand  cmd; AndroidKeyCode  kcode; }  keycodes[] =
413    {
414        { SKIN_KEY_COMMAND_BUTTON_CALL,   kKeyCodeCall },
415        { SKIN_KEY_COMMAND_BUTTON_HOME,   kKeyCodeHome },
416        { SKIN_KEY_COMMAND_BUTTON_BACK,   kKeyCodeBack },
417        { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall },
418        { SKIN_KEY_COMMAND_BUTTON_POWER,  kKeyCodePower },
419        { SKIN_KEY_COMMAND_BUTTON_SEARCH,      kKeyCodeSearch },
420        { SKIN_KEY_COMMAND_BUTTON_MENU,        kKeyCodeMenu },
421        { SKIN_KEY_COMMAND_BUTTON_DPAD_UP,     kKeyCodeDpadUp },
422        { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT,   kKeyCodeDpadLeft },
423        { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT,  kKeyCodeDpadRight },
424        { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN,   kKeyCodeDpadDown },
425        { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter },
426        { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP,   kKeyCodeVolumeUp },
427        { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown },
428        { SKIN_KEY_COMMAND_BUTTON_CAMERA,      kKeyCodeCamera },
429        { SKIN_KEY_COMMAND_NONE, 0 }
430    };
431    int          nn;
432#ifdef CONFIG_TRACE
433    static int   tracing = 0;
434#endif
435    QEmulator*   emulator = opaque;
436
437
438    for (nn = 0; keycodes[nn].kcode != 0; nn++) {
439        if (command == keycodes[nn].cmd) {
440            unsigned  code = keycodes[nn].kcode;
441            if (down)
442                code |= 0x200;
443            kbd_put_keycode( code );
444            return;
445        }
446    }
447
448    // for the show-trackball command, handle down events to enable, and
449    // up events to disable
450    if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) {
451        emulator->show_trackball = (down != 0);
452        skin_window_show_trackball( emulator->window, emulator->show_trackball );
453        //qemulator_set_title( emulator );
454        return;
455    }
456
457    // only handle down events for the rest
458    if (down == 0)
459        return;
460
461    switch (command)
462    {
463    case SKIN_KEY_COMMAND_TOGGLE_NETWORK:
464        {
465            qemu_net_disable = !qemu_net_disable;
466            if (android_modem) {
467                amodem_set_data_registration(
468                        android_modem,
469                qemu_net_disable ? A_REGISTRATION_UNREGISTERED
470                    : A_REGISTRATION_HOME);
471            }
472            D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" );
473        }
474        break;
475
476    case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN:
477        if (emulator->window) {
478            skin_window_toggle_fullscreen(emulator->window);
479        }
480        break;
481
482    case SKIN_KEY_COMMAND_TOGGLE_TRACING:
483        {
484#ifdef CONFIG_TRACE
485            tracing = !tracing;
486            if (tracing)
487                start_tracing();
488            else
489                stop_tracing();
490#endif
491        }
492        break;
493
494    case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL:
495        emulator->show_trackball = !emulator->show_trackball;
496        skin_window_show_trackball( emulator->window, emulator->show_trackball );
497        qemulator_set_title(emulator);
498        break;
499
500    case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
501    case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
502        if (emulator->onion)
503        {
504            int  alpha = emulator->onion_alpha;
505
506            if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP)
507                alpha += 16;
508            else
509                alpha -= 16;
510
511            if (alpha > 256)
512                alpha = 256;
513            else if (alpha < 0)
514                alpha = 0;
515
516            emulator->onion_alpha = alpha;
517            skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha );
518            skin_window_redraw( emulator->window, NULL );
519            //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 );
520        }
521        break;
522
523    case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV:
524    case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT:
525        {
526            SkinLayout*  layout = NULL;
527
528            if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) {
529                layout = emulator->layout->next;
530                if (layout == NULL)
531                    layout = emulator->layout_file->layouts;
532            }
533            else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) {
534                layout = emulator->layout_file->layouts;
535                while (layout->next && layout->next != emulator->layout)
536                    layout = layout->next;
537            }
538            if (layout != NULL) {
539                SkinRotation  rotation;
540
541                emulator->layout = layout;
542                skin_window_reset( emulator->window, layout );
543
544                rotation = skin_layout_get_dpad_rotation( layout );
545
546                if (emulator->keyboard)
547                    skin_keyboard_set_rotation( emulator->keyboard, rotation );
548
549                if (emulator->trackball) {
550                    skin_trackball_set_rotation( emulator->trackball, rotation );
551                    skin_window_set_trackball( emulator->window, emulator->trackball );
552                    skin_window_show_trackball( emulator->window, emulator->show_trackball );
553                }
554
555                skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
556
557                qframebuffer_invalidate_all();
558                qframebuffer_check_updates();
559            }
560        }
561        break;
562
563    default:
564        /* XXX: TODO ? */
565        ;
566    }
567}
568
569
570static void sdl_at_exit(void)
571{
572    emulator_config_done();
573    qemulator_done(qemulator_get());
574    SDL_Quit();
575}
576
577
578void sdl_display_init(DisplayState *ds, int full_screen, int  no_frame)
579{
580    QEmulator*    emulator = qemulator_get();
581    SkinDisplay*  disp     = skin_layout_get_display(emulator->layout);
582    DisplayChangeListener*  dcl;
583    int           width, height;
584
585    if (disp->rotation & 1) {
586        width  = disp->rect.size.h;
587        height = disp->rect.size.w;
588    } else {
589        width  = disp->rect.size.w;
590        height = disp->rect.size.h;
591    }
592
593    /* Register a display state object for the emulated framebuffer */
594    ds->allocator = &default_allocator;
595    ds->opaque    = emulator;
596    ds->surface   = qemu_create_displaysurface(ds, width, height);
597    register_displaystate(ds);
598
599    /* Register a change listener for it */
600    dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
601    dcl->dpy_update      = sdl_update;
602    dcl->dpy_resize      = sdl_resize;
603    dcl->dpy_refresh     = sdl_refresh;
604    dcl->dpy_text_cursor = NULL;
605    register_displaychangelistener(ds, dcl);
606
607    skin_keyboard_enable( emulator->keyboard, 1 );
608    skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
609}
610
611
612static const char*  skin_network_speed = NULL;
613static const char*  skin_network_delay = NULL;
614
615/* list of skin aliases */
616static const struct {
617    const char*  name;
618    const char*  alias;
619} skin_aliases[] = {
620    { "QVGA-L", "320x240" },
621    { "QVGA-P", "240x320" },
622    { "HVGA-L", "480x320" },
623    { "HVGA-P", "320x480" },
624    { "QVGA", "320x240" },
625    { "HVGA", "320x480" },
626    { NULL, NULL }
627};
628
629/* this is used by hw/events_device.c to send the charmap name to the system */
630const char*    android_skin_keycharmap = NULL;
631
632void init_skinned_ui(const char *path, const char *name, AndroidOptions*  opts)
633{
634    char      tmp[1024];
635    AConfig*  root;
636    AConfig*  n;
637    int       win_x, win_y, flags;
638
639    signal(SIGINT, SIG_DFL);
640#ifndef _WIN32
641    signal(SIGQUIT, SIG_DFL);
642#endif
643
644    /* we're not a game, so allow the screensaver to run */
645    putenv("SDL_VIDEO_ALLOW_SCREENSAVER=1");
646
647    flags = SDL_INIT_NOPARACHUTE;
648    if (!opts->no_window)
649        flags |= SDL_INIT_VIDEO;
650
651    if(SDL_Init(flags)){
652        fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
653        exit(1);
654    }
655
656    if (!opts->no_window) {
657        SDL_EnableUNICODE(!opts->raw_keys);
658        SDL_EnableKeyRepeat(0,0);
659
660        sdl_set_window_icon();
661    }
662    else
663    {
664#ifndef _WIN32
665       /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
666        * able to run the emulator in the background (e.g. "emulator &").
667        * despite the fact that the emulator should not grab input or try to
668        * write to the output in normal cases, we're stopped on some systems
669        * (e.g. OS X)
670        */
671        signal(SIGTTIN, SIG_IGN);
672        signal(SIGTTOU, SIG_IGN);
673#endif
674    }
675    atexit(sdl_at_exit);
676
677    root = aconfig_node("", "");
678
679    if(name) {
680        /* Support skin aliases like QVGA-H QVGA-P, etc...
681           But first we check if it's a directory that exist before applying
682           the alias */
683        int  checkAlias = 1;
684
685        if (path != NULL) {
686            bufprint(tmp, tmp+sizeof(tmp), "%s/%s", path, name);
687            if (path_exists(tmp)) {
688                checkAlias = 0;
689            } else {
690                D("there is no '%s' skin in '%s'", name, path);
691            }
692        }
693
694        if (checkAlias) {
695            int  nn;
696
697            for (nn = 0; ; nn++ ) {
698                const char*  skin_name  = skin_aliases[nn].name;
699                const char*  skin_alias = skin_aliases[nn].alias;
700
701                if ( !skin_name )
702                    break;
703
704                if ( !strcasecmp( skin_name, name ) ) {
705                    D("skin name '%s' aliased to '%s'", name, skin_alias);
706                    name = skin_alias;
707                    break;
708                }
709            }
710        }
711
712        /* Magically support skins like "320x240" */
713        if(isdigit(name[0])) {
714            char *x = strchr(name, 'x');
715            if(x && isdigit(x[1])) {
716                int width = atoi(name);
717                int height = atoi(x + 1);
718                sprintf(tmp,"display {\n  width %d\n  height %d\n}\n",
719                        width, height);
720                aconfig_load(root, strdup(tmp));
721                path = ":";
722                goto found_a_skin;
723            }
724        }
725
726        if (path == NULL) {
727            derror("unknown skin name '%s'", name);
728            exit(1);
729        }
730
731        sprintf(tmp, "%s/%s/layout", path, name);
732        D("trying to load skin file '%s'", tmp);
733
734        if(aconfig_load_file(root, tmp) >= 0) {
735            sprintf(tmp, "%s/%s/", path, name);
736            path = tmp;
737            goto found_a_skin;
738        } else {
739            dwarning("could not load skin file '%s', using built-in one\n",
740                     tmp);
741        }
742    }
743
744    {
745        const unsigned char*  layout_base;
746        size_t                layout_size;
747
748        name = "<builtin>";
749
750        layout_base = android_resource_find( "layout", &layout_size );
751        if (layout_base != NULL) {
752            char*  base = malloc( layout_size+1 );
753            memcpy( base, layout_base, layout_size );
754            base[layout_size] = 0;
755
756            D("parsing built-in skin layout file (size=%d)", (int)layout_size);
757            aconfig_load(root, base);
758            path = ":";
759        } else {
760            fprintf(stderr, "Couldn't load builtin skin\n");
761            exit(1);
762        }
763    }
764
765found_a_skin:
766    {
767        win_x = 10;
768        win_y = 10;
769
770        if (userConfig)
771            auserConfig_getWindowPos(userConfig, &win_x, &win_y);
772    }
773
774    if ( qemulator_init(qemulator_get(), root, path, win_x, win_y, opts ) < 0 ) {
775        fprintf(stderr, "### Error: could not load emulator skin '%s'\n", name);
776        exit(1);
777    }
778
779    android_skin_keycharmap = skin_keyboard_charmap_name(qemulator_get()->keyboard);
780
781    /* the default network speed and latency can now be specified by the device skin */
782    n = aconfig_find(root, "network");
783    if (n != NULL) {
784        skin_network_speed = aconfig_str(n, "speed", 0);
785        skin_network_delay = aconfig_str(n, "delay", 0);
786    }
787
788#if 0
789    /* create a trackball if needed */
790    n = aconfig_find(root, "trackball");
791    if (n != NULL) {
792        SkinTrackBallParameters  params;
793
794        params.x        = aconfig_unsigned(n, "x", 0);
795        params.y        = aconfig_unsigned(n, "y", 0);
796        params.diameter = aconfig_unsigned(n, "diameter", 20);
797        params.ring     = aconfig_unsigned(n, "ring", 1);
798
799        params.ball_color = aconfig_unsigned(n, "ball-color", 0xffe0e0e0);
800        params.dot_color  = aconfig_unsigned(n, "dot-color",  0xff202020 );
801        params.ring_color = aconfig_unsigned(n, "ring-color", 0xff000000 );
802
803        qemu_disp->trackball = skin_trackball_create( &params );
804        skin_trackball_refresh( qemu_disp->trackball );
805    }
806#endif
807
808    /* add an onion overlay image if needed */
809    if (opts->onion) {
810        SkinImage*  onion = skin_image_find_simple( opts->onion );
811        int         alpha, rotate;
812
813        if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
814            alpha = (256*alpha)/100;
815        } else
816            alpha = 128;
817
818        if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
819            rotate &= 3;
820        } else
821            rotate = SKIN_ROTATION_0;
822
823        qemulator_get()->onion          = onion;
824        qemulator_get()->onion_alpha    = alpha;
825        qemulator_get()->onion_rotation = rotate;
826    }
827}
828
829int qemu_main(int argc, char **argv);
830
831/* this function dumps the QEMU help */
832extern void  help( void );
833extern void  emulator_help( void );
834
835#define  VERBOSE_OPT(str,var)   { str, &var }
836
837#define  _VERBOSE_TAG(x,y)   { #x, VERBOSE_##x, y },
838static const struct { const char*  name; int  flag; const char*  text; }
839verbose_options[] = {
840    VERBOSE_TAG_LIST
841    { 0, 0, 0 }
842};
843
844int
845android_parse_network_speed(const char*  speed)
846{
847    int          n;
848    char*  end;
849    double       sp;
850
851    if (speed == NULL || speed[0] == 0) {
852        speed = DEFAULT_NETSPEED;
853    }
854
855    for (n = 0; android_netspeeds[n].name != NULL; n++) {
856        if (!strcmp(android_netspeeds[n].name, speed)) {
857            qemu_net_download_speed = android_netspeeds[n].download;
858            qemu_net_upload_speed   = android_netspeeds[n].upload;
859            return 0;
860        }
861    }
862
863    /* is this a number ? */
864    sp = strtod(speed, &end);
865    if (end == speed) {
866        return -1;
867    }
868
869    qemu_net_download_speed = qemu_net_upload_speed = sp*1000.;
870    if (*end == ':') {
871        speed = end+1;
872        sp = strtod(speed, &end);
873        if (end > speed) {
874            qemu_net_download_speed = sp*1000.;
875        }
876    }
877
878    if (android_modem)
879        amodem_set_data_network_type( android_modem,
880                                      android_parse_network_type(speed) );
881    return 0;
882}
883
884
885int
886android_parse_network_latency(const char*  delay)
887{
888    int  n;
889    char*  end;
890    double  sp;
891
892    if (delay == NULL || delay[0] == 0)
893        delay = DEFAULT_NETDELAY;
894
895    for (n = 0; android_netdelays[n].name != NULL; n++) {
896        if ( !strcmp( android_netdelays[n].name, delay ) ) {
897            qemu_net_min_latency = android_netdelays[n].min_ms;
898            qemu_net_max_latency = android_netdelays[n].max_ms;
899            return 0;
900        }
901    }
902
903    /* is this a number ? */
904    sp = strtod(delay, &end);
905    if (end == delay) {
906        return -1;
907    }
908
909    qemu_net_min_latency = qemu_net_max_latency = (int)sp;
910    if (*end == ':') {
911        delay = (const char*)end+1;
912        sp = strtod(delay, &end);
913        if (end > delay) {
914            qemu_net_max_latency = (int)sp;
915        }
916    }
917    return 0;
918}
919
920
921static int
922load_keyset(const char*  path)
923{
924    if (path_can_read(path)) {
925        AConfig*  root = aconfig_node("","");
926        if (!aconfig_load_file(root, path)) {
927            android_keyset = skin_keyset_new(root);
928            if (android_keyset != NULL) {
929                D( "keyset loaded from: %s", path);
930                return 0;
931            }
932        }
933    }
934    return -1;
935}
936
937static void
938parse_keyset(const char*  keyset, AndroidOptions*  opts)
939{
940    char   kname[MAX_PATH];
941    char   temp[MAX_PATH];
942    char*  p;
943    char*  end;
944
945    /* append .keyset suffix if needed */
946    if (strchr(keyset, '.') == NULL) {
947        p   =  kname;
948        end = p + sizeof(kname);
949        p   = bufprint(p, end, "%s.keyset", keyset);
950        if (p >= end) {
951            derror( "keyset name too long: '%s'\n", keyset);
952            exit(1);
953        }
954        keyset = kname;
955    }
956
957    /* look for a the keyset file */
958    p   = temp;
959    end = p + sizeof(temp);
960    p = bufprint_config_file(p, end, keyset);
961    if (p < end && load_keyset(temp) == 0)
962        return;
963
964    p = temp;
965    p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->sysdir, keyset);
966    if (p < end && load_keyset(temp) == 0)
967        return;
968
969    p = temp;
970    p = bufprint_app_dir(p, end);
971    p = bufprint(p, end, PATH_SEP "keysets" PATH_SEP "%s", keyset);
972    if (p < end && load_keyset(temp) == 0)
973        return;
974
975    return;
976}
977
978static void
979write_default_keyset( void )
980{
981    char   path[MAX_PATH];
982
983    bufprint_config_file( path, path+sizeof(path), KEYSET_FILE );
984
985    /* only write if there is no file here */
986    if ( !path_exists(path) ) {
987        int          fd = open( path, O_WRONLY | O_CREAT, 0666 );
988        int          ret;
989        const char*  ks = skin_keyset_get_default();
990
991
992        D( "writing default keyset file to %s", path );
993
994        if (fd < 0) {
995            D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) );
996            return;
997        }
998        CHECKED(ret, write(fd, ks, strlen(ks)));
999        close(fd);
1000    }
1001}
1002
1003#ifdef CONFIG_NAND_LIMITS
1004
1005static uint64_t
1006parse_nand_rw_limit( const char*  value )
1007{
1008    char*     end;
1009    uint64_t  val = strtoul( value, &end, 0 );
1010
1011    if (end == value) {
1012        derror( "bad parameter value '%s': expecting unsigned integer", value );
1013        exit(1);
1014    }
1015
1016    switch (end[0]) {
1017        case 'K':  val <<= 10; break;
1018        case 'M':  val <<= 20; break;
1019        case 'G':  val <<= 30; break;
1020        case 0: break;
1021        default:
1022            derror( "bad read/write limit suffix: use K, M or G" );
1023            exit(1);
1024    }
1025    return val;
1026}
1027
1028static void
1029parse_nand_limits(char*  limits)
1030{
1031    int      pid = -1, signal = -1;
1032    int64_t  reads = 0, writes = 0;
1033    char*    item = limits;
1034
1035    /* parse over comma-separated items */
1036    while (item && *item) {
1037        char*  next = strchr(item, ',');
1038        char*  end;
1039
1040        if (next == NULL) {
1041            next = item + strlen(item);
1042        } else {
1043            *next++ = 0;
1044        }
1045
1046        if ( !memcmp(item, "pid=", 4) ) {
1047            pid = strtol(item+4, &end, 10);
1048            if (end == NULL || *end) {
1049                derror( "bad parameter, expecting pid=<number>, got '%s'",
1050                        item );
1051                exit(1);
1052            }
1053            if (pid <= 0) {
1054                derror( "bad parameter: process identifier must be > 0" );
1055                exit(1);
1056            }
1057        }
1058        else if ( !memcmp(item, "signal=", 7) ) {
1059            signal = strtol(item+7,&end, 10);
1060            if (end == NULL || *end) {
1061                derror( "bad parameter: expecting signal=<number>, got '%s'",
1062                        item );
1063                exit(1);
1064            }
1065            if (signal <= 0) {
1066                derror( "bad parameter: signal number must be > 0" );
1067                exit(1);
1068            }
1069        }
1070        else if ( !memcmp(item, "reads=", 6) ) {
1071            reads = parse_nand_rw_limit(item+6);
1072        }
1073        else if ( !memcmp(item, "writes=", 7) ) {
1074            writes = parse_nand_rw_limit(item+7);
1075        }
1076        else {
1077            derror( "bad parameter '%s' (see -help-nand-limits)", item );
1078            exit(1);
1079        }
1080        item = next;
1081    }
1082    if (pid < 0) {
1083        derror( "bad paramater: missing pid=<number>" );
1084        exit(1);
1085    }
1086    else if (signal < 0) {
1087        derror( "bad parameter: missing signal=<number>" );
1088        exit(1);
1089    }
1090    else if (reads == 0 && writes == 0) {
1091        dwarning( "no read or write limit specified. ignoring -nand-limits" );
1092    } else {
1093        nand_threshold*  t;
1094
1095        t  = &android_nand_read_threshold;
1096        t->pid     = pid;
1097        t->signal  = signal;
1098        t->counter = 0;
1099        t->limit   = reads;
1100
1101        t  = &android_nand_write_threshold;
1102        t->pid     = pid;
1103        t->signal  = signal;
1104        t->counter = 0;
1105        t->limit   = writes;
1106    }
1107}
1108#endif /* CONFIG_NAND_LIMITS */
1109
1110void emulator_help( void )
1111{
1112    STRALLOC_DEFINE(out);
1113    android_help_main(out);
1114    printf( "%.*s", out->n, out->s );
1115    stralloc_reset(out);
1116    exit(1);
1117}
1118
1119static int
1120add_dns_server( const char*  server_name )
1121{
1122    SockAddress   addr;
1123
1124    if (sock_address_init_resolve( &addr, server_name, 55, 0 ) < 0) {
1125        fprintf(stderr,
1126                "### WARNING: can't resolve DNS server name '%s'\n",
1127                server_name );
1128        return -1;
1129    }
1130
1131    D( "DNS server name '%s' resolved to %s", server_name, sock_address_to_string(&addr) );
1132
1133    if ( slirp_add_dns_server( &addr ) < 0 ) {
1134        fprintf(stderr,
1135                "### WARNING: could not add DNS server '%s' to the network stack\n", server_name);
1136        return -1;
1137    }
1138    return 0;
1139}
1140
1141
1142/* this function is used to perform auto-detection of the
1143 * system directory in the case of a SDK installation.
1144 *
1145 * we want to deal with several historical usages, hence
1146 * the slightly complicated logic.
1147 *
1148 * NOTE: the function returns the path to the directory
1149 *       containing 'fileName'. this is *not* the full
1150 *       path to 'fileName'.
1151 */
1152static char*
1153_getSdkImagePath( const char*  fileName )
1154{
1155    char   temp[MAX_PATH];
1156    char*  p   = temp;
1157    char*  end = p + sizeof(temp);
1158    char*  q;
1159    char*  app;
1160
1161    static const char* const  searchPaths[] = {
1162        "",                                  /* program's directory */
1163        "/lib/images",                       /* this is for SDK 1.0 */
1164        "/../platforms/android-1.1/images",  /* this is for SDK 1.1 */
1165        NULL
1166    };
1167
1168    app = bufprint_app_dir(temp, end);
1169    if (app >= end)
1170        return NULL;
1171
1172    do {
1173        int  nn;
1174
1175        /* first search a few well-known paths */
1176        for (nn = 0; searchPaths[nn] != NULL; nn++) {
1177            p = bufprint(app, end, "%s", searchPaths[nn]);
1178            q = bufprint(p, end, "/%s", fileName);
1179            if (q < end && path_exists(temp)) {
1180                *p = 0;
1181                goto FOUND_IT;
1182            }
1183        }
1184
1185        /* hmmm. let's assume that we are in a post-1.1 SDK
1186         * scan ../platforms if it exists
1187         */
1188        p = bufprint(app, end, "/../platforms");
1189        if (p < end) {
1190            DirScanner*  scanner = dirScanner_new(temp);
1191            if (scanner != NULL) {
1192                int          found = 0;
1193                const char*  subdir;
1194
1195                for (;;) {
1196                    subdir = dirScanner_next(scanner);
1197                    if (!subdir) break;
1198
1199                    q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
1200                    if (q >= end || !path_exists(temp))
1201                        continue;
1202
1203                    found = 1;
1204                    p = bufprint(p, end, "/%s/images", subdir);
1205                    break;
1206                }
1207                dirScanner_free(scanner);
1208                if (found)
1209                    break;
1210            }
1211        }
1212
1213        /* I'm out of ideas */
1214        return NULL;
1215
1216    } while (0);
1217
1218FOUND_IT:
1219    //D("image auto-detection: %s/%s", temp, fileName);
1220    return qemu_strdup(temp);
1221}
1222
1223static char*
1224_getSdkImage( const char*  path, const char*  file )
1225{
1226    char  temp[MAX_PATH];
1227    char  *p = temp, *end = p + sizeof(temp);
1228
1229    p = bufprint(temp, end, "%s/%s", path, file);
1230    if (p >= end || !path_exists(temp))
1231        return NULL;
1232
1233    return qemu_strdup(temp);
1234}
1235
1236static char*
1237_getSdkSystemImage( const char*  path, const char*  optionName, const char*  file )
1238{
1239    char*  image = _getSdkImage(path, file);
1240
1241    if (image == NULL) {
1242        derror("Your system directory is missing the '%s' image file.\n"
1243               "Please specify one with the '%s <filepath>' option",
1244               file, optionName);
1245        exit(2);
1246    }
1247    return image;
1248}
1249
1250static void
1251_forceAvdImagePath( AvdImageType  imageType,
1252                   const char*   path,
1253                   const char*   description,
1254                   int           required )
1255{
1256    if (path == NULL)
1257        return;
1258
1259    if (required && !path_exists(path)) {
1260        derror("Cannot find %s image file: %s", description, path);
1261        exit(1);
1262    }
1263    android_avdParams->forcePaths[imageType] = path;
1264}
1265
1266static uint64_t
1267_adjustPartitionSize( const char*  description,
1268                      uint64_t     imageBytes,
1269                      uint64_t     defaultBytes,
1270                      int          inAndroidBuild )
1271{
1272    char      temp[64];
1273    unsigned  imageMB;
1274    unsigned  defaultMB;
1275
1276    if (imageBytes <= defaultBytes)
1277        return defaultBytes;
1278
1279    imageMB   = convertBytesToMB(imageBytes);
1280    defaultMB = convertBytesToMB(defaultBytes);
1281
1282    if (imageMB > defaultMB) {
1283        snprintf(temp, sizeof temp, "(%d MB > %d MB)", imageMB, defaultMB);
1284    } else {
1285        snprintf(temp, sizeof temp, "(%lld bytes > %lld bytes)", imageBytes, defaultBytes);
1286    }
1287
1288    if (inAndroidBuild) {
1289        dwarning("%s partition size adjusted to match image file %s\n", description, temp);
1290    }
1291
1292    return convertMBToBytes(imageMB);
1293}
1294
1295
1296int main(int argc, char **argv)
1297{
1298    char   tmp[MAX_PATH];
1299    char*  tmpend = tmp + sizeof(tmp);
1300    char*  args[128];
1301    int    n;
1302    char*  opt;
1303    int    use_sdcard_img = 0;
1304    int    serial = 0;
1305    int    gps_serial = 0;
1306    int    radio_serial = 0;
1307    int    qemud_serial = 0;
1308    int    shell_serial = 0;
1309    int    dns_count = 0;
1310    unsigned  cachePartitionSize = 0;
1311    unsigned  systemPartitionSize = 0;
1312    unsigned  dataPartitionSize = 0;
1313    unsigned  defaultPartitionSize = convertMBToBytes(66);
1314
1315    AndroidHwConfig*  hw;
1316    AvdInfo*          avd;
1317
1318    //const char *appdir = get_app_dir();
1319    char*       android_build_root = NULL;
1320    char*       android_build_out  = NULL;
1321
1322    AndroidOptions  opts[1];
1323
1324    args[0] = argv[0];
1325
1326    if ( android_parse_options( &argc, &argv, opts ) < 0 ) {
1327        exit(1);
1328    }
1329
1330    while (argc-- > 1) {
1331        opt = (++argv)[0];
1332
1333        if(!strcmp(opt, "-qemu")) {
1334            argc--;
1335            argv++;
1336            break;
1337        }
1338
1339        if (!strcmp(opt, "-help")) {
1340            emulator_help();
1341        }
1342
1343        if (!strncmp(opt, "-help-",6)) {
1344            STRALLOC_DEFINE(out);
1345            opt += 6;
1346
1347            if (!strcmp(opt, "all")) {
1348                android_help_all(out);
1349            }
1350            else if (android_help_for_option(opt, out) == 0) {
1351                /* ok */
1352            }
1353            else if (android_help_for_topic(opt, out) == 0) {
1354                /* ok */
1355            }
1356            if (out->n > 0) {
1357                printf("\n%.*s", out->n, out->s);
1358                exit(0);
1359            }
1360
1361            fprintf(stderr, "unknown option: -help-%s\n", opt);
1362            fprintf(stderr, "please use -help for a list of valid topics\n");
1363            exit(1);
1364        }
1365
1366        if (opt[0] == '-') {
1367            fprintf(stderr, "unknown option: %s\n", opt);
1368            fprintf(stderr, "please use -help for a list of valid options\n");
1369            exit(1);
1370        }
1371
1372        fprintf(stderr, "invalid command-line parameter: %s.\n", opt);
1373        fprintf(stderr, "Hint: use '@foo' to launch a virtual device named 'foo'.\n");
1374        fprintf(stderr, "please use -help for more information\n");
1375        exit(1);
1376    }
1377
1378    /* special case, if -qemu -h is used, directly invoke the QEMU-specific help */
1379    if (argc > 0) {
1380        int  nn;
1381        for (nn = 0; nn < argc; nn++)
1382            if (!strcmp(argv[nn], "-h")) {
1383                qemu_help(0);
1384                break;
1385            }
1386    }
1387
1388    if (android_charmap_setup(opts->charmap)) {
1389        exit(1);
1390    }
1391
1392    if (opts->version) {
1393        printf("Android emulator version %s\n"
1394               "Copyright (C) 2006-2008 The Android Open Source Project and many others.\n"
1395               "This program is a derivative of the QEMU CPU emulator (www.qemu.org).\n\n",
1396#if defined ANDROID_BUILD_ID
1397               VERSION_STRING " (build_id " STRINGIFY(ANDROID_BUILD_ID) ")" );
1398#else
1399               VERSION_STRING);
1400#endif
1401        printf("  This software is licensed under the terms of the GNU General Public\n"
1402               "  License version 2, as published by the Free Software Foundation, and\n"
1403               "  may be copied, distributed, and modified under those terms.\n\n"
1404               "  This program is distributed in the hope that it will be useful,\n"
1405               "  but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1406               "  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1407               "  GNU General Public License for more details.\n\n");
1408
1409        exit(0);
1410    }
1411
1412    if (opts->timezone) {
1413        if ( timezone_set(opts->timezone) < 0 ) {
1414            fprintf(stderr, "emulator: it seems the timezone '%s' is not in zoneinfo format\n", opts->timezone);
1415        }
1416    }
1417
1418    /* legacy support: we used to use -system <dir> and -image <file>
1419     * instead of -sysdir <dir> and -system <file>, so handle this by checking
1420     * whether the options point to directories or files.
1421     */
1422    if (opts->image != NULL) {
1423        if (opts->system != NULL) {
1424            if (opts->sysdir != NULL) {
1425                derror( "You can't use -sysdir, -system and -image at the same time.\n"
1426                        "You should probably use '-sysdir <path> -system <file>'.\n" );
1427                exit(2);
1428            }
1429        }
1430        dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
1431                  "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
1432        opts->sysdir = opts->system;
1433        opts->system = opts->image;
1434        opts->image  = NULL;
1435    }
1436    else if (opts->system != NULL && path_is_dir(opts->system)) {
1437        if (opts->sysdir != NULL) {
1438            derror( "Option -system should now be followed by a file path, not a directory one.\n"
1439                    "Please use '-sysdir <path>' to point to the system directory.\n" );
1440            exit(1);
1441        }
1442        dwarning( "Please note that the -system option should now be used to point to the initial\n"
1443                  "system image (like the obsolete -image option). To point to the system directory\n"
1444                  "please now use '-sysdir <path>' instead.\n" );
1445
1446        opts->sysdir = opts->system;
1447        opts->system = NULL;
1448    }
1449
1450    if (opts->nojni)
1451        opts->no_jni = opts->nojni;
1452
1453    if (opts->nocache)
1454        opts->no_cache = opts->nocache;
1455
1456    if (opts->noaudio)
1457        opts->no_audio = opts->noaudio;
1458
1459    if (opts->noskin)
1460        opts->no_skin = opts->noskin;
1461
1462    if (opts->initdata) {
1463        opts->init_data = opts->initdata;
1464        opts->initdata  = NULL;
1465    }
1466
1467    /* If no AVD name was given, try to find the top of the
1468     * Android build tree
1469     */
1470    if (opts->avd == NULL) {
1471        do {
1472            char*  out = getenv("ANDROID_PRODUCT_OUT");
1473
1474            if (out == NULL || out[0] == 0)
1475                break;
1476
1477            if (!path_exists(out)) {
1478                derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
1479                    "You need to build the Android system before launching the emulator",
1480                    out);
1481                exit(2);
1482            }
1483
1484            android_build_root = path_parent( out, 4 );
1485            if (android_build_root == NULL || !path_exists(android_build_root)) {
1486                derror("Can't find the Android build root from '%s'\n"
1487                    "Please check the definition of the ANDROID_PRODUCT_OUT variable.\n"
1488                    "It should point to your product-specific build output directory.\n",
1489                    out );
1490                exit(2);
1491            }
1492            android_build_out = out;
1493            D( "found Android build root: %s", android_build_root );
1494            D( "found Android build out:  %s", android_build_out );
1495        } while (0);
1496    }
1497    /* if no virtual device name is given, and we're not in the
1498     * Android build system, we'll need to perform some auto-detection
1499     * magic :-)
1500     */
1501    if (opts->avd == NULL && !android_build_out)
1502    {
1503        char   dataDirIsSystem = 0;
1504
1505        if (!opts->sysdir) {
1506            opts->sysdir = _getSdkImagePath("system.img");
1507            if (!opts->sysdir) {
1508                derror(
1509                "You did not specify a virtual device name, and the system\n"
1510                "directory could not be found.\n\n"
1511                "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
1512                "to start a given virtual device (see -help-avd for details).\n\n"
1513
1514                "Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
1515                );
1516                exit(2);
1517            }
1518            D("autoconfig: -sysdir %s", opts->sysdir);
1519        }
1520
1521        if (!opts->system) {
1522            opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
1523            D("autoconfig: -image %s", opts->image);
1524        }
1525
1526        if (!opts->kernel) {
1527            opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
1528            D("autoconfig: -kernel %s", opts->kernel);
1529        }
1530
1531        if (!opts->ramdisk) {
1532            opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
1533            D("autoconfig: -ramdisk %s", opts->ramdisk);
1534        }
1535
1536        /* if no data directory is specified, use the system directory */
1537        if (!opts->datadir) {
1538            opts->datadir   = qemu_strdup(opts->sysdir);
1539            dataDirIsSystem = 1;
1540            D("autoconfig: -datadir %s", opts->sysdir);
1541        }
1542
1543        if (!opts->data) {
1544            /* check for userdata-qemu.img in the data directory */
1545            bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
1546            if (!path_exists(tmp)) {
1547                derror(
1548                "You did not provide the name of an Android Virtual Device\n"
1549                "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
1550
1551                "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
1552                "to specify a data partition image file (I hope you know what you're doing).\n"
1553                );
1554                exit(2);
1555            }
1556
1557            opts->data = qemu_strdup(tmp);
1558            D("autoconfig: -data %s", opts->data);
1559        }
1560
1561        if (!opts->sdcard && opts->datadir) {
1562            bufprint(tmp, tmpend, "%s/sdcard.img", opts->datadir);
1563            if (path_exists(tmp)) {
1564                opts->sdcard = qemu_strdup(tmp);
1565                D("autoconfig: -sdcard %s", opts->sdcard);
1566            }
1567        }
1568    }
1569
1570    /* setup the virtual device parameters from our options
1571     */
1572    if (opts->no_cache) {
1573        android_avdParams->flags |= AVDINFO_NO_CACHE;
1574    }
1575    if (opts->wipe_data) {
1576        android_avdParams->flags |= AVDINFO_WIPE_DATA | AVDINFO_WIPE_CACHE;
1577    }
1578
1579    /* if certain options are set, we can force the path of
1580        * certain kernel/disk image files
1581        */
1582    _forceAvdImagePath(AVD_IMAGE_KERNEL,     opts->kernel, "kernel", 1);
1583    _forceAvdImagePath(AVD_IMAGE_INITSYSTEM, opts->system, "system", 1);
1584    _forceAvdImagePath(AVD_IMAGE_RAMDISK,    opts->ramdisk,"ramdisk", 1);
1585    _forceAvdImagePath(AVD_IMAGE_USERDATA,   opts->data,   "user data", 0);
1586    _forceAvdImagePath(AVD_IMAGE_CACHE,      opts->cache,  "cache", 0);
1587    _forceAvdImagePath(AVD_IMAGE_SDCARD,     opts->sdcard, "SD Card", 0);
1588
1589    /* we don't accept -skindir without -skin now
1590     * to simplify the autoconfig stuff with virtual devices
1591     */
1592    if (opts->no_skin) {
1593        opts->skin    = "320x480";
1594        opts->skindir = NULL;
1595    }
1596
1597    if (opts->skindir) {
1598        if (!opts->skin) {
1599            derror( "the -skindir <path> option requires a -skin <name> option");
1600            exit(1);
1601        }
1602    }
1603    android_avdParams->skinName     = opts->skin;
1604    android_avdParams->skinRootPath = opts->skindir;
1605
1606    /* setup the virtual device differently depending on whether
1607     * we are in the Android build system or not
1608     */
1609    if (opts->avd != NULL)
1610    {
1611        android_avdInfo = avdInfo_new( opts->avd, android_avdParams );
1612        if (android_avdInfo == NULL) {
1613            /* an error message has already been printed */
1614            dprint("could not find virtual device named '%s'", opts->avd);
1615            exit(1);
1616        }
1617    }
1618    else
1619    {
1620        if (!android_build_out) {
1621            android_build_out = android_build_root = opts->sysdir;
1622        }
1623        android_avdInfo = avdInfo_newForAndroidBuild(
1624                            android_build_root,
1625                            android_build_out,
1626                            android_avdParams );
1627
1628        if(android_avdInfo == NULL) {
1629            D("could not start virtual device\n");
1630            exit(1);
1631        }
1632    }
1633
1634    avd = android_avdInfo;
1635
1636    /* get the skin from the virtual device configuration */
1637    opts->skin    = (char*) avdInfo_getSkinName( avd );
1638    opts->skindir = (char*) avdInfo_getSkinDir( avd );
1639
1640    if (opts->skin) {
1641        D("autoconfig: -skin %s", opts->skin);
1642    }
1643    if (opts->skindir) {
1644        D("autoconfig: -skindir %s", opts->skindir);
1645    }
1646
1647    /* Read hardware configuration */
1648    hw = android_hw;
1649    if (avdInfo_getHwConfig(avd, hw) < 0) {
1650        derror("could not read hardware configuration ?");
1651        exit(1);
1652    }
1653
1654#ifdef CONFIG_NAND_LIMITS
1655    if (opts->nand_limits)
1656        parse_nand_limits(opts->nand_limits);
1657#endif
1658
1659    if (opts->keyset) {
1660        parse_keyset(opts->keyset, opts);
1661        if (!android_keyset) {
1662            fprintf(stderr,
1663                    "emulator: WARNING: could not find keyset file named '%s',"
1664                    " using defaults instead\n",
1665                    opts->keyset);
1666        }
1667    }
1668    if (!android_keyset) {
1669        parse_keyset("default", opts);
1670        if (!android_keyset) {
1671            android_keyset = skin_keyset_new_from_text( skin_keyset_get_default() );
1672            if (!android_keyset) {
1673                fprintf(stderr, "PANIC: default keyset file is corrupted !!\n" );
1674                fprintf(stderr, "PANIC: please update the code in android/skin/keyset.c\n" );
1675                exit(1);
1676            }
1677            if (!opts->keyset)
1678                write_default_keyset();
1679        }
1680    }
1681
1682    /* the purpose of -no-audio is to disable sound output from the emulator,
1683     * not to disable Audio emulation. So simply force the 'none' backends */
1684    if (opts->no_audio)
1685        opts->audio = "none";
1686
1687    if (opts->audio) {
1688        if (opts->audio_in || opts->audio_out) {
1689            derror( "you can't use -audio with -audio-in or -audio-out\n" );
1690            exit(1);
1691        }
1692        if ( !audio_check_backend_name( 0, opts->audio ) ) {
1693            derror( "'%s' is not a valid audio output backend. see -help-audio-out\n",
1694                    opts->audio);
1695            exit(1);
1696        }
1697        opts->audio_out = opts->audio;
1698        opts->audio_in  = opts->audio;
1699
1700        if ( !audio_check_backend_name( 1, opts->audio ) ) {
1701            fprintf(stderr,
1702                    "emulator: warning: '%s' is not a valid audio input backend. audio record disabled\n",
1703                    opts->audio);
1704            opts->audio_in = "none";
1705        }
1706    }
1707
1708    if (opts->audio_in) {
1709        static char  env[64]; /* note: putenv needs a static unique string buffer */
1710        if ( !audio_check_backend_name( 1, opts->audio_in ) ) {
1711            derror( "'%s' is not a valid audio input backend. see -help-audio-in\n",
1712                    opts->audio_in);
1713            exit(1);
1714        }
1715        bufprint( env, env+sizeof(env), "QEMU_AUDIO_IN_DRV=%s", opts->audio_in );
1716        putenv( env );
1717
1718        if (!hw->hw_audioInput) {
1719            dwarning( "Emulated hardware doesn't have audio input.");
1720        }
1721    }
1722    if (opts->audio_out) {
1723        static char  env[64]; /* note: putenv needs a static unique string buffer */
1724        if ( !audio_check_backend_name( 0, opts->audio_out ) ) {
1725            derror( "'%s' is not a valid audio output backend. see -help-audio-out\n",
1726                    opts->audio_out);
1727            exit(1);
1728        }
1729        bufprint( env, env+sizeof(env), "QEMU_AUDIO_OUT_DRV=%s", opts->audio_out );
1730        putenv( env );
1731        if (!hw->hw_audioOutput) {
1732            dwarning( "Emulated hardware doesn't have audio output");
1733        }
1734    }
1735
1736    if (opts->cpu_delay) {
1737        char*   end;
1738        long    delay = strtol(opts->cpu_delay, &end, 0);
1739        if (end == NULL || *end || delay < 0 || delay > 1000 ) {
1740            fprintf(stderr, "option -cpu-delay must be an integer between 0 and 1000\n" );
1741            exit(1);
1742        }
1743        if (delay > 0)
1744            delay = (1000-delay);
1745
1746        qemu_cpu_delay = (int) delay;
1747    }
1748
1749    if (opts->shared_net_id) {
1750        char*  end;
1751        long   shared_net_id = strtol(opts->shared_net_id, &end, 0);
1752        if (end == NULL || *end || shared_net_id < 1 || shared_net_id > 255) {
1753            fprintf(stderr, "option -shared-net-id must be an integer between 1 and 255\n");
1754            exit(1);
1755        }
1756        char ip[11];
1757        snprintf(ip, 11, "10.1.2.%ld", shared_net_id);
1758        boot_property_add("net.shared_net_ip",ip);
1759    }
1760
1761
1762    emulator_config_init();
1763    init_skinned_ui(opts->skindir, opts->skin, opts);
1764
1765    if (!opts->netspeed) {
1766        if (skin_network_speed)
1767            D("skin network speed: '%s'", skin_network_speed);
1768        opts->netspeed = (char*)skin_network_speed;
1769    }
1770    if (!opts->netdelay) {
1771        if (skin_network_delay)
1772            D("skin network delay: '%s'", skin_network_delay);
1773        opts->netdelay = (char*)skin_network_delay;
1774    }
1775
1776    if ( android_parse_network_speed(opts->netspeed) < 0 ) {
1777        fprintf(stderr, "invalid -netspeed parameter '%s', see emulator -usage\n", opts->netspeed);
1778        emulator_help();
1779    }
1780
1781    if ( android_parse_network_latency(opts->netdelay) < 0 ) {
1782        fprintf(stderr, "invalid -netdelay parameter '%s', see emulator -usage\n", opts->netdelay);
1783        emulator_help();
1784    }
1785
1786    if (opts->netfast) {
1787        qemu_net_download_speed = 0;
1788        qemu_net_upload_speed = 0;
1789        qemu_net_min_latency = 0;
1790        qemu_net_max_latency = 0;
1791    }
1792
1793    if (opts->trace) {
1794        char*   tracePath = avdInfo_getTracePath(avd, opts->trace);
1795        int     ret;
1796
1797        if (tracePath == NULL) {
1798            derror( "bad -trace parameter" );
1799            exit(1);
1800        }
1801        ret = path_mkdir_if_needed( tracePath, 0755 );
1802        if (ret < 0) {
1803            fprintf(stderr, "could not create directory '%s'\n", tmp);
1804            exit(2);
1805        }
1806        opts->trace = tracePath;
1807    }
1808
1809#ifdef CONFIG_MEMCHECK
1810    if (opts->memcheck) {
1811        memcheck_init(opts->memcheck);
1812    }
1813#endif  // CONFIG_MEMCHECK
1814
1815    if (opts->tcpdump) {
1816        if (qemu_tcpdump_start(opts->tcpdump) < 0) {
1817            dwarning( "could not start packet capture: %s", strerror(errno));
1818        }
1819    }
1820
1821    if (opts->no_cache)
1822        opts->cache = 0;
1823
1824    if (opts->dns_server) {
1825        char*  x = strchr(opts->dns_server, ',');
1826        dns_count = 0;
1827        if (x == NULL)
1828        {
1829            if ( add_dns_server( opts->dns_server ) == 0 )
1830                dns_count = 1;
1831        }
1832        else
1833        {
1834            x = strdup(opts->dns_server);
1835            while (*x) {
1836                char*  y = strchr(x, ',');
1837
1838                if (y != NULL)
1839                    *y = 0;
1840
1841                if (y == NULL || y > x) {
1842                    if ( add_dns_server( x ) == 0 )
1843                        dns_count += 1;
1844                }
1845
1846                if (y == NULL)
1847                    break;
1848
1849                x = y+1;
1850            }
1851        }
1852        if (dns_count == 0)
1853            fprintf( stderr, "### WARNING: will use system default DNS server\n" );
1854    }
1855
1856    if (dns_count == 0)
1857        dns_count = slirp_get_system_dns_servers();
1858
1859    n = 1;
1860    /* generate arguments for the underlying qemu main() */
1861    {
1862        const char*  kernelFile    = avdInfo_getImageFile(avd, AVD_IMAGE_KERNEL);
1863        int          kernelFileLen = strlen(kernelFile);
1864
1865        args[n++] = "-kernel";
1866        args[n++] = (char*)kernelFile;
1867
1868        /* If the kernel image name ends in "-armv7", then change the cpu
1869         * type automatically. This is a poor man's approach to configuration
1870         * management, but should allow us to get past building ARMv7
1871         * system images with dex preopt pass without introducing too many
1872         * changes to the emulator sources.
1873         *
1874         * XXX:
1875         * A 'proper' change would require adding some sort of hardware-property
1876         * to each AVD config file, then automatically determine its value for
1877         * full Android builds (depending on some environment variable), plus
1878         * some build system changes. I prefer not to do that for now for reasons
1879         * of simplicity.
1880         */
1881         if (kernelFileLen > 6 && !memcmp(kernelFile + kernelFileLen - 6, "-armv7", 6)) {
1882            args[n++] = "-cpu";
1883            args[n++] = "cortex-a8";
1884         }
1885    }
1886
1887    args[n++] = "-initrd";
1888    args[n++] = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_RAMDISK);
1889
1890    if (opts->partition_size) {
1891        char*  end;
1892        long   sizeMB = strtol(opts->partition_size, &end, 0);
1893        long   minSizeMB = 10;
1894        long   maxSizeMB = LONG_MAX / ONE_MB;
1895
1896        if (sizeMB < 0 || *end != 0) {
1897            derror( "-partition-size must be followed by a positive integer" );
1898            exit(1);
1899        }
1900        if (sizeMB < minSizeMB || sizeMB > maxSizeMB) {
1901            derror( "partition-size (%d) must be between %dMB and %dMB",
1902                    sizeMB, minSizeMB, maxSizeMB );
1903            exit(1);
1904        }
1905        defaultPartitionSize = sizeMB * ONE_MB;
1906    }
1907
1908    /* Check the size of the system partition image.
1909     * If we have an AVD, it must be smaller than
1910     * the disk.systemPartition.size hardware property.
1911     *
1912     * Otherwise, we need to adjust the systemPartitionSize
1913     * automatically, and print a warning.
1914     *
1915     */
1916    {
1917        uint64_t   systemBytes  = avdInfo_getImageFileSize(avd, AVD_IMAGE_INITSYSTEM);
1918        uint64_t   defaultBytes = defaultPartitionSize;
1919
1920        if (defaultBytes == 0 || opts->partition_size)
1921            defaultBytes = defaultPartitionSize;
1922
1923        systemPartitionSize = _adjustPartitionSize("system", systemBytes, defaultBytes,
1924                                                   android_build_out != NULL);
1925    }
1926
1927    /* Check the size of the /data partition. The only interesting cases here are:
1928     * - when the USERDATA image already exists and is larger than the default
1929     * - when we're wiping data and the INITDATA is larger than the default.
1930     */
1931
1932    {
1933        const char*  dataPath     = avdInfo_getImageFile(avd, AVD_IMAGE_USERDATA);
1934        uint64_t     defaultBytes = defaultPartitionSize;
1935
1936        if (defaultBytes == 0 || opts->partition_size)
1937            defaultBytes = defaultPartitionSize;
1938
1939        if (dataPath == NULL || !path_exists(dataPath) || opts->wipe_data) {
1940            dataPath = avdInfo_getImageFile(avd, AVD_IMAGE_INITDATA);
1941        }
1942        if (dataPath == NULL || !path_exists(dataPath)) {
1943            dataPartitionSize = defaultBytes;
1944        }
1945        else {
1946            uint64_t  dataBytes;
1947            path_get_size(dataPath, &dataBytes);
1948
1949            dataPartitionSize = _adjustPartitionSize("data", dataBytes, defaultBytes,
1950                                                     android_build_out != NULL);
1951        }
1952    }
1953
1954    {
1955        const char*  filetype = "file";
1956
1957        if (avdInfo_isImageReadOnly(avd, AVD_IMAGE_INITSYSTEM))
1958            filetype = "initfile";
1959
1960        bufprint(tmp, tmpend,
1961             "system,size=0x%x,%s=%s", systemPartitionSize, filetype,
1962             avdInfo_getImageFile(avd, AVD_IMAGE_INITSYSTEM));
1963
1964        args[n++] = "-nand";
1965        args[n++] = strdup(tmp);
1966    }
1967
1968    bufprint(tmp, tmpend,
1969             "userdata,size=0x%x,file=%s",
1970             dataPartitionSize,
1971             avdInfo_getImageFile(avd, AVD_IMAGE_USERDATA));
1972
1973    args[n++] = "-nand";
1974    args[n++] = strdup(tmp);
1975
1976    if (hw->disk_cachePartition) {
1977        opts->cache = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_CACHE);
1978        cachePartitionSize = hw->disk_cachePartition_size;
1979    }
1980    else if (opts->cache) {
1981        dwarning( "Emulated hardware doesn't support a cache partition" );
1982        opts->cache    = NULL;
1983        opts->no_cache = 1;
1984    }
1985
1986    if (opts->cache) {
1987        /* use a specific cache file */
1988        sprintf(tmp, "cache,size=0x%0x,file=%s", cachePartitionSize, opts->cache);
1989        args[n++] = "-nand";
1990        args[n++] = strdup(tmp);
1991    }
1992    else if (!opts->no_cache) {
1993        /* create a temporary cache partition file */
1994        sprintf(tmp, "cache,size=0x%0x", cachePartitionSize);
1995        args[n++] = "-nand";
1996        args[n++] = strdup(tmp);
1997    }
1998
1999    if (hw->hw_sdCard != 0)
2000        opts->sdcard = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_SDCARD);
2001    else if (opts->sdcard) {
2002        dwarning( "Emulated hardware doesn't support SD Cards" );
2003        opts->sdcard = NULL;
2004    }
2005
2006    if(opts->sdcard) {
2007        uint64_t  size;
2008        if (path_get_size(opts->sdcard, &size) == 0) {
2009            /* see if we have an sdcard image.  get its size if it exists */
2010            /* due to what looks like limitations of the MMC protocol, one has
2011             * to use an SD Card image that is equal or larger than 9 MB
2012             */
2013            if (size < 9*1024*1024ULL) {
2014                fprintf(stderr, "### WARNING: SD Card files must be at least 9MB, ignoring '%s'\n", opts->sdcard);
2015            } else {
2016                args[n++] = "-hda";
2017                args[n++] = opts->sdcard;
2018                use_sdcard_img = 1;
2019            }
2020        } else {
2021            D("no SD Card image at '%s'", opts->sdcard);
2022        }
2023    }
2024
2025    if (!opts->logcat || opts->logcat[0] == 0) {
2026        opts->logcat = getenv("ANDROID_LOG_TAGS");
2027        if (opts->logcat && opts->logcat[0] == 0)
2028            opts->logcat = NULL;
2029    }
2030
2031#if 0
2032    if (opts->console) {
2033        derror( "option -console is obsolete. please use -shell instead" );
2034        exit(1);
2035    }
2036#endif
2037
2038    /* we always send the kernel messages from ttyS0 to android_kmsg */
2039    {
2040        AndroidKmsgFlags  flags = 0;
2041
2042        if (opts->show_kernel)
2043            flags |= ANDROID_KMSG_PRINT_MESSAGES;
2044
2045        android_kmsg_init( flags );
2046        args[n++] = "-serial";
2047        args[n++] = "android-kmsg";
2048        serial++;
2049    }
2050
2051    /* XXXX: TODO: implement -shell and -logcat through qemud instead */
2052    if (!opts->shell_serial) {
2053#ifdef _WIN32
2054        opts->shell_serial = "con:";
2055#else
2056        opts->shell_serial = "stdio";
2057#endif
2058    }
2059    else
2060        opts->shell = 1;
2061
2062    if (opts->shell || opts->logcat) {
2063        args[n++] = "-serial";
2064        args[n++] = opts->shell_serial;
2065        shell_serial = serial++;
2066    }
2067
2068    if (opts->old_system)
2069    {
2070        if (opts->radio) {
2071            args[n++] = "-serial";
2072            args[n++] = opts->radio;
2073            radio_serial = serial++;
2074        }
2075        else {
2076            args[n++] = "-serial";
2077            args[n++] = "android-modem";
2078            radio_serial = serial++;
2079        }
2080        if (opts->gps) {
2081            args[n++] = "-serial";
2082            args[n++] = opts->gps;
2083            gps_serial = serial++;
2084        }
2085    }
2086    else /* !opts->old_system */
2087    {
2088        args[n++] = "-serial";
2089        args[n++] = "android-qemud";
2090        qemud_serial = serial++;
2091
2092        if (opts->radio) {
2093            CharDriverState*  cs = qemu_chr_open("radio",opts->radio,NULL);
2094            if (cs == NULL) {
2095                derror( "unsupported character device specification: %s\n"
2096                        "used -help-char-devices for list of available formats\n", opts->radio );
2097                exit(1);
2098            }
2099            android_qemud_set_channel( ANDROID_QEMUD_GSM, cs);
2100        }
2101        else if ( hw->hw_gsmModem != 0 ) {
2102            if ( android_qemud_get_channel( ANDROID_QEMUD_GSM, &android_modem_cs ) < 0 ) {
2103                derror( "could not initialize qemud 'gsm' channel" );
2104                exit(1);
2105            }
2106        }
2107
2108        if (opts->gps) {
2109            CharDriverState*  cs = qemu_chr_open("gps",opts->gps,NULL);
2110            if (cs == NULL) {
2111                derror( "unsupported character device specification: %s\n"
2112                        "used -help-char-devices for list of available formats\n", opts->gps );
2113                exit(1);
2114            }
2115            android_qemud_set_channel( ANDROID_QEMUD_GPS, cs);
2116        }
2117        else if ( hw->hw_gps != 0 ) {
2118            if ( android_qemud_get_channel( "gps", &android_gps_cs ) < 0 ) {
2119                derror( "could not initialize qemud 'gps' channel" );
2120                exit(1);
2121            }
2122        }
2123    }
2124
2125    if (opts->memory) {
2126        char*  end;
2127        long   ramSize = strtol(opts->memory, &end, 0);
2128        if (ramSize < 0 || *end != 0) {
2129            derror( "-memory must be followed by a positive integer" );
2130            exit(1);
2131        }
2132        if (ramSize < 32 || ramSize > 4096) {
2133            derror( "physical memory size must be between 32 and 4096 MB" );
2134            exit(1);
2135        }
2136    }
2137    if (!opts->memory) {
2138        bufprint(tmp, tmpend, "%d", hw->hw_ramSize);
2139        opts->memory = qemu_strdup(tmp);
2140    }
2141
2142    if (opts->trace) {
2143        args[n++] = "-trace";
2144        args[n++] = opts->trace;
2145        args[n++] = "-tracing";
2146        args[n++] = "off";
2147    }
2148
2149    args[n++] = "-append";
2150
2151    if (opts->bootchart) {
2152        char*  end;
2153        int    timeout = strtol(opts->bootchart, &end, 10);
2154        if (timeout == 0)
2155            opts->bootchart = NULL;
2156        else if (timeout < 0 || timeout > 15*60) {
2157            derror( "timeout specified for -bootchart option is invalid.\n"
2158                    "please use integers between 1 and 900\n");
2159            exit(1);
2160        }
2161    }
2162
2163    /* start the 'boot-properties service, and parse the -prop
2164     * options, if any.
2165     */
2166    boot_property_init_service();
2167
2168    hwLcd_setBootProperty(get_device_dpi(opts));
2169
2170    /* Set the VM's max heap size, passed as a boot property */
2171    if (hw->vm_heapSize > 0) {
2172        char  tmp[32], *p=tmp, *end=p + sizeof(tmp);
2173        p = bufprint(p, end, "%dm", hw->vm_heapSize);
2174
2175        boot_property_add("dalvik.vm.heapsize",tmp);
2176    }
2177
2178    if (opts->prop != NULL) {
2179        ParamList*  pl = opts->prop;
2180        for ( ; pl != NULL; pl = pl->next ) {
2181            boot_property_parse_option(pl->param);
2182        }
2183    }
2184
2185    /* Setup the kernel init options
2186     */
2187    {
2188        static char  params[1024];
2189        char        *p = params, *end = p + sizeof(params);
2190
2191        p = bufprint(p, end, "qemu=1 console=ttyS0" );
2192
2193        if (opts->shell || opts->logcat) {
2194            p = bufprint(p, end, " androidboot.console=ttyS%d", shell_serial );
2195        }
2196
2197        if (opts->trace) {
2198            p = bufprint(p, end, " android.tracing=1");
2199        }
2200
2201#ifdef CONFIG_MEMCHECK
2202        if (opts->memcheck) {
2203            /* This will set ro.kernel.memcheck system property
2204             * to memcheck's tracing flags. */
2205            p = bufprint(p, end, " memcheck=%s", opts->memcheck);
2206        }
2207#endif  // CONFIG_MEMCHECK
2208
2209        if (!opts->no_jni) {
2210            p = bufprint(p, end, " android.checkjni=1");
2211        }
2212
2213        if (opts->no_boot_anim) {
2214            p = bufprint( p, end, " android.bootanim=0" );
2215        }
2216
2217        if (opts->logcat) {
2218            char*  q = bufprint(p, end, " androidboot.logcat=%s", opts->logcat);
2219
2220            if (q < end) {
2221                /* replace any space by a comma ! */
2222                {
2223                    int  nn;
2224                    for (nn = 1; p[nn] != 0; nn++)
2225                        if (p[nn] == ' ' || p[nn] == '\t')
2226                            p[nn] = ',';
2227                    p += nn;
2228                }
2229            }
2230            p = q;
2231        }
2232
2233        if (opts->old_system)
2234        {
2235            p = bufprint(p, end, " android.ril=ttyS%d", radio_serial);
2236
2237            if (opts->gps) {
2238                p = bufprint(p, end, " android.gps=ttyS%d", gps_serial);
2239            }
2240        }
2241        else
2242        {
2243            p = bufprint(p, end, " android.qemud=ttyS%d", qemud_serial);
2244        }
2245
2246        if (dns_count > 0) {
2247            p = bufprint(p, end, " android.ndns=%d", dns_count);
2248        }
2249
2250        if (opts->bootchart) {
2251            p = bufprint(p, end, " androidboot.bootchart=%s", opts->bootchart);
2252        }
2253
2254        if (p >= end) {
2255            fprintf(stderr, "### ERROR: kernel parameters too long\n");
2256            exit(1);
2257        }
2258
2259        args[n++] = strdup(params);
2260    }
2261
2262    /* physical memory */
2263    args[n++] = "-m";
2264    args[n++] = opts->memory;
2265
2266    /* on Linux, the 'dynticks' clock sometimes doesn't work
2267     * properly. this results in the UI freezing while emulation
2268     * continues, for several seconds...
2269     */
2270#ifdef __linux__
2271    args[n++] = "-clock";
2272    args[n++] = "unix";
2273#endif
2274
2275    /* Set up the interfaces for inter-emulator networking */
2276    if (opts->shared_net_id) {
2277        unsigned int shared_net_id = atoi(opts->shared_net_id);
2278        char nic[37];
2279        args[n++] = "-net";
2280        snprintf(nic, 37, "nic,vlan=1,macaddr=52:54:00:12:34:%02x", shared_net_id);
2281        args[n++] = strdup(nic);
2282        args[n++] = "-net";
2283        args[n++] = "socket,vlan=1,mcast=230.0.0.10:1234";
2284
2285        args[n++] = "-net";
2286        args[n++] = "nic,vlan=0";
2287        args[n++] = "-net";
2288        args[n++] = "user,vlan=0";
2289    }
2290
2291    while(argc-- > 0) {
2292        args[n++] = *argv++;
2293    }
2294    args[n] = 0;
2295
2296    if(VERBOSE_CHECK(init)) {
2297        int i;
2298        for(i = 0; i < n; i++) {
2299            fprintf(stdout, "emulator: argv[%02d] = \"%s\"\n", i, args[i]);
2300        }
2301    }
2302    return qemu_main(n, args);
2303}
2304
2305void  android_emulation_teardown( void )
2306{
2307    android_charmap_done();
2308}
2309