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