android: Update vl.c to use AndroidEmu + support Android options
diff --git a/qemu-options.hx b/qemu-options.hx
index 7d3166f..fd06b25 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -295,6 +295,16 @@
 parameters.
 ETEXI
 
+DEF("no-audio", 0, QEMU_OPTION_audio_none,
+    "-no-audio        disable audio support\n",
+    QEMU_ARCH_ALL)
+STEXI
+@item -no-audio
+@findex -no-audio
+Will disable audio support
+parameters.
+ETEXI
+
 DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw,
     "-soundhw c1,... enable audio support\n"
     "                and only specified sound cards (comma separated list)\n"
@@ -3388,6 +3398,94 @@
 in @var{file}
 ETEXI
 
+#ifdef CONFIG_ANDROID
+
+DEF("netspeed", HAS_ARG, QEMU_OPTION_netspeed,
+    "-netspeed <speed> maximum network download/upload speeds\n", QEMU_ARCH_ALL)
+STEXI
+@item -netspeed @var{speed}
+@findex -netspeed
+Set a maximum network transfer speed, either as a network type or in kbit/s
+ETEXI
+
+DEF("netdelay", HAS_ARG, QEMU_OPTION_netdelay,
+    "-netdelay <delay> network latency emulation\n", QEMU_ARCH_ALL)
+STEXI
+@item -netdelay @var{delay}
+@findex -netdelay
+Set the network delay, either based on a network type or in milliseconds
+ETEXI
+
+DEF("netfast", 0, QEMU_OPTION_netfast,
+    "-netfast disable network shaping\n", QEMU_ARCH_ALL)
+STEXI
+@item -netfast
+@findex -netfast
+Disable network shaping to make network as fast as possible
+ETEXI
+
+DEF("boot-property", HAS_ARG, QEMU_OPTION_boot_property, \
+    "-boot-property <name>=<value> set system property on boot\n", QEMU_ARCH_ALL)
+STEXI
+@item -boot-property
+@findex -boot-property
+Set system property on boot
+ETEXI
+
+DEF("lcd-density", HAS_ARG, QEMU_OPTION_lcd_density,
+    "-lcd-density density\n"
+    "                select lcd display density value (default is 160)\n", QEMU_ARCH_ALL)
+STEXI
+@item -lcd-density density (integer value)
+@findex -lcd-density
+Select lcd display density value (default is 160)
+ETEXI
+
+DEF("android-ports", HAS_ARG, QEMU_OPTION_android_ports,
+    "-android-ports <consoleport>,<adbport>"
+    " TCP ports used for the emulator instance and adb bridge\n", QEMU_ARCH_ALL)
+STEXI
+@item -android-ports @var{consoleport},@var{adbport}
+@findex -android-ports
+TCP ports used for the emulator instance and adb bridge
+ETEXI
+
+DEF("android-report-console", HAS_ARG, QEMU_OPTION_android_report_console, \
+    "-android-report-console <socket>"
+    " report console port to remote socket\n", QEMU_ARCH_ALL)
+STEXI
+@item -android-report-console @var{socket}
+@findex -android-report-console
+Report console port to remote socket
+ETEXI
+
+DEF("http-proxy", HAS_ARG, QEMU_OPTION_http_proxy,
+    "-http-proxy <proxy> make TCP connections through a HTTP/HTTPS proxy\n", QEMU_ARCH_ALL)
+STEXI
+@item -http-proxy @var{proxy}
+@findex -http-proxy
+make TCP connections through a HTTP/HTTPS proxy
+ETEXI
+
+DEF("dns-server", HAS_ARG, QEMU_OPTION_dns_server,
+    "-dns-server <servers> use this DNS server(s) in the emulated system\n", QEMU_ARCH_ALL)
+STEXI
+@item -dns-server @var{servers}
+@findex -dns-server
+Use one or more DNS servers, separated by comma, in the emulated system
+ETEXI
+
+DEF("android-hw", HAS_ARG, QEMU_OPTION_android_hw,
+    "-android-hw <file>\n"
+    "                specify the hw config ini file location\n", QEMU_ARCH_ALL)
+STEXI
+@item -android-hw @var{file}
+@findex -android-hw
+Specify the hw config ini file location
+ETEXI
+
+#endif
+
 HXCOMM This is the last statement. Insert new options before this line!
 STEXI
 @end table
diff --git a/vl.c b/vl.c
old mode 100644
new mode 100755
index cd0fff2..209b5e8
--- a/vl.c
+++ b/vl.c
@@ -38,24 +38,6 @@
 #include <libvdeplug.h>
 #endif
 
-#ifdef CONFIG_SDL
-#if defined(__APPLE__) || defined(main)
-#include <SDL.h>
-int qemu_main(int argc, char **argv, char **envp);
-int main(int argc, char **argv)
-{
-    return qemu_main(argc, argv, NULL);
-}
-#undef main
-#define main qemu_main
-#endif
-#endif /* CONFIG_SDL */
-
-#ifdef CONFIG_COCOA
-#undef main
-#define main qemu_main
-#endif /* CONFIG_COCOA */
-
 #include <glib.h>
 
 #include "qemu/sockets.h"
@@ -71,6 +53,7 @@
 #include "hw/xen/xen.h"
 #include "hw/qdev.h"
 #include "hw/loader.h"
+#include "hw/display/goldfish_fb.h"
 #include "monitor/qdev.h"
 #include "sysemu/bt.h"
 #include "net/net.h"
@@ -120,11 +103,83 @@
 #include "qom/object_interfaces.h"
 #include "qapi-event.h"
 
+#ifdef CONFIG_ANDROID
+
+
+#include "config.h"
+
+#include "android/boot-properties.h"
+#include "android/error-messages.h"
+#include "android/crashreport/crash-handler.h"
+#include "android/emulation/bufprint_config_dirs.h"
+#include "android/metrics/metrics_reporter.h"
+#include "android/metrics/studio-config.h"
+#include "android/update-check/update_check.h"
+#include "android/utils/async.h"
+#include "android/utils/debug.h"
+#include "android/utils/path.h"
+#include "android/utils/property_file.h"
+#include "android/utils/lineinput.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/filelock.h"
+#include "android/utils/ini.h"
+#include "android/utils/tempfile.h"
+#include "android/skin/winsys.h"
+#include "android/main-common.h"
+#include "android/multitouch-port.h"
+#include "android/network/globals.h"
+#include "android/opengl/emugl_config.h"
+#include "android/ui-emu-agent.h"
+#include "android/globals.h"
+#include "android/help.h"
+#include "android-qemu2-glue/looper-qemu.h"
+#include "android/gps.h"
+#include "android/telephony/modem_driver.h"
+#include "android/hw-control.h"
+#include "android/hw-qemud.h"
+#include "android/utils/socket_drainer.h"
+#include "android/wear-agent/android_wear_agent.h"
+#include "android-qemu2-glue/android_qemud.h"
+#include "android-qemu2-glue/qemu-control-impl.h"
+#include "android-qemu2-glue/qemu-setup.h"
+#include "android/snapshot.h"
+#include "android/snaphost-android.h"
+#include "android/android.h"
+#include "android/camera/camera-service.h"
+#include "android/version.h"
+#include "hw/input/goldfish_events.h"
+
+// this path has to be relative as AndroidEmu include paths go after the qemu2
+// ones, and android/opengles.h resolves to the very same this file
+#include "../qemu/android/opengles.h"
+
+#define QEMU_CORE_VERSION "qemu2 " QEMU_VERSION
+
+int android_display_width  = 640;
+int android_display_height = 480;
+
+/////////////////////////////////////////////////////////////
+
+#define  LCD_DENSITY_LDPI      120
+#define  LCD_DENSITY_MDPI      160
+#define  LCD_DENSITY_TVDPI     213
+#define  LCD_DENSITY_HDPI      240
+#define  LCD_DENSITY_280DPI    280
+#define  LCD_DENSITY_XHDPI     320
+#define  LCD_DENSITY_360DPI    360
+#define  LCD_DENSITY_400DPI    400
+#define  LCD_DENSITY_420DPI    420
+#define  LCD_DENSITY_XXHDPI    480
+#define  LCD_DENSITY_560DPI    560
+#define  LCD_DENSITY_XXXHDPI   640
+#endif // CONFIG_ANDROID
+
 #define DEFAULT_RAM_SIZE 128
 
 #define MAX_VIRTIO_CONSOLES 1
 #define MAX_SCLP_CONSOLES 1
 
+
 static const char *data_dir[16];
 static int data_dir_idx;
 const char *bios_name = NULL;
@@ -169,6 +224,20 @@
 int no_shutdown = 0;
 int cursor_hide = 1;
 int graphic_rotate = 0;
+#ifdef CONFIG_ANDROID
+/* -netspeed option value. */
+char* android_op_netspeed = NULL;
+char* android_op_netdelay = NULL;
+int android_op_netfast = 0;
+char* android_op_dns_server = NULL;
+int lcd_density = LCD_DENSITY_MDPI;
+char* additional_kernel_params = NULL;
+extern char* op_http_proxy;
+extern char* android_op_ports;
+extern int android_op_ports_numbers[2];
+extern char* android_op_report_console;
+static const char* android_hw_file = NULL;
+#endif  // CONFIG_ANDROID
 const char *watchdog;
 QEMUOptionRom option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;
@@ -555,6 +624,38 @@
     },
 };
 
+#ifdef CONFIG_ANDROID
+// Save System boot parameters from the command line
+#define MAX_N_CMD_PROPS 16
+static const char* cmd_props[MAX_N_CMD_PROPS];
+static       int   n_cmd_props = 0;
+
+static void save_cmd_property(const char* propStr) {
+    if (n_cmd_props >= MAX_N_CMD_PROPS) {
+        fprintf(stderr, "Too many command-line boot properties. "
+                        "This property is ignored: \"%s\"\n", propStr);
+        return;
+    }
+    cmd_props[n_cmd_props++] = propStr;
+}
+
+// Provide the saved System boot parameters from the command line
+static void process_cmd_properties(void) {
+    int idx;
+    for(idx = 0; idx < n_cmd_props; idx++) {
+        // The string should be of the form
+        // "keyname=value"
+        const char* pkey = cmd_props[idx];
+        const char* peq = strchr(pkey, '=');
+        if (peq) {
+            // Pass ptr and length for both parts
+            boot_property_add2(pkey, (peq - pkey),
+                               peq + 1, strlen(peq + 1));
+        }
+    }
+}
+#endif  // CONFIG_ANDROID
+
 /**
  * Get machine options
  *
@@ -576,6 +677,9 @@
         g_free(boot_splash_filedata);
         boot_splash_filedata = NULL;
     }
+#ifdef CONFIG_ANDROID
+    g_free(additional_kernel_params);
+#endif  // CONFIG_ANDROID
 }
 
 static int default_driver_check(QemuOpts *opts, void *opaque)
@@ -1906,7 +2010,7 @@
 
 static void version(void)
 {
-    printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+    printf("QEMU emulator version " QEMU_VERSION " " QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
 }
 
 static void help()
@@ -2051,7 +2155,7 @@
     DisplayType display = DT_DEFAULT;
 
     if (strstart(p, "sdl", &opts)) {
-#ifdef CONFIG_SDL
+#if defined(CONFIG_SDL) || defined(CONFIG_ANDROID)
         display = DT_SDL;
         while (*opts) {
             const char *nextopt;
@@ -2608,12 +2712,12 @@
     notifier_list_notify(&machine_init_done_notifiers, NULL);
 }
 
-static const QEMUOption *lookup_opt(int argc, char **argv,
+static const QEMUOption *lookup_opt(int argc, const char **argv,
                                     const char **poptarg, int *poptind)
 {
     const QEMUOption *popt;
     int optind = *poptind;
-    char *r = argv[optind];
+    const char *r = argv[optind];
     const char *optarg;
 
     loc_set_cmdline(argv, optind, 1);
@@ -2755,7 +2859,106 @@
     return 0;
 }
 
-int main(int argc, char **argv, char **envp)
+#if !defined(CONFIG_ANDROID)
+// We don't use the AndroidEmu library in the original qemu2 build,
+// so let's return their main function back
+#define run_qemu_main main
+
+#else  /* CONFIG_ANDROID */
+
+static int is_opengl_alive = 1;
+
+static void android_check_for_updates()
+{
+    android_checkForUpdates(QEMU_CORE_VERSION);
+}
+
+static void android_init_metrics()
+{
+    char path[MAX_PATH], *pathend=path, *bufend=pathend+sizeof(path);
+    AndroidMetrics metrics;
+
+    if (!android_studio_get_optins()) {
+        return;
+    }
+
+    pathend = bufprint_avd_home_path(path, bufend);
+    if (pathend >= bufend || !androidMetrics_moduleInit(path))
+    {
+        printf("Failed to initialize metrics reporting.\n");
+        return;
+    }
+
+    androidMetrics_init(&metrics);
+    ANDROID_METRICS_STRASSIGN(metrics.emulator_version,
+                              EMULATOR_VERSION_STRING);
+    ANDROID_METRICS_STRASSIGN(metrics.core_version,
+                              QEMU_CORE_VERSION);
+
+    ANDROID_METRICS_STRASSIGN_MALLOCED(metrics.host_os_type, get_host_os_type());
+    ANDROID_METRICS_STRASSIGN(metrics.guest_arch, android_hw->hw_cpu_arch);
+    metrics.guest_api_level = avdInfo_getApiLevel(android_avdInfo);
+
+    metrics.renderer =
+        emuglConfig_get_renderer(android_hw->hw_gpu_mode);
+    metrics.guest_gpu_enabled = android_hw->hw_gpu_enabled;
+    if (android_hw->hw_gpu_enabled) {
+        free(metrics.guest_gl_vendor);
+        metrics.guest_gl_vendor = NULL;
+        free(metrics.guest_gl_renderer);
+        metrics.guest_gl_renderer = NULL;
+        free(metrics.guest_gl_version);
+        metrics.guest_gl_version = NULL;
+        // This call is only sensible after |android_startOpenglesRenderer| has
+        // been called.
+        android_getOpenglesHardwareStrings(&metrics.guest_gl_vendor,
+                                           &metrics.guest_gl_renderer,
+                                           &metrics.guest_gl_version);
+    }
+
+    // Tell the metrics the host GPU information
+    emugl_host_gpu_prop_list gpu_props = emuglConfig_get_host_gpu_props();
+    androidMetrics_populateGpuProps(&metrics, &gpu_props);
+    free_emugl_host_gpu_props(gpu_props);
+
+    metrics.opengl_alive = is_opengl_alive;
+    androidMetrics_write(&metrics);
+    androidMetrics_fini(&metrics);
+
+    async((async_function_t)androidMetrics_tryReportAll);
+
+    androidMetrics_keepAlive(looper_getForThread(), android_base_port);
+}
+
+static void android_teardown_metrics()
+{
+    // NB: It is safe to cleanup metrics reporting even if we never initialized
+    // it.
+    androidMetrics_seal();
+    androidMetrics_moduleFini();
+}
+
+static bool android_reporting_setup(void)
+{
+    android_init_metrics();
+    if (!is_opengl_alive) {
+        derror("Could not initialize OpenglES emulation, "
+               "use '-gpu off' to disable it.");
+        return false;
+    }
+
+    android_check_for_updates();
+    return true;
+}
+
+static void android_reporting_teardown(void)
+{
+    android_teardown_metrics();
+}
+
+#endif  /* CONFIG_ANDROID */
+
+int run_qemu_main(int argc, const char **argv)
 {
     int i;
     int snapshot, linux_boot;
@@ -3134,6 +3337,9 @@
                 AUD_help ();
                 return (0);
                 break;
+            case QEMU_OPTION_audio_none:
+                setenv("QEMU_AUDIO_DRV", "none", 1);
+                break;
             case QEMU_OPTION_soundhw:
                 select_soundhw (optarg);
                 break;
@@ -3499,13 +3705,13 @@
                 no_quit = 1;
                 break;
             case QEMU_OPTION_sdl:
-#ifdef CONFIG_SDL
+#if defined(CONFIG_SDL) || defined(CONFIG_ANDROID)
                 display_type = DT_SDL;
-                break;
 #else
                 fprintf(stderr, "SDL support is disabled\n");
                 return 1;
 #endif
+                break;
             case QEMU_OPTION_pidfile:
                 pid_file = optarg;
                 break;
@@ -3851,11 +4057,71 @@
                     return 1;
                 }
                 break;
+#ifdef CONFIG_ANDROID
+            case QEMU_OPTION_netspeed:
+                android_op_netspeed = (char*)optarg;
+                break;
+            case QEMU_OPTION_netdelay:
+                android_op_netdelay = (char*)optarg;
+                break;
+            case QEMU_OPTION_netfast:
+                android_op_netfast = 1;
+                break;
+            case QEMU_OPTION_boot_property:
+                save_cmd_property((char*)optarg);
+                break;
+            case QEMU_OPTION_lcd_density:
+                lcd_density = strtol(optarg, (char **) &optarg, 10);
+                switch (lcd_density) {
+                    case LCD_DENSITY_LDPI:
+                    case LCD_DENSITY_MDPI:
+                    case LCD_DENSITY_TVDPI:
+                    case LCD_DENSITY_HDPI:
+                    case LCD_DENSITY_280DPI:
+                    case LCD_DENSITY_XHDPI:
+                    case LCD_DENSITY_360DPI:
+                    case LCD_DENSITY_400DPI:
+                    case LCD_DENSITY_420DPI:
+                    case LCD_DENSITY_XXHDPI:
+                    case LCD_DENSITY_560DPI:
+                    case LCD_DENSITY_XXXHDPI:
+                        break;
+                    default:
+                        fprintf(stderr, "qemu: available lcd densities are: "
+                                "120, 160, 213, 240, 280, 320, 360, 400, 420, 480, 560, 640\n");
+                        return 1;
+                }
+                break;
+            case QEMU_OPTION_dns_server:
+                android_op_dns_server = (char*)optarg;
+                break;
+
+            case QEMU_OPTION_http_proxy:
+                op_http_proxy = (char*)optarg;
+                break;
+            case QEMU_OPTION_android_hw:
+                android_hw_file = optarg;
+                break;
+
+            case QEMU_OPTION_android_ports:
+                android_op_ports = (char*)optarg;
+                if (!android_parse_ports_option(android_op_ports,
+                                                &android_op_ports_numbers[0],
+                                                &android_op_ports_numbers[1])) {
+                    return 1;
+                }
+                break;
+            case QEMU_OPTION_android_report_console:
+                android_op_report_console = (char*)optarg;
+                break;
+
+#endif  // CONFIG_ANDROID
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
         }
     }
+
     loc_set_none();
 
     os_daemonize();
@@ -3865,6 +4131,193 @@
         return 1;
     }
 
+#ifdef CONFIG_ANDROID
+
+    /* Ensure Looper implementation for this thread is based on the QEMU
+     * main loop. */
+    qemu_looper_setForThread();
+
+    /* make sure qemud is initialized before any calls to it */
+    android_qemu2_qemud_init();
+
+    boot_property_init_service();
+    android_hw_control_init();
+
+    socket_drainer_start(looper_getForThread());
+    android_wear_agent_start(looper_getForThread());
+
+    if (!android_hw_file) {
+        error_report("Missing -android-hw <file> option!");
+        return 1;
+    }
+
+    CIniFile* hw_ini = iniFile_newFromFile(android_hw_file);
+    if (hw_ini == NULL) {
+        error_report("Could not find %s file.", android_hw_file);
+        return 1;
+    }
+
+    androidHwConfig_init(android_hw, 0);
+    androidHwConfig_read(android_hw, hw_ini);
+
+    /* If we're loading VM from a snapshot, make sure that the current HW config
+     * matches the one with which the VM has been saved. */
+    if (loadvm && *loadvm && !snaphost_match_configs(hw_ini, loadvm)) {
+        error_report("HW config doesn't match the one in the snapshot");
+        return 0;
+    }
+
+    iniFile_free(hw_ini);
+
+    {
+        int width  = android_hw->hw_lcd_width;
+        int height = android_hw->hw_lcd_height;
+        int depth  = android_hw->hw_lcd_depth;
+
+        /* A bit of sanity checking */
+        if (width <= 0 || height <= 0    ||
+            (depth != 16 && depth != 32) ||
+            ((width & 1) != 0)  )
+        {
+            error_report("Invalid display configuration (%d,%d,%d)",
+                  width, height, depth);
+            return 1;
+        }
+        android_display_width  = width;
+        android_display_height = height;
+        goldfish_fb_set_display_depth(depth);
+    }
+
+    /* Initialize camera */
+    android_camera_service_init();
+
+    /* Initialize multi-touch emulation. */
+    if (androidHwConfig_isScreenMultiTouch(android_hw)) {
+        mts_port_create(NULL, gQAndroidUserEventAgent, gQAndroidDisplayAgent);
+    }
+
+    /* qemu.gles will be read by the OpenGL ES emulation libraries.
+     * If set to 0, the software GL ES renderer will be used as a fallback.
+     * If the parameter is undefined, this means the system image runs
+     * inside an emulator that doesn't support GPU emulation at all.
+     *
+     * The GL ES renderer cannot start properly if GPU emulation is disabled
+     * because this requires changing the LD_LIBRARY_PATH before launching
+     * the emulation engine. */
+    int qemu_gles = 0;
+    is_opengl_alive = 1;
+    if (android_hw->hw_gpu_enabled) {
+        if (strcmp(android_hw->hw_gpu_mode, "guest") != 0) {
+            if (android_initOpenglesEmulation() != 0 ||
+                android_startOpenglesRenderer(android_hw->hw_lcd_width,
+                                              android_hw->hw_lcd_height) != 0) {
+                is_opengl_alive = 0;
+            } else {
+                goldfish_fb_set_use_host_gpu(1);
+                qemu_gles = 1;   // Using emugl
+            }
+        } else {
+            qemu_gles = 2;   // Using guest
+        }
+    }
+    if (qemu_gles) {
+        char  tmp[64];
+        snprintf(tmp, sizeof(tmp), "%d", 0x20000);
+        boot_property_add("ro.opengles.version", tmp);
+    }
+
+    /* Set the VM's max heap size, passed as a boot property */
+    if (android_hw->vm_heapSize > 0) {
+        char  temp[64];
+        snprintf(temp, sizeof(temp), "%dm", android_hw->vm_heapSize);
+        boot_property_add("dalvik.vm.heapsize",temp);
+    }
+
+    /* From API 19 and above, the platform provides an explicit property for low memory devices. */
+    if (android_hw->hw_ramSize <= 512) {
+        boot_property_add("ro.config.low_ram", "true");
+    }
+
+    /* Initialize presence of hardware nav button */
+    boot_property_add("qemu.hw.mainkeys", android_hw->hw_mainKeys ? "1" : "0");
+
+    if (android_hw->hw_gsmModem) {
+        if (android_qemud_get_channel(ANDROID_QEMUD_GSM,
+                                      &android_modem_serial_line) < 0) {
+            error_report("could not initialize qemud 'gsm' channel");
+            return 1;
+        }
+    }
+
+    if (android_hw->hw_gps) {
+        if (android_qemud_get_channel(ANDROID_QEMUD_GPS,
+                                      &android_gps_serial_line) < 0) {
+            error_report("could not initialize qemud 'gps' channel");
+            return 1;
+        }
+    }
+
+    if (lcd_density) {
+        char temp[8];
+        snprintf(temp, sizeof(temp), "%d", lcd_density);
+        boot_property_add("qemu.sf.lcd_density", temp);
+    }
+
+    if (android_op_netspeed) {
+        /* The command line gives the network speed */
+        if (android_parse_network_speed(android_op_netspeed) < 0) {
+            fprintf(stderr, "invalid -netspeed parameter '%s'\n",
+                    android_op_netspeed);
+            return 1;
+        }
+    }
+
+    if (android_parse_network_latency(android_op_netdelay) < 0) {
+        fprintf(stderr, "invalid -netdelay parameter '%s'",
+                android_op_netdelay);
+        return 1;
+    }
+
+    if (android_op_netfast) {
+        android_net_download_speed = 0;
+        android_net_upload_speed = 0;
+        android_net_min_latency = 0;
+        android_net_max_latency = 0;
+    }
+
+    int dns_count = 0;
+    if (android_op_dns_server) {
+        dns_count = slirp_parse_dns_servers(android_op_dns_server);
+        if (dns_count == -2) {
+            // Special case for better user feedback on this error message
+            fprintf(stderr,
+                    "too many servers specified in -dns-server-parameter "
+                    "argument '%s'. A maximum of %d is supported.\n",
+                    android_op_dns_server,
+                    slirp_get_max_dns_servers());
+            return 1;
+        } else if (dns_count < 0) {
+            fprintf(stderr, "invalid -dns-server parameter '%s'\n",
+                    android_op_dns_server);
+            return 1;
+        }
+        if (dns_count == 0) {
+            printf("### WARNING: will use system default DNS server\n");
+        }
+    }
+    if (dns_count == 0) {
+        dns_count = slirp_get_system_dns_servers();
+        if (dns_count < 0) {
+            printf("### WARNING: unable to configure any DNS servers, "
+                   "name resolution will not work\n");
+        }
+    }
+    if (dns_count > 1) {
+        additional_kernel_params = g_strdup_printf("ndns=%d", dns_count);
+    }
+
+#endif // CONFIG_ANDROID
+
     if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
         return 1;
     }
@@ -4070,7 +4523,7 @@
     if (display_type == DT_DEFAULT && !display_remote) {
 #if defined(CONFIG_GTK)
         display_type = DT_GTK;
-#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA) || defined(CONFIG_ANDROID)
         display_type = DT_SDL;
 #elif defined(CONFIG_VNC)
         vnc_display = "localhost:0,to=99";
@@ -4095,7 +4548,12 @@
     }
 #endif
 
+#ifndef CONFIG_ANDROID
+    // When using AndroidEmu, this "main" is no longer the entry point on the
+    // main thread. It is in fact called on a secondary thread, and socket
+    // initialization is long finished (See android-qemu2-glue/main.cpp).
     socket_init();
+#endif
 
     if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0)
         return 1;
@@ -4112,6 +4570,16 @@
 #if defined(CONFIG_HAX)
     uint64_t hax_max_ram = 0;
     if (hax_get_max_ram(&hax_max_ram) == 0 && hax_max_ram > 0) {
+#ifdef CONFIG_ANDROID
+        char str[32] = {0};
+        snprintf(str, sizeof(str) - 1, "%"PRIu64, hax_max_ram);
+        crashhandler_add_string("hax_max_ram.txt", str);
+#endif
+        // current haxm cannot handle more than 3G memory
+        // b.android.com/214422
+        if (hax_max_ram  > 3072LL * 1024 * 1024) {
+            hax_max_ram = 3072LL * 1024 * 1024;
+        }
         if (ram_size > hax_max_ram) {
             const int requested_meg = ram_size / (1024 * 1024);
             const int actual_meg = hax_max_ram / (1024 * 1024);
@@ -4147,6 +4615,7 @@
         return 1;
     }
 
+
     if (qtest_chrdev) {
         Error *local_err = NULL;
         qtest_init(qtest_chrdev, qtest_log, &local_err);
@@ -4191,14 +4660,24 @@
         boot_strict = qemu_opt_get_bool(opts, "strict", false);
     }
 
-    if (!kernel_cmdline) {
-        kernel_cmdline = "";
-        current_machine->kernel_cmdline = (char *)kernel_cmdline;
+    current_machine->kernel_cmdline = kernel_cmdline ? (char *)kernel_cmdline : "";
+
+#ifdef CONFIG_ANDROID
+    if (additional_kernel_params) {
+        char* combined = g_strdup_printf("%s %s",
+                                         current_machine->kernel_cmdline,
+                                         additional_kernel_params);
+        current_machine->kernel_cmdline = combined;
+        // Free the original buffer and put the newly allocated one in there
+        // to make sure it gets deallocated.
+        g_free(additional_kernel_params);
+        additional_kernel_params = combined;
     }
+#endif  // CONFIG_ANDROID
 
     linux_boot = (kernel_filename != NULL);
 
-    if (!linux_boot && *kernel_cmdline != '\0') {
+    if (!linux_boot && *current_machine->kernel_cmdline != '\0') {
         fprintf(stderr, "-append only allowed with -kernel option\n");
         return 1;
     }
@@ -4294,10 +4773,6 @@
 
     set_numa_nodes();
 
-    if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) {
-        exit(1);
-    }
-
     if (foreach_device_config(DEV_SERIAL, serial_parse) < 0)
         return 1;
     if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0)
@@ -4333,6 +4808,74 @@
     if (machine_class->compat_props) {
         qdev_prop_register_global_list(machine_class->compat_props);
     }
+
+#if defined(CONFIG_ANDROID)
+    /* Configure goldfish events device */
+    {
+        bool have_multitouch = androidHwConfig_isScreenMultiTouch(android_hw);
+
+        /* TODO(digit): Should we set this up as command-line parameters
+         * in android-qemu2-glue/main.cpp:main() instead? as in:
+         *
+         *    -set device.goldfish-events.have-dpad=<value>
+         *    -set device.goldfish-events.have-trackball=<value>
+         *    ...
+         */
+
+        // The GlobalProperty values are directly added to a global linked list
+        // so store them in a static array instead of the stack to ensure they
+        // have the proper lifecycle. We then initialize the array with
+        // values computed dynamically.
+#define LIST_GOLDFISH_EVENT_PROPS(X) \
+    X("have-dpad", android_hw->hw_dPad) \
+    X("have-trackball", android_hw->hw_trackBall) \
+    X("have-camera", \
+            strcmp(android_hw->hw_camera_back, "none") || \
+            strcmp(android_hw->hw_camera_front, "none")) \
+    X("have-keyboard", android_hw->hw_keyboard) \
+    X("have-lidswitch", android_hw->hw_keyboard_lid) \
+    X("have-touch", androidHwConfig_isScreenTouch(android_hw)) \
+    X("have-multitouch", have_multitouch)
+
+#define GOLDFISH_DECLARE_PROP(name, value) \
+        { \
+            .driver = "goldfish-events", \
+            .property = name, \
+        },
+
+        static GlobalProperty goldfish_events_properties[] = {
+            LIST_GOLDFISH_EVENT_PROPS(GOLDFISH_DECLARE_PROP) \
+            { /* end of list */ }
+        };
+
+        // Then initialize them.
+#define GOLDFISH_INIT_PROP(name, val)  \
+            goldfish_events_properties[n].value = (val) ? "true" : "false"; \
+            VERBOSE_PRINT(init, \
+                          "goldfish_events.%s: %s", \
+                          goldfish_events_properties[n].property, \
+                          goldfish_events_properties[n].value); \
+            n++;
+
+        int n = 0;
+        LIST_GOLDFISH_EVENT_PROPS(GOLDFISH_INIT_PROP)
+
+#undef GOLDFISH_INIT_PROP
+#undef GOLDFISH_DECLARE_PROP
+
+        qdev_prop_register_global_list(goldfish_events_properties);
+
+        if (have_multitouch) {
+            // in android-qemu2-glue/qemu-user-event-agent-impl.c
+            extern const GoldfishEventMultitouchFuncs
+                    qemu2_goldfish_event_multitouch_funcs;
+
+            goldfish_events_enable_multitouch(
+                    &qemu2_goldfish_event_multitouch_funcs);
+        }
+    }
+#endif  // CONFIG_ANDROID
+
     qemu_add_globals();
 
     qdev_machine_init();
@@ -4344,6 +4887,12 @@
     current_machine->cpu_model = cpu_model;
 
     machine_class->init(current_machine);
+#ifdef CONFIG_ANDROID
+    if (android_init_error_occurred()) {
+        // Something went wrong when initializing the virtual machine
+        return 1;
+    }
+#endif
 
     if (!realtime_init()) {
         return 1;
@@ -4379,6 +4928,16 @@
 
     net_check_clients();
 
+#if defined(CONFIG_ANDROID)
+    /* call android-specific setup function */
+    if (!qemu_android_emulation_setup()) {
+        return 1;
+    }
+
+    extern void android_emulator_set_base_port(int);
+    android_emulator_set_base_port(android_base_port);
+#endif  // CONFIG_ANDROID
+
     ds = init_displaystate();
 
     /* init local displays */
@@ -4391,7 +4950,7 @@
         curses_display_init(ds, full_screen);
         break;
 #endif
-#if defined(CONFIG_SDL)
+#if defined(CONFIG_SDL) || defined(CONFIG_ANDROID)
     case DT_SDL:
         if (!sdl_display_init(ds, full_screen, no_frame)) {
             return 1;
@@ -4449,6 +5008,16 @@
         return 1;
     }
 
+    if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) {
+        return 1;
+    }
+
+#ifdef CONFIG_ANDROID
+    // Parse the System boot parameters from the command line last,
+    // so they take precedence
+    process_cmd_properties();
+#endif  // CONFIG_ANDROID
+
     /* TODO: once all bus devices are qdevified, this should be done
      * when bus is created by qdev.c */
     qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
@@ -4492,7 +5061,22 @@
         }
     }
 
+#ifdef CONFIG_ANDROID
+    // Initialize reporting right before entering main loop.
+    // We want to track performance of a running emulator, ignoring any early
+    // exits as a result of incorrect setup.
+    if (!android_reporting_setup()) {
+        return 1;
+    }
+#endif
+
     main_loop();
+
+#ifdef CONFIG_ANDROID
+    crashhandler_exitmode("after main_loop");
+    android_wear_agent_stop();
+    socket_drainer_stop();
+#endif
     bdrv_close_all();
     pause_all_vcpus();
     res_free();
@@ -4500,5 +5084,9 @@
     tpm_cleanup();
 #endif
 
+#ifdef CONFIG_ANDROID
+    android_reporting_teardown();
+#endif
+
     return 0;
 }