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; }