android: vl.c: proper Android support (NO DNS SERVER SUPPORT!)
Change-Id: Iceceabaaf0bdf2130de345b239c2b15e5ba1972c
diff --git a/android-qemu2-glue/build/Makefile.qemu2-glue.mk b/android-qemu2-glue/build/Makefile.qemu2-glue.mk
index 1e2939d..fe850ef 100644
--- a/android-qemu2-glue/build/Makefile.qemu2-glue.mk
+++ b/android-qemu2-glue/build/Makefile.qemu2-glue.mk
@@ -32,6 +32,7 @@
qemu-net-agent-impl.c \
qemu-sensors-agent-impl.c \
qemu-setup.cpp \
+ qemu-setup-dns-servers.cpp \
qemu-telephony-agent-impl.c \
qemu-user-event-agent-impl.c \
qemu-vm-operations-impl.c \
diff --git a/android-qemu2-glue/qemu-setup-dns-servers.cpp b/android-qemu2-glue/qemu-setup-dns-servers.cpp
new file mode 100644
index 0000000..2042334
--- /dev/null
+++ b/android-qemu2-glue/qemu-setup-dns-servers.cpp
@@ -0,0 +1,161 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "android-qemu2-glue/qemu-setup.h"
+
+#include "android/base/Log.h"
+#include "android/utils/debug.h"
+
+#ifdef _WIN32
+// This includes must happen before qemu/osdep.h to avoid compiler
+// errors regarding FD_SETSIZE being redefined.
+#include "android/base/sockets/Winsock.h"
+#include "android/base/sockets/SocketErrors.h"
+#else
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+extern "C" {
+#include "qemu/osdep.h"
+#include "net/slirp.h"
+#include "slirp/libslirp.h"
+} // extern "C"
+
+#include <vector>
+
+#include <errno.h>
+
+// Resolve host name |hostName| into a list of sockaddr_storage.
+// On success, return true and append the names to |*out|. On failure
+// return false, leave |*out| untouched, and sets errno.
+static bool resolveHostNameToList(
+ const char* hostName, std::vector<sockaddr_storage>* out) {
+ addrinfo* res = nullptr;
+ addrinfo hints = {};
+ hints.ai_family = AF_UNSPEC;
+ int ret = ::getaddrinfo(hostName, nullptr, &hints, &res);
+ if (ret != 0) {
+ // Handle errors.
+ int err = 0;
+ switch (ret) {
+ case EAI_AGAIN: // server is down
+ case EAI_FAIL: // server is sick
+ err = EHOSTDOWN;
+ break;
+/* NOTE that in x86_64-w64-mingw32 both EAI_NODATA and EAI_NONAME are the same */
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+ case EAI_NODATA:
+#endif
+ case EAI_NONAME:
+ err = ENOENT;
+ break;
+
+ case EAI_MEMORY:
+ err = ENOMEM;
+ break;
+
+ default:
+ err = EINVAL;
+ }
+ errno = err;
+ return false;
+ }
+
+ int count = 0;
+
+ for (auto r = res; r != nullptr; r = r->ai_next) {
+ sockaddr_storage addr = {};
+ switch (r->ai_family) {
+ case AF_INET:
+ *(struct sockaddr_in *)&addr =
+ *(const struct sockaddr_in *)r->ai_addr;
+ break;
+
+ case AF_INET6:
+ *(struct sockaddr_in6 *)&addr =
+ *(const struct sockaddr_in6 *)r->ai_addr;
+ break;
+ default:
+ continue;
+ }
+ out->emplace_back(std::move(addr));
+ count++;
+ }
+ ::freeaddrinfo(res);
+
+ return (count > 0);
+}
+
+bool qemu_android_emulation_setup_dns_servers(const char* dns_servers,
+ int* pcount4, int* pcount6) {
+ CHECK(net_slirp_state() != nullptr) << "slirp stack should be inited!";
+
+ if (!dns_servers || !dns_servers[0]) {
+ // Empty list, use the default behaviour.
+ return 0;
+ }
+
+ std::vector<sockaddr_storage> server_addresses;
+
+ // Separate individual DNS server names, then resolve each one of them
+ // into one or more IP addresses. Support both IPv4 and IPv6 at the same
+ // time.
+ const char* p = dns_servers;
+ while (*p) {
+ const char* next_p;
+ const char* comma = strchr(p, ',');
+ if (!comma) {
+ comma = p + strlen(p);
+ next_p = comma;
+ } else {
+ next_p = comma + 1;
+ }
+ while (p < comma && *p == ' ') p++;
+ while (p < comma && comma[-1] == ' ') comma--;
+
+ if (comma > p) {
+ // Extract single server name.
+ std::string server(p, comma - p);
+ if (!resolveHostNameToList(server.c_str(), &server_addresses)) {
+ dwarning("Ignoring ivalid DNS address: [%s]\n", server.c_str());
+ }
+ }
+ p = next_p;
+ }
+
+ int count = static_cast<int>(server_addresses.size());
+ if (!count) {
+ return 0;
+ }
+
+ slirp_init_custom_dns_servers(static_cast<Slirp*>(net_slirp_state()),
+ &server_addresses[0], count);
+
+ // Count number of IPv4 and IPv6 DNS servers.
+ int count4 = 0;
+ int count6 = 0;
+ for (const auto& item : server_addresses) {
+ if (item.ss_family == AF_INET) {
+ count4 += 1;
+ } else if (item.ss_family == AF_INET6) {
+ count6 += 1;
+ }
+ }
+
+ *pcount4 = count4;
+ *pcount6 = count6;
+
+ return true;
+}
diff --git a/android-qemu2-glue/qemu-setup.h b/android-qemu2-glue/qemu-setup.h
index 7bd3f45..5c57b32 100644
--- a/android-qemu2-glue/qemu-setup.h
+++ b/android-qemu2-glue/qemu-setup.h
@@ -26,6 +26,15 @@
* main thread. Return true on success, false otherwise. */
extern bool qemu_android_emulation_early_setup(void);
+/* Call this function to setup a list of custom DNS servers to be used
+ * by the network stack. |dns_servers| must be the content of the
+ * -dns-server option, i.e. a comma-separated list of DNS server addresses.
+ * On success, return true and set |*count4| and |*count6| to the number
+ * of IPv4 and IPv6 IP addresses, respectively. Return false on failure. */
+extern bool qemu_android_emulation_setup_dns_servers(const char* dns_servers,
+ int* count4,
+ int* count6);
+
/* Call this function after the QEMU main() function has inited the
* machine, but before it has started it. */
extern bool qemu_android_emulation_setup(void);
diff --git a/vl.c b/vl.c
old mode 100644
new mode 100755
index 4a8de9c..5f056a3
--- a/vl.c
+++ b/vl.c
@@ -70,6 +70,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"
@@ -126,8 +127,73 @@
#include "qapi/qmp/qerror.h"
#ifdef CONFIG_ANDROID
+
+#undef socket_connect
+#undef socket_listen
+
+#include "android/android.h"
+#include "android/boot-properties.h"
+#include "android/crashreport/crash-handler.h"
+#include "android/emulation/bufprint_config_dirs.h"
+#include "android/error-messages.h"
+#include "android/globals.h"
+#include "android/gps.h"
+#include "android/help.h"
+#include "android/hw-control.h"
+#include "android/hw-qemud.h"
+#include "android/main-common.h"
+#include "android/metrics/metrics.h"
+#include "android/multitouch-port.h"
+#include "android/network/control.h"
+#include "android/network/globals.h"
+#include "android/opengl/emugl_config.h"
+#include "android/skin/winsys.h"
+#include "android/snapshot.h"
+#include "android/snaphost-android.h"
+#include "android/telephony/modem_driver.h"
+#include "android/update-check/update_check.h"
+#include "android/ui-emu-agent.h"
+#include "android/utils/async.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+#include "android/utils/filelock.h"
+#include "android/utils/ini.h"
+#include "android/utils/lineinput.h"
+#include "android/utils/path.h"
+#include "android/utils/property_file.h"
+#include "android/utils/socket_drainer.h"
+#include "android/utils/tempfile.h"
+#include "android/version.h"
+#include "android/wear-agent/android_wear_agent.h"
+#include "android-qemu2-glue/android_qemud.h"
+#include "android-qemu2-glue/looper-qemu.h"
+#include "android-qemu2-glue/qemu-control-impl.h"
#include "android-qemu2-glue/qemu-setup.h"
-#endif
+#include "android/camera/camera-service.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
+
+/////////////////////////////////////////////////////////////
+
+#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 MAX_VIRTIO_CONSOLES 1
#define MAX_SCLP_CONSOLES 1
@@ -171,6 +237,18 @@
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;
+int lcd_density = LCD_DENSITY_MDPI;
+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;
@@ -513,6 +591,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
*
@@ -1927,7 +2037,7 @@
static void version(void)
{
- printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", "
+ printf("QEMU emulator version " QEMU_VERSION " " QEMU_PKGVERSION ", "
QEMU_COPYRIGHT "\n");
}
@@ -2081,7 +2191,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;
@@ -2701,12 +2811,12 @@
machine_init_done = true;
}
-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((const char**)argv, optind, 1);
@@ -2943,12 +3053,61 @@
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()
+{
+ android_metrics_start(EMULATOR_VERSION_STRING,
+ EMULATOR_FULL_VERSION_STRING,
+ QEMU_VERSION,
+ android_base_port);
+ android_metrics_report_common_info(is_opengl_alive);
+}
+
+static void android_teardown_metrics()
+{
+ android_metrics_stop();
+}
+
+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;
const char *initrd_filename;
const char *kernel_filename, *kernel_cmdline;
+ char *additional_kernel_params = NULL;
const char *boot_order = NULL;
const char *boot_once = NULL;
DisplayState *ds;
@@ -2981,9 +3140,7 @@
bool list_data_dirs = false;
#ifdef CONFIG_ANDROID
- if (!qemu_android_emulation_early_setup()) {
- return 1;
- }
+ char* android_op_dns_server = NULL;
#endif
qemu_init_cpu_loop();
@@ -4011,6 +4168,65 @@
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);
}
@@ -4040,6 +4256,163 @@
return 1;
}
+#ifdef CONFIG_ANDROID
+
+ if (!qemu_android_emulation_early_setup()) {
+ return 1;
+ }
+
+ /* 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;
+ }
+ graphic_width = width;
+ graphic_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_network_set_speed(android_op_netspeed) < 0) {
+ fprintf(stderr, "invalid -netspeed parameter '%s'\n",
+ android_op_netspeed);
+ return 1;
+ }
+ }
+
+ if (android_network_set_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;
+ }
+
+#endif // CONFIG_ANDROID
+
+
if (qemu_opts_foreach(qemu_find_opts("sandbox"),
parse_sandbox, NULL, NULL)) {
return 1;
@@ -4251,7 +4624,7 @@
if (display_type == DT_DEFAULT && !display_remote) {
#if defined(CONFIG_GTK)
display_type = DT_GTK;
-#elif defined(CONFIG_SDL)
+#elif defined(CONFIG_SDL) || defined(CONFIG_ANDROID)
display_type = DT_SDL;
#elif defined(CONFIG_COCOA)
display_type = DT_COCOA;
@@ -4289,7 +4662,13 @@
}
page_size_init();
+
+#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("object"),
user_creatable_add_opts_foreach,
@@ -4360,14 +4739,26 @@
boot_order = machine_class->default_boot_order;
}
- if (!kernel_cmdline) {
- kernel_cmdline = "";
- current_machine->kernel_cmdline = (char *)kernel_cmdline;
+ current_machine->kernel_cmdline =
+ g_strdup(kernel_cmdline ? kernel_cmdline : "");
+
+#ifdef CONFIG_ANDROID
+ if (additional_kernel_params) {
+ char* combined = g_strdup_printf("%s %s",
+ current_machine->kernel_cmdline,
+ additional_kernel_params);
+ g_free(current_machine->kernel_cmdline);
+ 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') {
error_report("-append only allowed with -kernel option");
return 1;
}
@@ -4384,7 +4775,8 @@
if (semihosting_enabled() && !semihosting_get_argc() && kernel_filename) {
/* fall back to the -kernel/-append */
- semihosting_arg_fallback(kernel_filename, kernel_cmdline);
+ semihosting_arg_fallback(kernel_filename,
+ current_machine->kernel_cmdline);
}
os_set_line_buffering();
@@ -4414,6 +4806,24 @@
return 1;
}
+#ifdef CONFIG_ANDROID
+ int dns_count = 0;
+ int dns6_count = 0;
+ if (0 && android_op_dns_server) {
+ if (!qemu_android_emulation_setup_dns_servers(
+ android_op_dns_server, &dns_count, &dns6_count)) {
+ fprintf(stderr, "invalid -dns-server parameter '%s'\n",
+ android_op_dns_server);
+ return 1;
+ }
+ // TODO: Find a way to pass the number of IPv6 DNS servers to
+ // the guest system.
+ if (dns_count > 1) {
+ additional_kernel_params = g_strdup_printf("ndns=%d", dns_count);
+ }
+ }
+#endif
+
if (qemu_opts_foreach(qemu_find_opts("object"),
user_creatable_add_opts_foreach,
object_create_delayed, NULL)) {
@@ -4509,6 +4919,78 @@
qemu_opts_foreach(qemu_find_opts("global"),
global_init_func, NULL, NULL);
+#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);
+ }
+ }
+
+ // Parse the System boot parameters from the command line last,
+ // so they take precedence
+ process_cmd_properties();
+
+#endif // CONFIG_ANDROID
+
/* This checkpoint is required by replay to separate prior clock
reading from the other reads, because timer polling functions query
clock values from the log. */
@@ -4530,7 +5012,10 @@
if (!qemu_android_emulation_setup()) {
return 1;
}
-#endif
+
+ extern void android_emulator_set_base_port(int);
+ android_emulator_set_base_port(android_base_port);
+#endif // CONFIG_ANDROID
if (!realtime_init()) {
return 1;
@@ -4670,10 +5155,25 @@
os_setup_post();
+#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 // CONFIG_ANDROID
+
trace_init_vcpu_events();
main_loop();
replay_disable_events();
+#ifdef CONFIG_ANDROID
+ crashhandler_exitmode("after main_loop");
+ android_wear_agent_stop();
+ socket_drainer_stop();
+#endif
+
bdrv_close_all();
pause_all_vcpus();
res_free();
@@ -4683,6 +5183,7 @@
#ifdef CONFIG_ANDROID
qemu_android_emulation_teardown();
+ android_reporting_teardown();
#endif
/* vhost-user must be cleaned up before chardevs. */