android: main.cpp: Implement full main() emulator wrapper.
Change-Id: Ie99ac7a83cefcc2b773dec40a5048d3359eb9b23
diff --git a/android-qemu2-glue/main.cpp b/android-qemu2-glue/main.cpp
index bf116cd..91fbb09 100644
--- a/android-qemu2-glue/main.cpp
+++ b/android-qemu2-glue/main.cpp
@@ -1,12 +1,929 @@
+// Copyright 2015 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/base/containers/StringVector.h"
+#include "android/base/files/PathUtils.h"
+#include "android/base/Log.h"
+#include "android/base/memory/ScopedPtr.h"
+#include "android/base/StringFormat.h"
+#include "android/base/system/System.h"
+
+#include "android/android.h"
+#include "android/avd/hw-config.h"
+#include "android/cmdline-option.h"
+#include "android/constants.h"
+#include "android/crashreport/crash-handler.h"
+#include "android/error-messages.h"
+#include "android/filesystems/ext4_resize.h"
+#include "android/filesystems/ext4_utils.h"
+#include "android/globals.h"
+#include "android/help.h"
+#include "android/kernel/kernel_utils.h"
+#include "android/main-common.h"
+#include "android/main-common-ui.h"
+#include "android/main-kernel-parameters.h"
+#include "android/opengl/emugl_config.h"
+#include "android/process_setup.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+#include "android/utils/path.h"
+#include "android/utils/lineinput.h"
+#include "android/utils/property_file.h"
+#include "android/utils/filelock.h"
+#include "android/utils/stralloc.h"
+#include "android/utils/string.h"
+#include "android/utils/tempfile.h"
+#include "android/utils/win32_cmdline_quote.h"
+
+#include "android/skin/winsys.h"
+
+#include "config-target.h"
+
+extern "C" {
+#include "android/skin/charmap.h"
+}
+
+#include "android/ui-emu-agent.h"
+#include "android-qemu2-glue/emulation/serial_line.h"
+#include "android-qemu2-glue/qemu-control-impl.h"
+
+#ifdef TARGET_AARCH64
+#define TARGET_ARM64
+#endif
+#ifdef TARGET_I386
+#define TARGET_X86
+#endif
+
+#include <algorithm>
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "android/version.h"
+#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
+
+int android_base_port;
+int android_serial_number_port;
+
+extern bool android_op_wipe_data;
+extern bool android_op_writable_system;
+
+using namespace android::base;
+using android::base::System;
+
+namespace {
+
+enum ImageType {
+ IMAGE_TYPE_SYSTEM = 0,
+ IMAGE_TYPE_CACHE,
+ IMAGE_TYPE_USER_DATA,
+ IMAGE_TYPE_SD_CARD,
+};
+
+const int kMaxPartitions = 4;
+const int kMaxTargetQemuParams = 16;
+
+/*
+ * A structure used to model information about a given target CPU architecture.
+ * |androidArch| is the architecture name, following Android conventions.
+ * |qemuArch| is the same name, following QEMU conventions, used to locate
+ * the final qemu-system-<qemuArch> binary.
+ * |qemuCpu| is the QEMU -cpu parameter value.
+ * |ttyPrefix| is the prefix to use for TTY devices.
+ * |storageDeviceType| is the QEMU storage device type.
+ * |networkDeviceType| is the QEMU network device type.
+ * |imagePartitionTypes| defines the order of how the image partitions are
+ * listed in the command line, because the command line order determines which
+ * mount point the partition is attached to. For x86, the first partition
+ * listed in command line is mounted first, i.e. to /dev/block/vda,
+ * the next one to /dev/block/vdb, etc. However, for arm/mips, it's reversed;
+ * the last one is mounted to /dev/block/vda. the 2nd last to /dev/block/vdb.
+ * So far, we have 4(kMaxPartitions) types defined for system, cache, userdata
+ * and sdcard images.
+ * |qemuExtraArgs| are the qemu parameters specific to the target platform.
+ * this is a NULL-terminated list of string pointers of at most
+ * kMaxTargetQemuParams(16).
+ */
+struct TargetInfo {
+ const char* androidArch;
+ const char* qemuArch;
+ const char* qemuCpu;
+ const char* ttyPrefix;
+ const char* storageDeviceType;
+ const char* networkDeviceType;
+ const ImageType imagePartitionTypes[kMaxPartitions];
+ const char* qemuExtraArgs[kMaxTargetQemuParams];
+};
+
+// The current target architecture information!
+const TargetInfo kTarget = {
+#ifdef TARGET_ARM64
+ "arm64",
+ "aarch64",
+ "cortex-a57",
+ "ttyAMA",
+ "virtio-blk-device",
+ "virtio-net-device",
+ {IMAGE_TYPE_SD_CARD, IMAGE_TYPE_USER_DATA, IMAGE_TYPE_CACHE, IMAGE_TYPE_SYSTEM},
+ {NULL},
+#elif defined(TARGET_ARM)
+ "arm",
+ "arm",
+ "cortex-a15",
+ "ttyAMA",
+ "virtio-blk-device",
+ "virtio-net-device",
+ {IMAGE_TYPE_SD_CARD, IMAGE_TYPE_USER_DATA, IMAGE_TYPE_CACHE, IMAGE_TYPE_SYSTEM},
+ {NULL},
+#elif defined(TARGET_MIPS64)
+ "mips64",
+ "mips64el",
+ "MIPS64R6-generic",
+ "ttyGF",
+ "virtio-blk-device",
+ "virtio-net-device",
+ {IMAGE_TYPE_SD_CARD, IMAGE_TYPE_USER_DATA, IMAGE_TYPE_CACHE, IMAGE_TYPE_SYSTEM},
+ {NULL},
+#elif defined(TARGET_MIPS)
+ "mips",
+ "mipsel",
+ "74Kf",
+ "ttyGF",
+ "virtio-blk-device",
+ "virtio-net-device",
+ {IMAGE_TYPE_SD_CARD, IMAGE_TYPE_USER_DATA, IMAGE_TYPE_CACHE, IMAGE_TYPE_SYSTEM},
+ {NULL},
+#elif defined(TARGET_X86_64)
+ "x86_64",
+ "x86_64",
+ "android64",
+ "ttyS",
+ "virtio-blk-pci",
+ "virtio-net-pci",
+ {IMAGE_TYPE_SYSTEM, IMAGE_TYPE_CACHE, IMAGE_TYPE_USER_DATA, IMAGE_TYPE_SD_CARD},
+ {"-vga", "none", NULL},
+#elif defined(TARGET_I386) // Both i386 and x86_64 targets define this macro
+ "x86",
+ "i386",
+ "android32",
+ "ttyS",
+ "virtio-blk-pci",
+ "virtio-net-pci",
+ {IMAGE_TYPE_SYSTEM, IMAGE_TYPE_CACHE, IMAGE_TYPE_USER_DATA, IMAGE_TYPE_SD_CARD},
+ {"-vga", "none", NULL},
+#else
+ #error No target platform is defined
+#endif
+};
+
+static std::string getNthParentDir(const char* path, size_t n) {
+ StringVector dir = PathUtils::decompose(path);
+ PathUtils::simplifyComponents(&dir);
+ if (dir.size() < n + 1U) {
+ return std::string("");
+ }
+ dir.resize(dir.size() - n);
+ return PathUtils::recompose(dir);
+}
+
+/* generate parameters for each partition by type.
+ * Param:
+ * args - array to hold parameters for qemu
+ * argsPosition - current index in the parameter array
+ * driveIndex - a sequence number for the drive parameter
+ * hw - the hardware configuration that conatains image info.
+ * type - what type of partition parameter to generate
+*/
+
+static void makePartitionCmd(const char** args, int* argsPosition, int* driveIndex,
+ AndroidHwConfig* hw, ImageType type, bool writable,
+ int apiLevel) {
+ int n = *argsPosition;
+ int idx = *driveIndex;
+
+#if defined(TARGET_X86_64) || defined(TARGET_I386)
+ /* for x86, 'if=none' is necessary for virtio blk*/
+ std::string driveParam("if=none,");
+#else
+ std::string driveParam;
+#endif
+ std::string deviceParam;
+
+ switch (type) {
+ case IMAGE_TYPE_SYSTEM:
+ driveParam += StringFormat("index=%d,id=system,file=%s,format=raw",
+ idx++,
+ hw->disk_systemPartition_initPath);
+ // API 15 and under images need a read+write
+ // system image.
+ if (apiLevel > 15) {
+ // API > 15 uses read-only system partition.
+ // You can override this explicitly
+ // by passing -writable-system to emulator.
+ if (!writable)
+ driveParam += ",read-only";
+ }
+ deviceParam = StringFormat("%s,drive=system",
+ kTarget.storageDeviceType);
+ break;
+ case IMAGE_TYPE_CACHE:
+ driveParam += StringFormat("index=%d,id=cache,file=%s,format=raw",
+ idx++,
+ hw->disk_cachePartition_path);
+ deviceParam = StringFormat("%s,drive=cache",
+ kTarget.storageDeviceType);
+ break;
+ case IMAGE_TYPE_USER_DATA:
+ driveParam += StringFormat("index=%d,id=userdata,file=%s,format=raw",
+ idx++,
+ hw->disk_dataPartition_path);
+ deviceParam = StringFormat("%s,drive=userdata",
+ kTarget.storageDeviceType);
+ break;
+ case IMAGE_TYPE_SD_CARD:
+ if (hw->hw_sdCard_path != NULL && strcmp(hw->hw_sdCard_path, "")) {
+ driveParam += StringFormat("index=%d,id=sdcard,file=%s,format=raw",
+ idx++, hw->hw_sdCard_path);
+ deviceParam = StringFormat("%s,drive=sdcard",
+ kTarget.storageDeviceType);
+ } else {
+ /* no sdcard is defined */
+ return;
+ }
+ break;
+ default:
+ dwarning("Unknown Image type %d\n", type);
+ return;
+ }
+ args[n++] = "-drive";
+ args[n++] = ASTRDUP(driveParam.c_str());
+ args[n++] = "-device";
+ args[n++] = ASTRDUP(deviceParam.c_str());
+ /* update the index */
+ *argsPosition = n;
+ *driveIndex = idx;
+}
+
+
+} // namespace
+
+
+extern "C" int run_qemu_main(int argc, const char **argv);
+
+static void enter_qemu_main_loop(int argc, char **argv) {
+#ifndef _WIN32
+ sigset_t set;
+ sigemptyset(&set);
+ pthread_sigmask(SIG_SETMASK, &set, NULL);
+#endif
+
+ D("Starting QEMU main loop");
+ run_qemu_main(argc, (const char**)argv);
+ D("Done with QEMU main loop");
+
+ if (android_init_error_occurred()) {
+ skin_winsys_error_dialog(android_init_error_get_message(), "Error");
+ }
+}
+
#if defined(_WIN32)
// On Windows, link against qtmain.lib which provides a WinMain()
// implementation, that later calls qMain().
#define main qt_main
#endif
-// Implemented by vl.c
-extern "C" int qemu_main(int argc, char** argv);
-
extern "C" int main(int argc, char **argv) {
- return qemu_main(argc, argv);
+ process_early_setup(argc, argv);
+
+ if (argc < 1) {
+ fprintf(stderr, "Invalid invocation (no program path)\n");
+ return 1;
+ }
+
+ /* The emulator always uses the first serial port for kernel messages
+ * and the second one for qemud. So start at the third if we need one
+ * for logcat or 'shell'
+ */
+ const char* args[128];
+ args[0] = argv[0];
+ int n = 1; // next parameter index
+
+ AndroidHwConfig* hw = android_hw;
+ AvdInfo* avd;
+ AndroidOptions opts[1];
+ int exitStatus = 0;
+
+ if (!emulator_parseCommonCommandLineOptions(&argc,
+ &argv,
+ kTarget.androidArch,
+ true, // is_qemu2
+ opts,
+ hw,
+ &android_avdInfo,
+ &exitStatus)) {
+ // Special case for QEMU positional parameters.
+ if (exitStatus == EMULATOR_EXIT_STATUS_POSITIONAL_QEMU_PARAMETER) {
+ // Copy all QEMU options to |args|, and set |n| to the number
+ // of options in |args| (|argc| must be positive here).
+ for (n = 1; n <= argc; ++n) {
+ args[n] = argv[n - 1];
+ }
+
+ // Skip the translation of command-line options and jump
+ // straight to qemu_main().
+ enter_qemu_main_loop(n, (char**)args);
+ return 0;
+ }
+
+ // Normal exit.
+ return exitStatus;
+ }
+ // just because we know that we're in the new emulator as we got here
+ opts->ranchu = 1;
+
+ avd = android_avdInfo;
+
+ if (!emulator_parseUiCommandLineOptions(opts, avd, hw)) {
+ return 1;
+ }
+
+ char boot_prop_ip[128] = {};
+ if (opts->shared_net_id) {
+ char* end;
+ long shared_net_id = strtol(opts->shared_net_id, &end, 0);
+ if (end == NULL || *end || shared_net_id < 1 || shared_net_id > 255) {
+ fprintf(stderr, "option -shared-net-id must be an integer between 1 and 255\n");
+ return 1;
+ }
+ snprintf(boot_prop_ip, sizeof(boot_prop_ip),
+ "net.shared_net_ip=10.1.2.%ld", shared_net_id);
+ }
+ if (boot_prop_ip[0]) {
+ args[n++] = "-boot-property";
+ args[n++] = boot_prop_ip;
+ }
+
+#ifdef CONFIG_NAND_LIMITS
+ if (opts->nand_limits) {
+ args[n++] = "-nand-limits";
+ args[n++] = opts->nand_limits;
+ }
+#endif
+
+ if (opts->timezone) {
+ args[n++] = "-timezone";
+ args[n++] = opts->timezone;
+ }
+
+ if (opts->netspeed) {
+ args[n++] = "-netspeed";
+ args[n++] = opts->netspeed;
+ }
+ if (opts->netdelay) {
+ args[n++] = "-netdelay";
+ args[n++] = opts->netdelay;
+ }
+ if (opts->netfast) {
+ args[n++] = "-netfast";
+ }
+
+ if (opts->audio && !strcmp(opts->audio, "none")) {
+ args[n++] = "-no-audio";
+ }
+
+ if (opts->cpu_delay) {
+ args[n++] = "-cpu-delay";
+ args[n++] = opts->cpu_delay;
+ }
+
+ if (opts->dns_server) {
+ args[n++] = "-dns-server";
+ args[n++] = opts->dns_server;
+ }
+
+ /** SNAPSHOT STORAGE HANDLING */
+
+ /* If we have a valid snapshot storage path */
+
+ if (opts->snapstorage) {
+ // NOTE: If QEMU2_SNAPSHOT_SUPPORT is not defined, a warning has been
+ // already printed by emulator_parseCommonCommandLineOptions().
+#ifdef QEMU2_SNAPSHOT_SUPPORT
+ /* We still use QEMU command-line options for the following since
+ * they can change from one invokation to the next and don't really
+ * correspond to the hardware configuration itself.
+ */
+ if (!opts->no_snapshot_load) {
+ args[n++] = "-loadvm";
+ args[n++] = ASTRDUP(opts->snapshot);
+ }
+
+ if (!opts->no_snapshot_save) {
+ args[n++] = "-savevm-on-exit";
+ args[n++] = ASTRDUP(opts->snapshot);
+ }
+
+ if (opts->no_snapshot_update_time) {
+ args[n++] = "-snapshot-no-time-update";
+ }
+#endif // QEMU2_SNAPSHOT_SUPPORT
+ }
+
+ {
+ // Always setup a single serial port, that can be connected
+ // either to the 'null' chardev, or the -shell-serial one,
+ // which by default will be either 'stdout' (Posix) or 'con:'
+ // (Windows).
+ const char* serial =
+ (opts->shell || opts->logcat || opts->show_kernel)
+ ? opts->shell_serial : "null";
+ args[n++] = "-serial";
+ args[n++] = serial;
+ }
+
+ if (opts->radio) {
+ args[n++] = "-radio";
+ args[n++] = opts->radio;
+ }
+
+ if (opts->gps) {
+ args[n++] = "-gps";
+ args[n++] = opts->gps;
+ }
+
+ if (opts->code_profile) {
+ args[n++] = "-code-profile";
+ args[n++] = opts->code_profile;
+ }
+
+ /* Pass boot properties to the core. First, those from boot.prop,
+ * then those from the command-line */
+ const FileData* bootProperties = avdInfo_getBootProperties(avd);
+ if (!fileData_isEmpty(bootProperties)) {
+ PropertyFileIterator iter[1];
+ propertyFileIterator_init(iter,
+ bootProperties->data,
+ bootProperties->size);
+ while (propertyFileIterator_next(iter)) {
+ char temp[MAX_PROPERTY_NAME_LEN + MAX_PROPERTY_VALUE_LEN + 2];
+ snprintf(temp, sizeof temp, "%s=%s", iter->name, iter->value);
+ args[n++] = "-boot-property";
+ args[n++] = ASTRDUP(temp);
+ }
+ }
+
+ if (opts->prop != NULL) {
+ ParamList* pl = opts->prop;
+ for ( ; pl != NULL; pl = pl->next ) {
+ args[n++] = "-boot-property";
+ args[n++] = pl->param;
+ }
+ }
+
+ if (opts->ports) {
+ args[n++] = "-android-ports";
+ args[n++] = opts->ports;
+ }
+
+ if (opts->port) {
+ int console_port = -1;
+ int adb_port = -1;
+ if (!android_parse_port_option(opts->port, &console_port, &adb_port)) {
+ return 1;
+ }
+ std::string portsOption = StringFormat("%d,%d",
+ console_port, adb_port);
+ args[n++] = "-android-ports";
+ args[n++] = strdup(portsOption.c_str());
+ }
+
+ if (opts->report_console) {
+ args[n++] = "-android-report-console";
+ args[n++] = opts->report_console;
+ }
+
+ if (opts->http_proxy) {
+ args[n++] = "-http-proxy";
+ args[n++] = opts->http_proxy;
+ }
+
+ if (!opts->charmap) {
+ /* Try to find a valid charmap name */
+ char* charmap = avdInfo_getCharmapFile(avd, hw->hw_keyboard_charmap);
+ if (charmap != NULL) {
+ D("autoconfig: -charmap %s", charmap);
+ opts->charmap = charmap;
+ }
+ }
+
+ if (opts->charmap) {
+ char charmap_name[SKIN_CHARMAP_NAME_SIZE];
+
+ if (!path_exists(opts->charmap)) {
+ derror("Charmap file does not exist: %s", opts->charmap);
+ return 1;
+ }
+ /* We need to store the charmap name in the hardware configuration.
+ * However, the charmap file itself is only used by the UI component
+ * and doesn't need to be set to the emulation engine.
+ */
+ kcm_extract_charmap_name(opts->charmap, charmap_name,
+ sizeof(charmap_name));
+ reassign_string(&hw->hw_keyboard_charmap, charmap_name);
+ }
+
+// TODO: imement network
+#if 0
+ /* Set up the interfaces for inter-emulator networking */
+ if (opts->shared_net_id) {
+ unsigned int shared_net_id = atoi(opts->shared_net_id);
+ char nic[37];
+
+ args[n++] = "-net";
+ args[n++] = "nic,vlan=0";
+ args[n++] = "-net";
+ args[n++] = "user,vlan=0";
+
+ args[n++] = "-net";
+ snprintf(nic, sizeof nic, "nic,vlan=1,macaddr=52:54:00:12:34:%02x", shared_net_id);
+ args[n++] = strdup(nic);
+ args[n++] = "-net";
+ args[n++] = "socket,vlan=1,mcast=230.0.0.10:1234";
+ }
+#endif
+
+ // Create userdata file from init version if needed.
+ if (android_op_wipe_data || !path_exists(hw->disk_dataPartition_path)) {
+ if (!path_exists(hw->disk_dataPartition_initPath)) {
+ derror("Missing initial data partition file: %s",
+ hw->disk_dataPartition_initPath);
+ return 1;
+ }
+ D("Creating: %s\n", hw->disk_dataPartition_path);
+
+ if (path_copy_file(hw->disk_dataPartition_path,
+ hw->disk_dataPartition_initPath) < 0) {
+ derror("Could not create %s: %s", hw->disk_dataPartition_path,
+ strerror(errno));
+ return 1;
+ }
+
+ resizeExt4Partition(android_hw->disk_dataPartition_path,
+ android_hw->disk_dataPartition_size);
+ }
+ else {
+ // Resize userdata-qemu.img if the size is smaller than what config.ini
+ // says.
+ // This can happen as user wants a larger data partition without wiping
+ // it.
+ // b.android.com/196926
+ System::FileSize current_data_size;
+ if (System::get()->pathFileSize(hw->disk_dataPartition_path,
+ ¤t_data_size)) {
+ System::FileSize partition_size = static_cast<System::FileSize>(
+ android_hw->disk_dataPartition_size);
+ if (android_hw->disk_dataPartition_size > 0 &&
+ current_data_size < partition_size) {
+ dwarning("userdata partition is resized from %d M to %d M\n",
+ (int)(current_data_size / (1024 * 1024)),
+ (int)(partition_size / (1024 * 1024)));
+ resizeExt4Partition(android_hw->disk_dataPartition_path,
+ android_hw->disk_dataPartition_size);
+ }
+ }
+ }
+
+ bool createEmptyCacheFile = false;
+
+ // Make sure there's a temp cache partition if there wasn't a permanent one
+ if (!hw->disk_cachePartition_path ||
+ strcmp(hw->disk_cachePartition_path, "") == 0) {
+ str_reset(&hw->disk_cachePartition_path,
+ tempfile_path(tempfile_create()));
+ createEmptyCacheFile = true;
+ }
+
+ createEmptyCacheFile |= !path_exists(hw->disk_cachePartition_path);
+
+ if (createEmptyCacheFile) {
+ D("Creating empty ext4 cache partition: %s",
+ hw->disk_cachePartition_path);
+ int ret = android_createEmptyExt4Image(
+ hw->disk_cachePartition_path,
+ hw->disk_cachePartition_size,
+ "cache");
+ if (ret < 0) {
+ derror("Could not create %s: %s", hw->disk_cachePartition_path,
+ strerror(-ret));
+ return 1;
+ }
+ }
+
+ // Make sure we always use the custom Android CPU definition.
+ args[n++] = "-cpu";
+ args[n++] = kTarget.qemuCpu;
+
+#if defined(TARGET_X86_64) || defined(TARGET_I386)
+ char* accel_status = NULL;
+ CpuAccelMode accel_mode = ACCEL_AUTO;
+ const bool accel_ok = handleCpuAcceleration(opts, avd,
+ &accel_mode, &accel_status);
+
+ if (accel_mode == ACCEL_ON) { // 'accel on' is specified'
+ if (!accel_ok) {
+ derror("CPU acceleration is not supported on this machine!");
+ derror("Reason: %s", accel_status);
+ return 1;
+ }
+ args[n++] = ASTRDUP(kEnableAccelerator);
+ } else if (accel_mode == ACCEL_AUTO) {
+ if (accel_ok) {
+ args[n++] = ASTRDUP(kEnableAccelerator);
+ }
+ } // else accel is off and we don't need to add anything else
+
+ AFREE(accel_status);
+#else // !TARGET_X86_64 && !TARGET_I386
+ args[n++] = "-machine";
+ args[n++] = "type=ranchu";
+#endif // !TARGET_X86_64 && !TARGET_I386
+
+#if defined(TARGET_X86_64) || defined(TARGET_I386)
+ // SMP Support.
+ std::string ncores;
+ if (hw->hw_cpu_ncore > 1) {
+ args[n++] = "-smp";
+
+#ifdef _WIN32
+ if (hw->hw_cpu_ncore > 16) {
+ dwarning("HAXM does not support more than 16 cores. Number of cores set to 16");
+ hw->hw_cpu_ncore = 16;
+ }
+#endif
+ ncores = StringFormat("cores=%ld", hw->hw_cpu_ncore);
+ args[n++] = ncores.c_str();
+ }
+#endif // !TARGET_X86_64 && !TARGET_I386
+
+ // Memory size
+ args[n++] = "-m";
+ std::string memorySize = StringFormat("%ld", hw->hw_ramSize);
+ args[n++] = memorySize.c_str();
+
+ // Kernel command-line parameters.
+ AndroidGlesEmulationMode glesMode = kAndroidGlesEmulationOff;
+ if (hw->hw_gpu_enabled) {
+ if (!strcmp(hw->hw_gpu_mode, "guest")) {
+ glesMode = kAndroidGlesEmulationGuest;
+ } else {
+ glesMode = kAndroidGlesEmulationHost;
+ }
+ }
+
+ uint64_t glesFramebufferCMA = 0ULL;
+ if ((glesMode == kAndroidGlesEmulationGuest) ||
+ (opts->gpu && !strcmp(opts->gpu, "guest")) ||
+ !hw->hw_gpu_enabled) {
+ // Set CMA (continguous memory allocation) to values that depend on
+ // the desired resolution.
+ // We will assume a double buffered 32-bit framebuffer
+ // in the calculation.
+ int framebuffer_width = hw->hw_lcd_width;
+ int framebuffer_height = hw->hw_lcd_height;
+ uint64_t bytes = framebuffer_width * framebuffer_height * 4;
+ const uint64_t one_MB = 1024ULL * 1024;
+ glesFramebufferCMA = (2 * bytes + one_MB - 1) / one_MB;
+ VERBOSE_PRINT(init, "Adjusting Contiguous Memory Allocation "
+ "of %dx%d framebuffer for software renderer to %"
+ PRIu64 "MB.", framebuffer_width, framebuffer_height,
+ glesFramebufferCMA);
+ } else {
+ VERBOSE_PRINT(init, "Using default value for kernel "
+ "Contiguous Memory Allocation.");
+ }
+
+
+ int apiLevel = avd ? avdInfo_getApiLevel(avd) : 1000;
+
+ char* kernel_parameters = emulator_getKernelParameters(
+ opts, kTarget.androidArch, apiLevel, kTarget.ttyPrefix,
+ hw->kernel_parameters, glesMode, glesFramebufferCMA,
+ true // isQemu2
+ );
+ if (!kernel_parameters) {
+ return 1;
+ }
+
+ args[n++] = "-append";
+ args[n++] = kernel_parameters;
+
+ // Support for changing default lcd-density
+ std::string lcd_density;
+ if (hw->hw_lcd_density) {
+ args[n++] = "-lcd-density";
+ lcd_density = StringFormat("%d", hw->hw_lcd_density);
+ args[n++] = lcd_density.c_str();
+ }
+
+ // Kernel image
+ args[n++] = "-kernel";
+ args[n++] = hw->kernel_path;
+
+ // Ramdisk
+ args[n++] = "-initrd";
+ args[n++] = hw->disk_ramdisk_path;
+
+ /*
+ * add partition parameters with the sequence
+ * pre-defined in targetInfo.imagePartitionTypes
+ */
+ int s;
+ int drvIndex = 0;
+ for (s = 0; s < kMaxPartitions; s++) {
+ bool writable = (kTarget.imagePartitionTypes[s] == IMAGE_TYPE_SYSTEM) ?
+ android_op_writable_system : true;
+ makePartitionCmd(args, &n, &drvIndex, hw,
+ kTarget.imagePartitionTypes[s], writable, apiLevel);
+ }
+
+ // Network
+ args[n++] = "-netdev";
+ args[n++] = "user,id=mynet";
+ args[n++] = "-device";
+ std::string netDevice =
+ StringFormat("%s,netdev=mynet", kTarget.networkDeviceType);
+ args[n++] = netDevice.c_str();
+ args[n++] = "-show-cursor";
+
+ // TODO: the following *should* re-enable -tcpdump in QEMU2 when we have
+ // rebased to at least QEMU 2.5 - the standard -tcpdump flag
+ // See http://wiki.qemu.org/ChangeLog/2.5#Network_2 and
+ // http://wiki.qemu.org/download/qemu-doc.html#index-_002dobject
+// std::string tcpdumpArg;
+// if (opts->tcpdump) {
+// args[n++] = "-object";
+// tcpdumpArg = StringFormat("filter-dump,id=mytcpdump,netdev=mynet,file=%s",
+// opts->tcpdump);
+// args[n++] = tcpdumpArg.c_str();
+// }
+
+ if (opts->tcpdump) {
+ dwarning("The -tcpdump flag is not supported in QEMU2 yet and will "
+ "be ignored.");
+ }
+
+ // Graphics
+ if (opts->no_window) {
+ args[n++] = "-nographic";
+ // also disable the qemu monitor which will otherwise grab stdio
+ args[n++] = "-monitor";
+ args[n++] = "none";
+ }
+
+ // Data directory (for keymaps and PC Bios).
+ args[n++] = "-L";
+ std::string dataDir = getNthParentDir(args[0], 3U);
+ if (dataDir.empty()) {
+ dataDir = "lib/pc-bios";
+ } else {
+ dataDir += "/lib/pc-bios";
+ }
+ args[n++] = dataDir.c_str();
+
+ // Audio enable hda by default for x86 and x64 platforms
+#if defined(TARGET_X86_64) || defined(TARGET_I386)
+ args[n++] = "-soundhw";
+ args[n++] = "hda";
+#endif
+
+ /* append extra qemu parameters if any */
+ for (int idx = 0; kTarget.qemuExtraArgs[idx] != NULL; idx++) {
+ args[n++] = kTarget.qemuExtraArgs[idx];
+ }
+
+ /* append the options after -qemu */
+ for (int i = 0; i < argc; ++i) {
+ args[n++] = argv[i];
+ }
+
+ /* Generate a hardware-qemu.ini for this AVD. The real hardware
+ * configuration is ususally stored in several files, e.g. the AVD's
+ * config.ini plus the skin-specific hardware.ini.
+ *
+ * The new file will group all definitions and will be used to
+ * launch the core with the -android-hw <file> option.
+ */
+ {
+ const char* coreHwIniPath = avdInfo_getCoreHwIniPath(avd);
+ const auto hwIni = android::base::makeCustomScopedPtr(
+ iniFile_newEmpty(NULL), iniFile_free);
+ androidHwConfig_write(hw, hwIni.get());
+
+ if (filelock_create(coreHwIniPath) == NULL) {
+ // The AVD is already in use
+ derror("There's another emulator instance running with "
+ "the current AVD '%s'. Exiting...\n", avdInfo_getName(avd));
+ return 1;
+ }
+
+ /* While saving HW config, ignore valueless entries. This will not break
+ * anything, but will significantly simplify comparing the current HW
+ * config with the one that has been associated with a snapshot (in case
+ * VM starts from a snapshot for this instance of emulator). */
+ if (iniFile_saveToFileClean(hwIni.get(), coreHwIniPath) < 0) {
+ derror("Could not write hardware.ini to %s: %s", coreHwIniPath, strerror(errno));
+ return 2;
+ }
+ args[n++] = "-android-hw";
+ args[n++] = strdup(coreHwIniPath);
+
+ crashhandler_copy_attachment(CRASH_AVD_HARDWARE_INFO, coreHwIniPath);
+
+ /* In verbose mode, dump the file's content */
+ if (VERBOSE_CHECK(init)) {
+ FILE* file = fopen(coreHwIniPath, "rt");
+ if (file == NULL) {
+ derror("Could not open hardware configuration file: %s\n",
+ coreHwIniPath);
+ } else {
+ LineInput* input = lineInput_newFromStdFile(file);
+ const char* line;
+ printf("Content of hardware configuration file:\n");
+ while ((line = lineInput_getLine(input)) != NULL) {
+ printf(" %s\n", line);
+ }
+ printf(".\n");
+ lineInput_free(input);
+ fclose(file);
+ }
+ }
+ }
+
+ args[n] = NULL;
+ // Check if we had enough slots in |args|.
+ assert(n < (int)(sizeof(args)/sizeof(args[0])));
+
+ if(VERBOSE_CHECK(init)) {
+ int i;
+ printf("QEMU options list:\n");
+ for(i = 0; i < n; i++) {
+ printf("emulator: argv[%02d] = \"%s\"\n", i, args[i]);
+ }
+ /* Dump final command-line option to make debugging the core easier */
+ printf("Concatenated QEMU options:\n");
+ for (i = 0; i < n; i++) {
+ /* To make it easier to copy-paste the output to a command-line,
+ * quote anything that contains spaces.
+ */
+ if (strchr(args[i], ' ') != NULL) {
+ printf(" '%s'", args[i]);
+ } else {
+ printf(" %s", args[i]);
+ }
+ }
+ printf("\n");
+ }
+
+ qemu2_android_serialline_init();
+
+ static UiEmuAgent uiEmuAgent;
+ uiEmuAgent.battery = gQAndroidBatteryAgent;
+ uiEmuAgent.cellular = gQAndroidCellularAgent;
+ uiEmuAgent.finger = gQAndroidFingerAgent;
+ uiEmuAgent.location = gQAndroidLocationAgent;
+ uiEmuAgent.sensors = gQAndroidSensorsAgent;
+ uiEmuAgent.telephony = gQAndroidTelephonyAgent;
+ uiEmuAgent.userEvents = gQAndroidUserEventAgent;
+ uiEmuAgent.window = gQAndroidEmulatorWindowAgent;
+
+ // for now there's no uses of SettingsAgent, so we don't set it
+ uiEmuAgent.settings = NULL;
+
+ /* Setup SDL UI just before calling the code */
+#ifndef _WIN32
+ sigset_t set;
+ sigfillset(&set);
+ pthread_sigmask(SIG_SETMASK, &set, NULL);
+#endif // !_WIN32
+
+ if (!emulator_initUserInterface(opts, &uiEmuAgent)) {
+ return 1;
+ }
+
+ skin_winsys_spawn_thread(opts->no_window, enter_qemu_main_loop, n, (char**)args);
+ skin_winsys_enter_main_loop(opts->no_window, argc, argv);
+
+ emulator_finiUserInterface();
+
+ process_late_teardown();
+ return 0;
}
diff --git a/vl.c b/vl.c
index b2cd32e..4a8de9c 100644
--- a/vl.c
+++ b/vl.c
@@ -53,7 +53,7 @@
#endif /* CONFIG_COCOA */
#ifdef CONFIG_ANDROID
-#define main qemu_main
+#define main run_qemu_main
#endif
#include "qemu/error-report.h"