Home | History | Annotate | Download | only in android
      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 
     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 "android/utils/debug.h"
     36 #include "android/config.h"
     37 #include "android/config/config.h"
     38 
     39 #include "android/user-config.h"
     40 #include "android/utils/bufprint.h"
     41 #include "android/utils/filelock.h"
     42 #include "android/utils/lineinput.h"
     43 #include "android/utils/path.h"
     44 #include "android/utils/tempfile.h"
     45 
     46 #include "android/main-common.h"
     47 #include "android/help.h"
     48 #include "hw/goldfish_nand.h"
     49 
     50 #include "android/globals.h"
     51 
     52 #include "android/qemulator.h"
     53 #include "android/display.h"
     54 
     55 #include "android/snapshot.h"
     56 
     57 #include "android/framebuffer.h"
     58 #include "iolooper.h"
     59 
     60 AndroidRotation  android_framebuffer_rotation;
     61 
     62 #define  STRINGIFY(x)   _STRINGIFY(x)
     63 #define  _STRINGIFY(x)  #x
     64 
     65 #ifdef ANDROID_SDK_TOOLS_REVISION
     66 #  define  VERSION_STRING  STRINGIFY(ANDROID_SDK_TOOLS_REVISION)".0"
     67 #else
     68 #  define  VERSION_STRING  "standalone"
     69 #endif
     70 
     71 #define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
     72 
     73 extern int  control_console_start( int  port );  /* in control.c */
     74 
     75 extern int qemu_milli_needed;
     76 
     77 /* the default device DPI if none is specified by the skin
     78  */
     79 #define  DEFAULT_DEVICE_DPI  165
     80 
     81 #ifdef CONFIG_TRACE
     82 extern void  start_tracing(void);
     83 extern void  stop_tracing(void);
     84 #endif
     85 
     86 unsigned long   android_verbose;
     87 
     88 int qemu_main(int argc, char **argv);
     89 
     90 /* this function dumps the QEMU help */
     91 extern void  help( void );
     92 extern void  emulator_help( void );
     93 
     94 #define  VERBOSE_OPT(str,var)   { str, &var }
     95 
     96 #define  _VERBOSE_TAG(x,y)   { #x, VERBOSE_##x, y },
     97 static const struct { const char*  name; int  flag; const char*  text; }
     98 verbose_options[] = {
     99     VERBOSE_TAG_LIST
    100     { 0, 0, 0 }
    101 };
    102 
    103 void emulator_help( void )
    104 {
    105     STRALLOC_DEFINE(out);
    106     android_help_main(out);
    107     printf( "%.*s", out->n, out->s );
    108     stralloc_reset(out);
    109     exit(1);
    110 }
    111 
    112 /* TODO: Put in shared source file */
    113 static char*
    114 _getFullFilePath( const char* rootPath, const char* fileName )
    115 {
    116     if (path_is_absolute(fileName)) {
    117         return ASTRDUP(fileName);
    118     } else {
    119         char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    120 
    121         p = bufprint(temp, end, "%s/%s", rootPath, fileName);
    122         if (p >= end) {
    123             return NULL;
    124         }
    125         return ASTRDUP(temp);
    126     }
    127 }
    128 
    129 static uint64_t
    130 _adjustPartitionSize( const char*  description,
    131                       uint64_t     imageBytes,
    132                       uint64_t     defaultBytes,
    133                       int          inAndroidBuild )
    134 {
    135     char      temp[64];
    136     unsigned  imageMB;
    137     unsigned  defaultMB;
    138 
    139     if (imageBytes <= defaultBytes)
    140         return defaultBytes;
    141 
    142     imageMB   = convertBytesToMB(imageBytes);
    143     defaultMB = convertBytesToMB(defaultBytes);
    144 
    145     if (imageMB > defaultMB) {
    146         snprintf(temp, sizeof temp, "(%d MB > %d MB)", imageMB, defaultMB);
    147     } else {
    148         snprintf(temp, sizeof temp, "(%lld bytes > %lld bytes)", imageBytes, defaultBytes);
    149     }
    150 
    151     if (inAndroidBuild) {
    152         dwarning("%s partition size adjusted to match image file %s\n", description, temp);
    153     }
    154 
    155     return convertMBToBytes(imageMB);
    156 }
    157 
    158 /* Parses a -webcam option, extracting 'name', and 'dir' values.
    159  * Param:
    160  *  param - -webcam option, that should be formatted as such:
    161  *      name=<name>[,dir=<direction>]
    162  * name, name_size - buffer (and its size) where to receive <name>
    163  * dir, dir_size - buffer (and its size) where to receive <direction>
    164  */
    165 static void
    166 _parseWebcamOption(const char* param,
    167                    char* name, size_t name_size,
    168                    char* dir, size_t dir_size)
    169 {
    170     const char* dr;
    171     const char* wc_opt = param;
    172 
    173     /* Must start with 'name=' */
    174     if (strlen(wc_opt) <= 5 || memcmp(wc_opt, "name=", 5)) {
    175         derror("Invalid value for -webcam parameter: %s\n", param);
    176         exit(1);
    177     }
    178 
    179     /* Move on to 'name' value. */
    180     wc_opt += 5;
    181     dr = strchr(wc_opt, ',');
    182     if (dr == NULL) {
    183         dr = wc_opt + strlen(wc_opt);
    184     }
    185 
    186     /* Make sure that <name> fits */
    187     if ((dr - wc_opt) < name_size) {
    188         memcpy(name, wc_opt, dr - wc_opt);
    189         name[dr - wc_opt] = '\0';
    190         if (*dr == '\0') {
    191             /* Default direction value is 'front' */
    192             strcpy(dir, "front");
    193             return;
    194         } else {
    195             dr++;
    196         }
    197     } else {
    198         derror("Invalid <name> value for -webcam parameter: %s\n", param);
    199         exit(1);
    200     }
    201 
    202     /* Parse 'dir'. Must begin with 'dir=' */
    203     if (strlen(dr) <= 4 || memcmp(dr, "dir=", 4)) {
    204         derror("Invalid value for -webcam parameter: %s\n", param);
    205         exit(1);
    206     }
    207     dr += 4;
    208     /* Check the bounds, and the values */
    209     if (strlen(dr) >= dir_size || (strcmp(dr, "front") && strcmp(dr, "back"))) {
    210         derror("Invalid <direction> value for -webcam parameter: %s\n"
    211                "Valid values are: 'front', or 'back'\n", param);
    212         exit(1);
    213     }
    214     strcpy(dir, dr);
    215 }
    216 
    217 int main(int argc, char **argv)
    218 {
    219     char   tmp[MAX_PATH];
    220     char*  tmpend = tmp + sizeof(tmp);
    221     char*  args[128];
    222     int    n;
    223     char*  opt;
    224     /* The emulator always uses the first serial port for kernel messages
    225      * and the second one for qemud. So start at the third if we need one
    226      * for logcat or 'shell'
    227      */
    228     int    serial = 2;
    229     int    shell_serial = 0;
    230 
    231     int    forceArmv7 = 0;
    232 
    233     AndroidHwConfig*  hw;
    234     AvdInfo*          avd;
    235     AConfig*          skinConfig;
    236     char*             skinPath;
    237     int               inAndroidBuild;
    238     uint64_t          defaultPartitionSize = convertMBToBytes(66);
    239 
    240     AndroidOptions  opts[1];
    241     /* net.shared_net_ip boot property value. */
    242     char boot_prop_ip[64];
    243     boot_prop_ip[0] = '\0';
    244 
    245     args[0] = argv[0];
    246 
    247     if ( android_parse_options( &argc, &argv, opts ) < 0 ) {
    248         exit(1);
    249     }
    250 
    251 #ifdef _WIN32
    252     socket_init();
    253 #endif
    254 
    255     handle_ui_options(opts);
    256 
    257     while (argc-- > 1) {
    258         opt = (++argv)[0];
    259 
    260         if(!strcmp(opt, "-qemu")) {
    261             argc--;
    262             argv++;
    263             break;
    264         }
    265 
    266         if (!strcmp(opt, "-help")) {
    267             emulator_help();
    268         }
    269 
    270         if (!strncmp(opt, "-help-",6)) {
    271             STRALLOC_DEFINE(out);
    272             opt += 6;
    273 
    274             if (!strcmp(opt, "all")) {
    275                 android_help_all(out);
    276             }
    277             else if (android_help_for_option(opt, out) == 0) {
    278                 /* ok */
    279             }
    280             else if (android_help_for_topic(opt, out) == 0) {
    281                 /* ok */
    282             }
    283             if (out->n > 0) {
    284                 printf("\n%.*s", out->n, out->s);
    285                 exit(0);
    286             }
    287 
    288             fprintf(stderr, "unknown option: -help-%s\n", opt);
    289             fprintf(stderr, "please use -help for a list of valid topics\n");
    290             exit(1);
    291         }
    292 
    293         if (opt[0] == '-') {
    294             fprintf(stderr, "unknown option: %s\n", opt);
    295             fprintf(stderr, "please use -help for a list of valid options\n");
    296             exit(1);
    297         }
    298 
    299         fprintf(stderr, "invalid command-line parameter: %s.\n", opt);
    300         fprintf(stderr, "Hint: use '@foo' to launch a virtual device named 'foo'.\n");
    301         fprintf(stderr, "please use -help for more information\n");
    302         exit(1);
    303     }
    304 
    305     if (opts->version) {
    306         printf("Android emulator version %s\n"
    307                "Copyright (C) 2006-2011 The Android Open Source Project and many others.\n"
    308                "This program is a derivative of the QEMU CPU emulator (www.qemu.org).\n\n",
    309 #if defined ANDROID_BUILD_ID
    310                VERSION_STRING " (build_id " STRINGIFY(ANDROID_BUILD_ID) ")" );
    311 #else
    312                VERSION_STRING);
    313 #endif
    314         printf("  This software is licensed under the terms of the GNU General Public\n"
    315                "  License version 2, as published by the Free Software Foundation, and\n"
    316                "  may be copied, distributed, and modified under those terms.\n\n"
    317                "  This program is distributed in the hope that it will be useful,\n"
    318                "  but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    319                "  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    320                "  GNU General Public License for more details.\n\n");
    321 
    322         exit(0);
    323     }
    324 
    325     if (opts->snapshot_list) {
    326         if (opts->snapstorage == NULL) {
    327             /* Need to find the default snapstorage */
    328             avd = createAVD(opts, &inAndroidBuild);
    329             opts->snapstorage = avdInfo_getSnapStoragePath(avd);
    330             if (opts->snapstorage != NULL) {
    331                 D("autoconfig: -snapstorage %s", opts->snapstorage);
    332             } else {
    333                 if (inAndroidBuild) {
    334                     derror("You must use the -snapstorage <file> option to specify a snapshot storage file!\n");
    335                 } else {
    336                     derror("This AVD doesn't have snapshotting enabled!\n");
    337                 }
    338                 exit(1);
    339             }
    340         }
    341         snapshot_print_and_exit(opts->snapstorage);
    342     }
    343 
    344     sanitizeOptions(opts);
    345 
    346     /* Initialization of UI started with -attach-core should work differently
    347      * than initialization of UI that starts the core. In particular....
    348      */
    349 
    350     /* -charmap is incompatible with -attach-core, because particular
    351      * charmap gets set up in the running core. */
    352     if (android_charmap_setup(opts->charmap)) {
    353         exit(1);
    354     }
    355 
    356     /* Parses options and builds an appropriate AVD. */
    357     avd = android_avdInfo = createAVD(opts, &inAndroidBuild);
    358 
    359     /* get the skin from the virtual device configuration */
    360     if (opts->skindir != NULL) {
    361         if (opts->skin == NULL) {
    362             /* NOTE: Normally handled by sanitizeOptions(), just be safe */
    363             derror("The -skindir <path> option requires a -skin <name> option");
    364             exit(2);
    365         }
    366     } else {
    367         char* skinName;
    368         char* skinDir;
    369 
    370         avdInfo_getSkinInfo(avd, &skinName, &skinDir);
    371 
    372         if (opts->skin == NULL) {
    373             opts->skin = skinName;
    374             D("autoconfig: -skin %s", opts->skin);
    375         } else {
    376             AFREE(skinName);
    377         }
    378 
    379         opts->skindir = skinDir;
    380         D("autoconfig: -skindir %s", opts->skindir);
    381     }
    382 
    383     /* Read hardware configuration */
    384     hw = android_hw;
    385     if (avdInfo_initHwConfig(avd, hw) < 0) {
    386         derror("could not read hardware configuration ?");
    387         exit(1);
    388     }
    389 
    390     if (opts->keyset) {
    391         parse_keyset(opts->keyset, opts);
    392         if (!android_keyset) {
    393             fprintf(stderr,
    394                     "emulator: WARNING: could not find keyset file named '%s',"
    395                     " using defaults instead\n",
    396                     opts->keyset);
    397         }
    398     }
    399     if (!android_keyset) {
    400         parse_keyset("default", opts);
    401         if (!android_keyset) {
    402             android_keyset = skin_keyset_new_from_text( skin_keyset_get_default() );
    403             if (!android_keyset) {
    404                 fprintf(stderr, "PANIC: default keyset file is corrupted !!\n" );
    405                 fprintf(stderr, "PANIC: please update the code in android/skin/keyset.c\n" );
    406                 exit(1);
    407             }
    408             if (!opts->keyset)
    409                 write_default_keyset();
    410         }
    411     }
    412 
    413     if (opts->shared_net_id) {
    414         char*  end;
    415         long   shared_net_id = strtol(opts->shared_net_id, &end, 0);
    416         if (end == NULL || *end || shared_net_id < 1 || shared_net_id > 255) {
    417             fprintf(stderr, "option -shared-net-id must be an integer between 1 and 255\n");
    418             exit(1);
    419         }
    420         snprintf(boot_prop_ip, sizeof(boot_prop_ip),
    421                  "net.shared_net_ip=10.1.2.%ld", shared_net_id);
    422     }
    423 
    424 
    425     user_config_init();
    426     parse_skin_files(opts->skindir, opts->skin, opts, hw,
    427                      &skinConfig, &skinPath);
    428 
    429     if (!opts->netspeed && skin_network_speed) {
    430         D("skin network speed: '%s'", skin_network_speed);
    431         if (strcmp(skin_network_speed, NETWORK_SPEED_DEFAULT) != 0) {
    432             opts->netspeed = (char*)skin_network_speed;
    433         }
    434     }
    435     if (!opts->netdelay && skin_network_delay) {
    436         D("skin network delay: '%s'", skin_network_delay);
    437         if (strcmp(skin_network_delay, NETWORK_DELAY_DEFAULT) != 0) {
    438             opts->netdelay = (char*)skin_network_delay;
    439         }
    440     }
    441 
    442     if (opts->trace) {
    443         char*   tracePath = avdInfo_getTracePath(avd, opts->trace);
    444         int     ret;
    445 
    446         if (tracePath == NULL) {
    447             derror( "bad -trace parameter" );
    448             exit(1);
    449         }
    450         ret = path_mkdir_if_needed( tracePath, 0755 );
    451         if (ret < 0) {
    452             fprintf(stderr, "could not create directory '%s'\n", tmp);
    453             exit(2);
    454         }
    455         opts->trace = tracePath;
    456     }
    457 
    458     /* Update CPU architecture for HW configs created from build dir. */
    459     if (inAndroidBuild) {
    460 #if defined(TARGET_ARM)
    461         free(android_hw->hw_cpu_arch);
    462         android_hw->hw_cpu_arch = ASTRDUP("arm");
    463 #elif defined(TARGET_I386)
    464         free(android_hw->hw_cpu_arch);
    465         android_hw->hw_cpu_arch = ASTRDUP("x86");
    466 #endif
    467     }
    468 
    469     n = 1;
    470     /* generate arguments for the underlying qemu main() */
    471     {
    472         char*  kernelFile    = opts->kernel;
    473         int    kernelFileLen;
    474 
    475         if (kernelFile == NULL) {
    476             kernelFile = avdInfo_getKernelPath(avd);
    477             if (kernelFile == NULL) {
    478                 derror( "This AVD's configuration is missing a kernel file!!" );
    479                 exit(2);
    480             }
    481             D("autoconfig: -kernel %s", kernelFile);
    482         }
    483         if (!path_exists(kernelFile)) {
    484             derror( "Invalid or missing kernel image file: %s", kernelFile );
    485             exit(2);
    486         }
    487 
    488         hw->kernel_path = kernelFile;
    489 
    490         /* If the kernel image name ends in "-armv7", then change the cpu
    491          * type automatically. This is a poor man's approach to configuration
    492          * management, but should allow us to get past building ARMv7
    493          * system images with dex preopt pass without introducing too many
    494          * changes to the emulator sources.
    495          *
    496          * XXX:
    497          * A 'proper' change would require adding some sort of hardware-property
    498          * to each AVD config file, then automatically determine its value for
    499          * full Android builds (depending on some environment variable), plus
    500          * some build system changes. I prefer not to do that for now for reasons
    501          * of simplicity.
    502          */
    503          kernelFileLen = strlen(kernelFile);
    504          if (kernelFileLen > 6 && !memcmp(kernelFile + kernelFileLen - 6, "-armv7", 6)) {
    505              forceArmv7 = 1;
    506          }
    507     }
    508 
    509     if (boot_prop_ip[0]) {
    510         args[n++] = "-boot-property";
    511         args[n++] = boot_prop_ip;
    512     }
    513 
    514     if (opts->tcpdump) {
    515         args[n++] = "-tcpdump";
    516         args[n++] = opts->tcpdump;
    517     }
    518 
    519 #ifdef CONFIG_NAND_LIMITS
    520     if (opts->nand_limits) {
    521         args[n++] = "-nand-limits";
    522         args[n++] = opts->nand_limits;
    523     }
    524 #endif
    525 
    526     if (opts->timezone) {
    527         args[n++] = "-timezone";
    528         args[n++] = opts->timezone;
    529     }
    530 
    531     if (opts->netspeed) {
    532         args[n++] = "-netspeed";
    533         args[n++] = opts->netspeed;
    534     }
    535     if (opts->netdelay) {
    536         args[n++] = "-netdelay";
    537         args[n++] = opts->netdelay;
    538     }
    539     if (opts->netfast) {
    540         args[n++] = "-netfast";
    541     }
    542 
    543     if (opts->audio) {
    544         args[n++] = "-audio";
    545         args[n++] = opts->audio;
    546     }
    547 
    548     if (opts->cpu_delay) {
    549         args[n++] = "-cpu-delay";
    550         args[n++] = opts->cpu_delay;
    551     }
    552 
    553     if (opts->dns_server) {
    554         args[n++] = "-dns-server";
    555         args[n++] = opts->dns_server;
    556     }
    557 
    558     /* opts->ramdisk is never NULL (see createAVD) here */
    559     if (opts->ramdisk) {
    560         AFREE(hw->disk_ramdisk_path);
    561         hw->disk_ramdisk_path = ASTRDUP(opts->ramdisk);
    562     }
    563     else if (!hw->disk_ramdisk_path[0]) {
    564         hw->disk_ramdisk_path = avdInfo_getRamdiskPath(avd);
    565         D("autoconfig: -ramdisk %s", hw->disk_ramdisk_path);
    566     }
    567 
    568     /* -partition-size is used to specify the max size of both the system
    569      * and data partition sizes.
    570      */
    571     if (opts->partition_size) {
    572         char*  end;
    573         long   sizeMB = strtol(opts->partition_size, &end, 0);
    574         long   minSizeMB = 10;
    575         long   maxSizeMB = LONG_MAX / ONE_MB;
    576 
    577         if (sizeMB < 0 || *end != 0) {
    578             derror( "-partition-size must be followed by a positive integer" );
    579             exit(1);
    580         }
    581         if (sizeMB < minSizeMB || sizeMB > maxSizeMB) {
    582             derror( "partition-size (%d) must be between %dMB and %dMB",
    583                     sizeMB, minSizeMB, maxSizeMB );
    584             exit(1);
    585         }
    586         defaultPartitionSize = (uint64_t) sizeMB * ONE_MB;
    587     }
    588 
    589 
    590     /** SYSTEM PARTITION **/
    591 
    592     if (opts->sysdir == NULL) {
    593         if (avdInfo_inAndroidBuild(avd)) {
    594             opts->sysdir = ASTRDUP(avdInfo_getContentPath(avd));
    595             D("autoconfig: -sysdir %s", opts->sysdir);
    596         }
    597     }
    598 
    599     if (opts->sysdir != NULL) {
    600         if (!path_exists(opts->sysdir)) {
    601             derror("Directory does not exist: %s", opts->sysdir);
    602             exit(1);
    603         }
    604     }
    605 
    606     {
    607         char*  rwImage   = NULL;
    608         char*  initImage = NULL;
    609 
    610         do {
    611             if (opts->system == NULL) {
    612                 /* If -system is not used, try to find a runtime system image
    613                 * (i.e. system-qemu.img) in the content directory.
    614                 */
    615                 rwImage = avdInfo_getSystemImagePath(avd);
    616                 if (rwImage != NULL) {
    617                     break;
    618                 }
    619                 /* Otherwise, try to find the initial system image */
    620                 initImage = avdInfo_getSystemInitImagePath(avd);
    621                 if (initImage == NULL) {
    622                     derror("No initial system image for this configuration!");
    623                     exit(1);
    624                 }
    625                 break;
    626             }
    627 
    628             /* If -system <name> is used, use it to find the initial image */
    629             if (opts->sysdir != NULL && !path_exists(opts->system)) {
    630                 initImage = _getFullFilePath(opts->sysdir, opts->system);
    631             } else {
    632                 initImage = ASTRDUP(opts->system);
    633             }
    634             if (!path_exists(initImage)) {
    635                 derror("System image file doesn't exist: %s", initImage);
    636                 exit(1);
    637             }
    638 
    639         } while (0);
    640 
    641         if (rwImage != NULL) {
    642             /* Use the read/write image file directly */
    643             hw->disk_systemPartition_path     = rwImage;
    644             hw->disk_systemPartition_initPath = NULL;
    645             D("Using direct system image: %s", rwImage);
    646         } else if (initImage != NULL) {
    647             hw->disk_systemPartition_path = NULL;
    648             hw->disk_systemPartition_initPath = initImage;
    649             D("Using initial system image: %s", initImage);
    650         }
    651 
    652         /* Check the size of the system partition image.
    653         * If we have an AVD, it must be smaller than
    654         * the disk.systemPartition.size hardware property.
    655         *
    656         * Otherwise, we need to adjust the systemPartitionSize
    657         * automatically, and print a warning.
    658         *
    659         */
    660         const char* systemImage = hw->disk_systemPartition_path;
    661         uint64_t    systemBytes;
    662 
    663         if (systemImage == NULL)
    664             systemImage = hw->disk_systemPartition_initPath;
    665 
    666         if (path_get_size(systemImage, &systemBytes) < 0) {
    667             derror("Missing system image: %s", systemImage);
    668             exit(1);
    669         }
    670 
    671         hw->disk_systemPartition_size =
    672             _adjustPartitionSize("system", systemBytes, defaultPartitionSize,
    673                                  avdInfo_inAndroidBuild(avd));
    674     }
    675 
    676     /** DATA PARTITION **/
    677 
    678     if (opts->datadir) {
    679         if (!path_exists(opts->datadir)) {
    680             derror("Invalid -datadir directory: %s", opts->datadir);
    681         }
    682     }
    683 
    684     {
    685         char*  dataImage = NULL;
    686         char*  initImage = NULL;
    687 
    688         do {
    689             if (!opts->data) {
    690                 dataImage = avdInfo_getDataImagePath(avd);
    691                 if (dataImage != NULL) {
    692                     D("autoconfig: -data %s", dataImage);
    693                     break;
    694                 }
    695                 dataImage = avdInfo_getDefaultDataImagePath(avd);
    696                 if (dataImage == NULL) {
    697                     derror("No data image path for this configuration!");
    698                     exit (1);
    699                 }
    700                 opts->wipe_data = 1;
    701                 break;
    702             }
    703 
    704             if (opts->datadir) {
    705                 dataImage = _getFullFilePath(opts->datadir, opts->data);
    706             } else {
    707                 dataImage = ASTRDUP(opts->data);
    708             }
    709         } while (0);
    710 
    711         if (opts->initdata != NULL) {
    712             initImage = ASTRDUP(opts->initdata);
    713             if (!path_exists(initImage)) {
    714                 derror("Invalid initial data image path: %s", initImage);
    715                 exit(1);
    716             }
    717         } else {
    718             initImage = avdInfo_getDataInitImagePath(avd);
    719             D("autoconfig: -initdata %s", initImage);
    720         }
    721 
    722         hw->disk_dataPartition_path = dataImage;
    723         if (opts->wipe_data) {
    724             hw->disk_dataPartition_initPath = initImage;
    725         } else {
    726             hw->disk_dataPartition_initPath = NULL;
    727         }
    728 
    729         uint64_t     defaultBytes =
    730                 hw->disk_dataPartition_size == 0 ?
    731                 defaultPartitionSize :
    732                 convertMBToBytes(hw->disk_dataPartition_size);
    733         uint64_t     dataBytes;
    734         const char*  dataPath = hw->disk_dataPartition_initPath;
    735 
    736         if (dataPath == NULL)
    737             dataPath = hw->disk_dataPartition_path;
    738 
    739         path_get_size(dataPath, &dataBytes);
    740 
    741         hw->disk_dataPartition_size =
    742             _adjustPartitionSize("data", dataBytes, defaultBytes,
    743                                  avdInfo_inAndroidBuild(avd));
    744     }
    745 
    746     /** CACHE PARTITION **/
    747 
    748     if (opts->no_cache) {
    749         /* No cache partition at all */
    750         hw->disk_cachePartition = 0;
    751     }
    752     else if (!hw->disk_cachePartition) {
    753         if (opts->cache) {
    754             dwarning( "Emulated hardware doesn't support a cache partition. -cache option ignored!" );
    755             opts->cache = NULL;
    756         }
    757     }
    758     else
    759     {
    760         if (!opts->cache) {
    761             /* Find the current cache partition file */
    762             opts->cache = avdInfo_getCachePath(avd);
    763             if (opts->cache == NULL) {
    764                 /* The file does not exists, we will force its creation
    765                  * if we are not in the Android build system. Otherwise,
    766                  * a temporary file will be used.
    767                  */
    768                 if (!avdInfo_inAndroidBuild(avd)) {
    769                     opts->cache = avdInfo_getDefaultCachePath(avd);
    770                 }
    771             }
    772             if (opts->cache) {
    773                 D("autoconfig: -cache %s", opts->cache);
    774             }
    775         }
    776 
    777         if (opts->cache) {
    778             hw->disk_cachePartition_path = ASTRDUP(opts->cache);
    779         }
    780     }
    781 
    782     /** SD CARD PARTITION */
    783 
    784     if (!hw->hw_sdCard) {
    785         /* No SD Card emulation, so -sdcard will be ignored */
    786         if (opts->sdcard) {
    787             dwarning( "Emulated hardware doesn't support SD Cards. -sdcard option ignored." );
    788             opts->sdcard = NULL;
    789         }
    790     } else {
    791         /* Auto-configure -sdcard if it is not available */
    792         if (!opts->sdcard) {
    793             do {
    794                 /* If -datadir <path> is used, look for a sdcard.img file here */
    795                 if (opts->datadir) {
    796                     bufprint(tmp, tmpend, "%s/%s", opts->datadir, "system.img");
    797                     if (path_exists(tmp)) {
    798                         opts->sdcard = strdup(tmp);
    799                         break;
    800                     }
    801                 }
    802 
    803                 /* Otherwise, look at the AVD's content */
    804                 opts->sdcard = avdInfo_getSdCardPath(avd);
    805                 if (opts->sdcard != NULL) {
    806                     break;
    807                 }
    808 
    809                 /* Nothing */
    810             } while (0);
    811 
    812             if (opts->sdcard) {
    813                 D("autoconfig: -sdcard %s", opts->sdcard);
    814             }
    815         }
    816     }
    817 
    818     if(opts->sdcard) {
    819         uint64_t  size;
    820         if (path_get_size(opts->sdcard, &size) == 0) {
    821             /* see if we have an sdcard image.  get its size if it exists */
    822             /* due to what looks like limitations of the MMC protocol, one has
    823              * to use an SD Card image that is equal or larger than 9 MB
    824              */
    825             if (size < 9*1024*1024ULL) {
    826                 fprintf(stderr, "### WARNING: SD Card files must be at least 9MB, ignoring '%s'\n", opts->sdcard);
    827             } else {
    828                 hw->hw_sdCard_path = ASTRDUP(opts->sdcard);
    829             }
    830         } else {
    831             dwarning("no SD Card image at '%s'", opts->sdcard);
    832         }
    833     }
    834 
    835 
    836     /** SNAPSHOT STORAGE HANDLING */
    837 
    838     /* Determine snapstorage path. -no-snapstorage disables all snapshotting
    839      * support. This means you can't resume a snapshot at load, save it at
    840      * exit, or even load/save them dynamically at runtime with the console.
    841      */
    842     if (opts->no_snapstorage) {
    843 
    844         if (opts->snapshot) {
    845             dwarning("ignoring -snapshot option due to the use of -no-snapstorage");
    846             opts->snapshot = NULL;
    847         }
    848 
    849         if (opts->snapstorage) {
    850             dwarning("ignoring -snapstorage option due to the use of -no-snapstorage");
    851             opts->snapstorage = NULL;
    852         }
    853     }
    854     else
    855     {
    856         if (!opts->snapstorage) {
    857             opts->snapstorage = avdInfo_getSnapStoragePath(avd);
    858             if (opts->snapstorage != NULL) {
    859                 D("autoconfig: -snapstorage %s", opts->snapstorage);
    860             }
    861         }
    862 
    863         if (opts->snapstorage && !path_exists(opts->snapstorage)) {
    864             D("no image at '%s', state snapshots disabled", opts->snapstorage);
    865             opts->snapstorage = NULL;
    866         }
    867     }
    868 
    869     /* If we have a valid snapshot storage path */
    870 
    871     if (opts->snapstorage) {
    872 
    873         hw->disk_snapStorage_path = ASTRDUP(opts->snapstorage);
    874 
    875         /* -no-snapshot is equivalent to using both -no-snapshot-load
    876         * and -no-snapshot-save. You can still load/save snapshots dynamically
    877         * from the console though.
    878         */
    879         if (opts->no_snapshot) {
    880 
    881             opts->no_snapshot_load = 1;
    882             opts->no_snapshot_save = 1;
    883 
    884             if (opts->snapshot) {
    885                 dwarning("ignoring -snapshot option due to the use of -no-snapshot.");
    886             }
    887         }
    888 
    889         if (!opts->no_snapshot_load || !opts->no_snapshot_save) {
    890             if (opts->snapshot == NULL) {
    891                 opts->snapshot = "default-boot";
    892                 D("autoconfig: -snapshot %s", opts->snapshot);
    893             }
    894         }
    895 
    896         /* We still use QEMU command-line options for the following since
    897         * they can change from one invokation to the next and don't really
    898         * correspond to the hardware configuration itself.
    899         */
    900         if (!opts->no_snapshot_load) {
    901             args[n++] = "-loadvm";
    902             args[n++] = ASTRDUP(opts->snapshot);
    903         }
    904 
    905         if (!opts->no_snapshot_save) {
    906             args[n++] = "-savevm-on-exit";
    907             args[n++] = ASTRDUP(opts->snapshot);
    908         }
    909 
    910         if (opts->no_snapshot_update_time) {
    911             args[n++] = "-snapshot-no-time-update";
    912         }
    913     }
    914 
    915     if (!opts->logcat || opts->logcat[0] == 0) {
    916         opts->logcat = getenv("ANDROID_LOG_TAGS");
    917         if (opts->logcat && opts->logcat[0] == 0)
    918             opts->logcat = NULL;
    919     }
    920 
    921     /* we always send the kernel messages from ttyS0 to android_kmsg */
    922     if (opts->show_kernel) {
    923         args[n++] = "-show-kernel";
    924     }
    925 
    926     /* XXXX: TODO: implement -shell and -logcat through qemud instead */
    927     if (!opts->shell_serial) {
    928 #ifdef _WIN32
    929         opts->shell_serial = "con:";
    930 #else
    931         opts->shell_serial = "stdio";
    932 #endif
    933     }
    934     else
    935         opts->shell = 1;
    936 
    937     if (opts->shell || opts->logcat) {
    938         args[n++] = "-serial";
    939         args[n++] = opts->shell_serial;
    940         shell_serial = serial++;
    941     }
    942 
    943     if (opts->radio) {
    944         args[n++] = "-radio";
    945         args[n++] = opts->radio;
    946     }
    947 
    948     if (opts->gps) {
    949         args[n++] = "-gps";
    950         args[n++] = opts->gps;
    951     }
    952 
    953     if (opts->memory) {
    954         char*  end;
    955         long   ramSize = strtol(opts->memory, &end, 0);
    956         if (ramSize < 0 || *end != 0) {
    957             derror( "-memory must be followed by a positive integer" );
    958             exit(1);
    959         }
    960         if (ramSize < 32 || ramSize > 4096) {
    961             derror( "physical memory size must be between 32 and 4096 MB" );
    962             exit(1);
    963         }
    964         hw->hw_ramSize = ramSize;
    965     }
    966     if (!opts->memory) {
    967         int ramSize = hw->hw_ramSize;
    968         if (ramSize <= 0) {
    969             /* Compute the default RAM size based on the size of screen.
    970              * This is only used when the skin doesn't provide the ram
    971              * size through its hardware.ini (i.e. legacy ones) or when
    972              * in the full Android build system.
    973              */
    974             int64_t pixels  = hw->hw_lcd_width * hw->hw_lcd_height;
    975             /* The following thresholds are a bit liberal, but we
    976              * essentially want to ensure the following mappings:
    977              *
    978              *   320x480 -> 96
    979              *   800x600 -> 128
    980              *  1024x768 -> 256
    981              *
    982              * These are just simple heuristics, they could change in
    983              * the future.
    984              */
    985             if (pixels <= 250000)
    986                 ramSize = 96;
    987             else if (pixels <= 500000)
    988                 ramSize = 128;
    989             else
    990                 ramSize = 256;
    991         }
    992         hw->hw_ramSize = ramSize;
    993     }
    994 
    995     D("Physical RAM size: %dMB\n", hw->hw_ramSize);
    996 
    997     if (hw->vm_heapSize == 0) {
    998         /* Compute the default heap size based on the RAM size.
    999          * Essentially, we want to ensure the following liberal mappings:
   1000          *
   1001          *   96MB RAM -> 16MB heap
   1002          *  128MB RAM -> 24MB heap
   1003          *  256MB RAM -> 48MB heap
   1004          */
   1005         int  ramSize = hw->hw_ramSize;
   1006         int  heapSize;
   1007 
   1008         if (ramSize < 100)
   1009             heapSize = 16;
   1010         else if (ramSize < 192)
   1011             heapSize = 24;
   1012         else
   1013             heapSize = 48;
   1014 
   1015         hw->vm_heapSize = heapSize;
   1016     }
   1017 
   1018     if (opts->trace) {
   1019         args[n++] = "-trace";
   1020         args[n++] = opts->trace;
   1021         args[n++] = "-tracing";
   1022         args[n++] = "off";
   1023     }
   1024 
   1025     /* Pass boot properties to the core. */
   1026     if (opts->prop != NULL) {
   1027         ParamList*  pl = opts->prop;
   1028         for ( ; pl != NULL; pl = pl->next ) {
   1029             args[n++] = "-boot-property";
   1030             args[n++] = pl->param;
   1031         }
   1032     }
   1033 
   1034     /* Setup the kernel init options
   1035      */
   1036     {
   1037         static char  params[1024];
   1038         char        *p = params, *end = p + sizeof(params);
   1039 
   1040         /* Don't worry about having a leading space here, this is handled
   1041          * by the core later. */
   1042 
   1043 #ifdef TARGET_I386
   1044         p = bufprint(p, end, " androidboot.hardware=goldfish");
   1045         p = bufprint(p, end, " clocksource=pit");
   1046 #endif
   1047 
   1048         if (opts->shell || opts->logcat) {
   1049             p = bufprint(p, end, " androidboot.console=ttyS%d", shell_serial );
   1050         }
   1051 
   1052         if (opts->trace) {
   1053             p = bufprint(p, end, " android.tracing=1");
   1054         }
   1055 
   1056         if (!opts->no_jni) {
   1057             p = bufprint(p, end, " android.checkjni=1");
   1058         }
   1059 
   1060         if (opts->no_boot_anim) {
   1061             p = bufprint( p, end, " android.bootanim=0" );
   1062         }
   1063 
   1064         if (opts->logcat) {
   1065             char*  q = bufprint(p, end, " androidboot.logcat=%s", opts->logcat);
   1066 
   1067             if (q < end) {
   1068                 /* replace any space by a comma ! */
   1069                 {
   1070                     int  nn;
   1071                     for (nn = 1; p[nn] != 0; nn++)
   1072                         if (p[nn] == ' ' || p[nn] == '\t')
   1073                             p[nn] = ',';
   1074                     p += nn;
   1075                 }
   1076             }
   1077             p = q;
   1078         }
   1079 
   1080         if (opts->bootchart) {
   1081             p = bufprint(p, end, " androidboot.bootchart=%s", opts->bootchart);
   1082         }
   1083 
   1084         if (p >= end) {
   1085             fprintf(stderr, "### ERROR: kernel parameters too long\n");
   1086             exit(1);
   1087         }
   1088 
   1089         hw->kernel_parameters = strdup(params);
   1090     }
   1091 
   1092     if (opts->ports) {
   1093         args[n++] = "-android-ports";
   1094         args[n++] = opts->ports;
   1095     }
   1096 
   1097     if (opts->port) {
   1098         args[n++] = "-android-port";
   1099         args[n++] = opts->port;
   1100     }
   1101 
   1102     if (opts->report_console) {
   1103         args[n++] = "-android-report-console";
   1104         args[n++] = opts->report_console;
   1105     }
   1106 
   1107     if (opts->http_proxy) {
   1108         args[n++] = "-http-proxy";
   1109         args[n++] = opts->http_proxy;
   1110     }
   1111 
   1112     if (!opts->charmap) {
   1113         /* Try to find a valid charmap name */
   1114         char* charmap = avdInfo_getCharmapFile(avd, hw->hw_keyboard_charmap);
   1115         if (charmap != NULL) {
   1116             D("autoconfig: -charmap %s", charmap);
   1117             opts->charmap = charmap;
   1118         }
   1119     }
   1120 
   1121     if (opts->charmap) {
   1122         char charmap_name[AKEYCHARMAP_NAME_SIZE];
   1123 
   1124         if (!path_exists(opts->charmap)) {
   1125             derror("Charmap file does not exist: %s", opts->charmap);
   1126             exit(1);
   1127         }
   1128         /* We need to store the charmap name in the hardware configuration.
   1129          * However, the charmap file itself is only used by the UI component
   1130          * and doesn't need to be set to the emulation engine.
   1131          */
   1132         kcm_extract_charmap_name(opts->charmap, charmap_name,
   1133                                  sizeof(charmap_name));
   1134         AFREE(hw->hw_keyboard_charmap);
   1135         hw->hw_keyboard_charmap = ASTRDUP(charmap_name);
   1136     }
   1137 
   1138     if (opts->memcheck) {
   1139         args[n++] = "-android-memcheck";
   1140         args[n++] = opts->memcheck;
   1141     }
   1142 
   1143     if (opts->gpu) {
   1144         const char* gpu = opts->gpu;
   1145         if (!strcmp(gpu,"on") || !strcmp(gpu,"enable")) {
   1146             hw->hw_gpu_enabled = 1;
   1147         } else if (!strcmp(gpu,"off") || !strcmp(gpu,"disable")) {
   1148             hw->hw_gpu_enabled = 0;
   1149         } else if (!strcmp(gpu,"auto")) {
   1150             /* Nothing to do */
   1151         } else {
   1152             derror("Invalid value for -gpu <mode> parameter: %s\n", gpu);
   1153             derror("Valid values are: on, off or auto\n");
   1154             exit(1);
   1155         }
   1156     }
   1157 
   1158     if (opts->fake_camera) {
   1159         if (!strcmp(opts->fake_camera, "back") ||
   1160             !strcmp(opts->fake_camera, "front") ||
   1161             !strcmp(opts->fake_camera, "off")) {
   1162             hw->hw_fakeCamera = ASTRDUP(opts->fake_camera);
   1163         } else {
   1164             derror("Invalid value for -fake-camera <mode> parameter: %s\n",
   1165                    opts->fake_camera);
   1166             derror("Valid values are: back, front, or off\n");
   1167             exit(1);
   1168         }
   1169     }
   1170 
   1171     if (opts->webcam != NULL) {
   1172         ParamList*  pl = opts->webcam;
   1173         int webcam_num = 0;
   1174         for ( ; pl != NULL; pl = pl->next ) {
   1175             char webcam_name[64];
   1176             char webcam_dir[16];
   1177             if (!strcmp(pl->param, "off")) {
   1178                 /* If 'off' is passed, there must be no other -webcam options. */
   1179                 if (webcam_num || pl->next != NULL) {
   1180                     derror("'-webcam off' cannot be combined with other -webcam otions\n");
   1181                     exit(1);
   1182                 }
   1183                 break;
   1184             }
   1185             if (!strcmp(pl->param, "list")) {
   1186                 /* If 'list' is passed, there must be no other -webcam options. */
   1187                 if (webcam_num || pl->next != NULL) {
   1188                     derror("'-webcam list' cannot be combined with other -webcam otions\n");
   1189                     exit(1);
   1190                 }
   1191                 args[n++] = "-list-webcam";
   1192                 break;
   1193             }
   1194             /* Extract name, and direction */
   1195             _parseWebcamOption(pl->param, webcam_name, sizeof(webcam_name),
   1196                                webcam_dir, sizeof(webcam_dir));
   1197             /* Save them to appropriate field in hw.ini */
   1198             switch (webcam_num) {
   1199                 case 0:
   1200                     hw->hw_webcam_0_name        = ASTRDUP(webcam_name);
   1201                     hw->hw_webcam_0_direction   = ASTRDUP(webcam_dir);
   1202                     break;
   1203                 case 1:
   1204                     hw->hw_webcam_1_name        = ASTRDUP(webcam_name);
   1205                     hw->hw_webcam_1_direction   = ASTRDUP(webcam_dir);
   1206                     break;
   1207                 case 2:
   1208                     hw->hw_webcam_2_name        = ASTRDUP(webcam_name);
   1209                     hw->hw_webcam_2_direction   = ASTRDUP(webcam_dir);
   1210                     break;
   1211                 case 3:
   1212                     hw->hw_webcam_3_name        = ASTRDUP(webcam_name);
   1213                     hw->hw_webcam_3_direction   = ASTRDUP(webcam_dir);
   1214                     break;
   1215                 case 4:
   1216                     hw->hw_webcam_4_name        = ASTRDUP(webcam_name);
   1217                     hw->hw_webcam_4_direction   = ASTRDUP(webcam_dir);
   1218                     break;
   1219                 case 5:
   1220                     hw->hw_webcam_5_name        = ASTRDUP(webcam_name);
   1221                     hw->hw_webcam_5_direction   = ASTRDUP(webcam_dir);
   1222                     break;
   1223                 default:
   1224                     derror("Too many -webcam options. Maximum number of -webcam options is 6\n");
   1225                     exit(1);
   1226             }
   1227             webcam_num++;
   1228         }
   1229         hw->hw_webcam_count = webcam_num;
   1230     }
   1231 
   1232     /* physical memory is now in hw->hw_ramSize */
   1233 
   1234     hw->avd_name = ASTRDUP(avdInfo_getName(avd));
   1235 
   1236     /* Set up the interfaces for inter-emulator networking */
   1237     if (opts->shared_net_id) {
   1238         unsigned int shared_net_id = atoi(opts->shared_net_id);
   1239         char nic[37];
   1240 
   1241         args[n++] = "-net";
   1242         args[n++] = "nic,vlan=0";
   1243         args[n++] = "-net";
   1244         args[n++] = "user,vlan=0";
   1245 
   1246         args[n++] = "-net";
   1247         snprintf(nic, sizeof nic, "nic,vlan=1,macaddr=52:54:00:12:34:%02x", shared_net_id);
   1248         args[n++] = strdup(nic);
   1249         args[n++] = "-net";
   1250         args[n++] = "socket,vlan=1,mcast=230.0.0.10:1234";
   1251     }
   1252 
   1253     while(argc-- > 0) {
   1254         args[n++] = *argv++;
   1255     }
   1256     args[n] = 0;
   1257 
   1258     /* If the target ABI is armeabi-v7a, we can auto-detect the cpu model
   1259      * as a cortex-a8, instead of the default (arm926) which only emulates
   1260      * an ARMv5TE CPU.
   1261      */
   1262     if (!forceArmv7 && hw->hw_cpu_model[0] == '\0')
   1263     {
   1264         char* abi = avdInfo_getTargetAbi(avd);
   1265         if (abi != NULL) {
   1266             if (!strcmp(abi, "armeabi-v7a")) {
   1267                 forceArmv7 = 1;
   1268             }
   1269             AFREE(abi);
   1270         }
   1271     }
   1272 
   1273     if (forceArmv7 != 0) {
   1274         AFREE(hw->hw_cpu_model);
   1275         hw->hw_cpu_model = ASTRDUP("cortex-a8");
   1276         D("Auto-config: -qemu -cpu %s", hw->hw_cpu_model);
   1277     }
   1278 
   1279     /* Generate a hardware-qemu.ini for this AVD. The real hardware
   1280      * configuration is ususally stored in several files, e.g. the AVD's
   1281      * config.ini plus the skin-specific hardware.ini.
   1282      *
   1283      * The new file will group all definitions and will be used to
   1284      * launch the core with the -android-hw <file> option.
   1285      */
   1286     {
   1287         const char* coreHwIniPath = avdInfo_getCoreHwIniPath(avd);
   1288         IniFile*    hwIni         = iniFile_newFromMemory("", NULL);
   1289         androidHwConfig_write(hw, hwIni);
   1290 
   1291         if (filelock_create(coreHwIniPath) == NULL) {
   1292             /* The AVD is already in use, we still support this as an
   1293              * experimental feature. Use a temporary hardware-qemu.ini
   1294              * file though to avoid overwriting the existing one. */
   1295              TempFile*  tempIni = tempfile_create();
   1296              coreHwIniPath = tempfile_path(tempIni);
   1297         }
   1298 
   1299         if (iniFile_saveToFile(hwIni, coreHwIniPath) < 0) {
   1300             derror("Could not write hardware.ini to %s: %s", coreHwIniPath, strerror(errno));
   1301             exit(2);
   1302         }
   1303         args[n++] = "-android-hw";
   1304         args[n++] = strdup(coreHwIniPath);
   1305 
   1306         /* In verbose mode, dump the file's content */
   1307         if (VERBOSE_CHECK(init)) {
   1308             FILE* file = fopen(coreHwIniPath, "rt");
   1309             if (file == NULL) {
   1310                 derror("Could not open hardware configuration file: %s\n",
   1311                        coreHwIniPath);
   1312             } else {
   1313                 LineInput* input = lineInput_newFromStdFile(file);
   1314                 const char* line;
   1315                 printf("Content of hardware configuration file:\n");
   1316                 while ((line = lineInput_getLine(input)) !=  NULL) {
   1317                     printf("  %s\n", line);
   1318                 }
   1319                 printf(".\n");
   1320                 lineInput_free(input);
   1321                 fclose(file);
   1322             }
   1323         }
   1324     }
   1325 
   1326     if(VERBOSE_CHECK(init)) {
   1327         int i;
   1328         printf("QEMU options list:\n");
   1329         for(i = 0; i < n; i++) {
   1330             printf("emulator: argv[%02d] = \"%s\"\n", i, args[i]);
   1331         }
   1332         /* Dump final command-line option to make debugging the core easier */
   1333         printf("Concatenated QEMU options:\n");
   1334         for (i = 0; i < n; i++) {
   1335             /* To make it easier to copy-paste the output to a command-line,
   1336              * quote anything that contains spaces.
   1337              */
   1338             if (strchr(args[i], ' ') != NULL) {
   1339                 printf(" '%s'", args[i]);
   1340             } else {
   1341                 printf(" %s", args[i]);
   1342             }
   1343         }
   1344         printf("\n");
   1345     }
   1346 
   1347     /* Setup SDL UI just before calling the code */
   1348     init_sdl_ui(skinConfig, skinPath, opts);
   1349 
   1350     if (attach_ui_to_core(opts) < 0) {
   1351         derror("Can't attach to core!");
   1352         exit(1);
   1353     }
   1354 
   1355     return qemu_main(n, args);
   1356 }
   1357