merge from tools_r10

Change-Id: I70d9ccafb5912c85baa0711f7e9010bec223efaa
diff --git a/Makefile b/Makefile
index 7b23968..053525c 100644
--- a/Makefile
+++ b/Makefile
@@ -13,17 +13,28 @@
 # limitations under the License.
 #
 
+# disable implicit rules
+.SUFFIXES:
+%:: %,v
+%:: RCS/%
+%:: RCS/%,v
+%:: s.%
+%:: SCCS/s.%
+%.c: %.w %.ch
+
+
 # this is a set of definitions that allow the usage of Makefile.android
 # even if we're not using the Android build system.
 #
 
 BUILD_SYSTEM := android/build
 OBJS_DIR     := objs
+LIBS_DIR     := $(OBJS_DIR)/libs
 CONFIG_MAKE  := $(OBJS_DIR)/config.make
 CONFIG_H     := $(OBJS_DIR)/config-host.h
 
 ifeq ($(wildcard $(CONFIG_MAKE)),)
-    $(error "The configuration file '$(CONFIG_MAKE)' doesnt' exist, please run the "rebuilt.sh" script)
+    $(error "The configuration file '$(CONFIG_MAKE)' doesnt' exist, please run the "android-configure.sh" script)
 endif
 
 include $(CONFIG_MAKE)
diff --git a/Makefile.android b/Makefile.android
index 1b44140..4b6e211 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -17,7 +17,6 @@
 # determine the location of platform-specific directories
 #
 CONFIG_DIRS     := \
-    $(LOCAL_PATH)/android/config \
     $(LOCAL_PATH)/android/config/$(QEMU_HOST_TAG)
 
 ifeq ($(BUILD_STANDALONE_EMULATOR),true)
@@ -26,7 +25,9 @@
 
 CONFIG_INCLUDES := $(CONFIG_DIRS:%=-I%)
 
-MY_CC := $(HOST_CC)
+MY_CC  := $(HOST_CC)
+MY_CXX := $(HOST_CXX)
+MY_AR  := $(HOST_AR)
 
 MY_OPTIM := -O2 -g -fno-PIC -falign-functions=0 -fomit-frame-pointer
 ifeq ($(BUILD_DEBUG_EMULATOR),true)
@@ -42,13 +43,6 @@
                  -fno-PIC -falign-functions=0
 endif
 
-MY_CFLAGS += -DCONFIG_MEMCHECK
-
-# prepare config.h for x86
-ifeq ($(TARGET_ARCH),x86)
-MY_CFLAGS += -DARCH_FLAGS_x86
-endif
-
 MY_LDLIBS :=
 
 # this is needed to build the emulator on 64-bit Linux systems
@@ -96,9 +90,22 @@
 # adequate values for HOST_CC
 #
 ifneq ($(BUILD_STANDALONE_EMULATOR),true)
+  # On Linux, use our custom 32-bit host toolchain, which contains the
+  # relevant headers and 32-bit libraries for audio (The host 64-bit Lucid
+  # doesn't provide these anymore, only their 64-bit versions).
+  ifeq ($(HOST_OS),linux)
+    HOST_SDK_TOOLCHAIN_PREFIX := prebuilt/linux-x86/toolchain/i686-linux-glibc2.7-4.4.3/bin/i686-linux
+    # Don't do anything if the toolchain is not there
+    ifneq (,$(strip $(wildcard $(HOST_SDK_TOOLCHAIN_PREFIX)-gcc)))
+      MY_CC  := $(HOST_SDK_TOOLCHAIN_PREFIX)-gcc
+      MY_CXX := $(HOST_SDK_TOOLCHAIN_PREFIX)-g++
+      MY_AR  := $(HOST_SDK_TOOLCHAIN_PREFIX)-ar
+    endif # $(HOST_SDK_TOOLCHAIN_PREFIX)-gcc exists
+  endif # HOST_OS == linux
 
   ifneq ($(USE_CCACHE),)
     ccache := prebuilt/$(HOST_PREBUILT_TAG)/ccache/ccache
+    ccache := $(strip $(wildcard $(ccache)))
     ifneq ($(ccache),$(firstword $(MY_CC)))
       MY_CC := $(ccache) $(MY_CC)
     endif
@@ -119,751 +126,43 @@
 #
 MY_CFLAGS += -Wall -Wno-missing-field-initializers
 
-include $(CLEAR_VARS)
+# Needed to build fpu/softfloat-native.h properly
+MY_CFLAGS += -D_GNU_SOURCE=1
 
-###########################################################
-# Zlib configuration
+# A useful function that can be used to start the declaration of a host
+# module. Avoids repeating the same stuff again and again.
+# Usage:
 #
-ZLIB_DIR := distrib/zlib-1.2.3
-include $(LOCAL_PATH)/$(ZLIB_DIR)/sources.make
-
-###########################################################
-# Libpng configuration
+#  $(call start-emulator-library, <module-name>)
 #
-LIBPNG_DIR := distrib/libpng-1.2.19
-include $(LOCAL_PATH)/$(LIBPNG_DIR)/sources.make
-
-###############################################################################
-# build the TCG code generator
+#  ... declarations
 #
-include $(CLEAR_VARS)
-
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_CFLAGS                    := $(MY_CFLAGS) $(LOCAL_CFLAGS)
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-LOCAL_MODULE                    := emulator-tcg
-
-TCG_TARGET := $(HOST_ARCH)
-ifeq ($(TCG_TARGET),x86)
-  TCG_TARGET := i386
-endif
-
-TCG_CFLAGS := -I$(LOCAL_PATH)/tcg -I$(LOCAL_PATH)/tcg/$(TCG_TARGET)
-
-LOCAL_CFLAGS += $(TCG_CFLAGS) -DNEED_CPU_H \
-                -I$(LOCAL_PATH)/$(EMULATOR_TARGET_CPU) \
-                -I$(LOCAL_PATH)/fpu \
-
-LOCAL_SRC_FILES := \
-    tcg/tcg.c \
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-##############################################################################
-# build the HW emulation support
+#  $(call end-emulator-library)
 #
-include $(CLEAR_VARS)
+start-emulator-library = \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_NO_DEFAULT_COMPILER_FLAGS := true) \
+    $(eval LOCAL_CC := $(MY_CC)) \
+    $(eval LOCAL_CXX := $(MY_CXX)) \
+    $(eval LOCAL_CFLAGS := $(MY_CFLAGS)) \
+    $(eval LOCAL_AR := $(MY_AR)) \
+    $(eval LOCAL_LDLIBS := $(MY_LDLIBS)) \
+    $(eval LOCAL_MODULE_TAGS := debug) \
+    $(eval LOCAL_MODULE := $1)
 
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-LOCAL_MODULE                    := emulator-hw
+# Used with start-emulator-library
+end-emulator-library = \
+    $(eval include $(BUILD_HOST_STATIC_LIBRARY))
 
-HW_CFLAGS    := -I$(LOCAL_PATH)/hw
+# A variant of start-emulator-library to start the definition of a host
+# program instead. Use with end-emulator-program
+start-emulator-program = $(call start-emulator-library,$1)
 
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) -DNEED_CPU_H
-LOCAL_CFLAGS += -I$(LOCAL_PATH)/$(EMULATOR_TARGET_CPU) -I$(LOCAL_PATH)/fpu $(HW_CFLAGS)
-LOCAL_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
-
-HW_SOURCES := \
-    bt.c \
-    bt-hci.c \
-    bt-hid.c \
-    bt-l2cap.c \
-    bt-sdp.c \
-    cdrom.c \
-    dma.c \
-    irq.c \
-    goldfish_device.c \
-    goldfish_events_device.c \
-    goldfish_fb.c \
-    goldfish_battery.c \
-    goldfish_mmc.c   \
-    goldfish_memlog.c \
-    goldfish_nand.c \
-    goldfish_tty.c \
-    msmouse.c \
-    pci.c \
-    qdev.c \
-    scsi-disk.c \
-    sysbus.c \
-    usb-hid.c \
-    usb-hub.c \
-    usb-msd.c \
-    usb-ohci.c \
-    usb.c \
-    watchdog.c \
-
-ifeq ($(TARGET_ARCH),arm)
-HW_SOURCES += android_arm.c \
-    arm_pic.c \
-    smc91c111.c \
-    goldfish_audio.c \
-    goldfish_interrupt.c \
-    goldfish_switch.c \
-    goldfish_timer.c \
-    goldfish_trace.c \
-
-endif
-
-ifeq ($(TARGET_ARCH),x86)
-HW_SOURCES += pc.c \
-    apic.c \
-    i8259.c \
-    mc146818rtc.c \
-    piix_pci.c \
-    i8254.c \
-    ne2000.c \
-    pckbd.c \
-    ioapic.c \
-    ps2.c \
-    smbios.c \
-    fw_cfg.c \
-
-endif
-
-LOCAL_SRC_FILES += $(HW_SOURCES:%=hw/%)
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-##############################################################################
-# build the ELF/DWARF stuff
-# This library is used by emulator's memory checker to extract debug information
-# from the symbol files when reporting memory allocation violations. In
-# particular, this library is used to extract routine name and source file
-# location for the code address where violation has been detected.
-#
-include $(CLEAR_VARS)
-
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-LOCAL_MODULE                    := emulator-elff
-LOCAL_CPP_EXTENSION             := .cc
-
-ELFF_CFLAGS    := -I$(LOCAL_PATH)/elff
-
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) -fno-exceptions
-LOCAL_CFLAGS += -I$(LOCAL_PATH)/$(EMULATOR_TARGET_CPU) -I$(LOCAL_PATH)/fpu $(ELFF_CFLAGS)
-LOCAL_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
-
-ELFF_SOURCES := \
-    dwarf_cu.cc \
-    dwarf_die.cc \
-    dwarf_utils.cc \
-    elf_alloc.cc \
-    elf_file.cc \
-    elf_mapped_section.cc \
-    elff_api.cc \
-
-LOCAL_SRC_FILES += $(ELFF_SOURCES:%=elff/%)
-ELFF_LDLIBS := -lstdc++
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-##############################################################################
-# build the memory access checking support
-# Memory access checker uses information collected by instrumented code in
-# libc.so in order to keep track of memory blocks allocated from heap. Memory
-# checker then uses this information to make sure that every access to allocated
-# memory is within allocated block. This information also allows detecting
-# memory leaks and attempts to free/realloc invalid pointers.
-#
-include $(CLEAR_VARS)
-
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-LOCAL_MODULE                    := emulator-memcheck
-
-MCHK_CFLAGS    := -I$(LOCAL_PATH)/memcheck -I$(LOCAL_PATH)/elff
-
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) -DNEED_CPU_H
-LOCAL_CFLAGS += -I$(LOCAL_PATH)/$(EMULATOR_TARGET_CPU) -I$(LOCAL_PATH)/fpu $(MCHK_CFLAGS)
-LOCAL_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
-
-MCHK_SOURCES := \
-    memcheck.c \
-    memcheck_proc_management.c \
-    memcheck_malloc_map.c \
-    memcheck_mmrange_map.c \
-    memcheck_util.c \
-
-LOCAL_SRC_FILES += $(MCHK_SOURCES:%=memcheck/%)
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-##############################################################################
-# build the CPU-specific emulation engine sources
-#
-include $(CLEAR_VARS)
-
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_MODULE			:= emulator-arm
-endif
-ifeq ($(TARGET_ARCH),x86)
-LOCAL_MODULE			:= emulator-i386
-LOCAL_MODULE_TAGS		:= optional
-endif
-
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_MODULE                    := $(LOCAL_MODULE)
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-LOCAL_CFLAGS                    := $(MY_CFLAGS) $(LOCAL_CFLAGS)
-LOCAL_STATIC_LIBRARIES          := emulator-hw
-
-LOCAL_CFLAGS := -fno-PIC -fomit-frame-pointer -Wno-sign-compare
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
-
-LOCAL_CFLAGS += -I$(LOCAL_PATH) \
-                -I$(LOCAL_PATH)/$(EMULATOR_TARGET_CPU) \
-                -I$(LOCAL_PATH)/fpu \
-                $(TCG_CFLAGS) \
-                $(HW_CFLAGS) \
-                -DNEED_CPU_H \
-
-ifeq ($(HOST_ARCH),ppc)
-    LOCAL_CFLAGS += -D__powerpc__
-endif
-
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += exec.c cpu-exec.c  \
-                   $(EMULATOR_TARGET_CPU)/op_helper.c \
-                   $(EMULATOR_TARGET_CPU)/iwmmxt_helper.c \
-                   $(EMULATOR_TARGET_CPU)/neon_helper.c \
-                   $(EMULATOR_TARGET_CPU)/helper.c \
-                   $(EMULATOR_TARGET_CPU)/translate.c \
-                   $(EMULATOR_TARGET_CPU)/machine.c \
-                   translate-all.c \
-                   hw/armv7m.c \
-                   hw/armv7m_nvic.c \
-                   arm-semi.c \
-                   trace.c \
-                   varint.c \
-                   dcache.c \
-                   softmmu_outside_jit.c \
-
-LOCAL_SRC_FILES += fpu/softfloat.c
-endif
-
-ifeq ($(TARGET_ARCH), x86)
-LOCAL_SRC_FILES += exec.c cpu-exec.c  \
-                   $(EMULATOR_TARGET_CPU)/op_helper.c \
-                   $(EMULATOR_TARGET_CPU)/helper.c \
-                   $(EMULATOR_TARGET_CPU)/translate.c \
-                   $(EMULATOR_TARGET_CPU)/machine.c \
-                   translate-all.c \
-                   trace.c \
-                   varint.c \
-                   dcache.c \
-                   softmmu_outside_jit.c \
-
-LOCAL_SRC_FILES += fpu/softfloat-native.c
-endif
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-##############################################################################
-# SDL-related definitions
-#
-
-# Build SDL from sources except on linux-x86, to avoid installing all
-# the X11 development packages on our build servers.
-#
-BUILD_SDL_FROM_SOURCES := true
-ifeq ($(QEMU_HOST_TAG),linux-x86)
-    BUILD_SDL_FROM_SOURCES := false
-endif
-ifeq ($(QEMU_HOST_TAG),darwin-x86)
-    BUILD_SDL_FROM_SOURCES := false
-endif
-ifeq ($(BUILD_STANDALONE_EMULATOR),true)
-    BUILD_SDL_FROM_SOURCES := true
-endif
-
-ifneq ($(SDL_CONFIG),)
-    BUILD_SDL_FROM_SOURCES := false
-endif
-
-ifneq ($(BUILD_SDL_FROM_SOURCES),true)
-
-SDL_CONFIG ?= prebuilt/$(QEMU_HOST_TAG)/sdl/bin/sdl-config
-SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags)
-
-# We need to filter out the _GNU_SOURCE variable because it breaks recent
-# releases of Cygwin when using the -mno-cygwin option. Moreover, we don't
-# need this macro at all to build the Android emulator.
-SDL_CFLAGS := $(filter-out -D_GNU_SOURCE=1,$(SDL_CFLAGS))
-SDL_LDLIBS := $(filter-out %.a %.lib,$(shell $(SDL_CONFIG) --static-libs))
-
-# Circular dependencies between libSDL and libSDLmain;
-# We repeat the libraries in the final link to work around it.
-SDL_STATIC_LIBRARIES := libSDL libSDLmain libSDL libSDLmain
-
-else   # !BUILD_STANDALONE_EMULATOR
-
-SDL_DIR := distrib/sdl-1.2.12
-include $(LOCAL_PATH)/$(SDL_DIR)/sources.make
-
-endif  # !BUILD_STANDALONE_EMULATOR
-
-##############################################################################
-# determine audio sources, build the prebuilt audio-library if needed
-#
-
-# determine AUDIO sources based on current configuration
-#
-AUDIO_SOURCES := audio.c noaudio.c wavaudio.c wavcapture.c mixeng.c
-AUDIO_CFLAGS  := -I$(LOCAL_PATH)/audio -DHAS_AUDIO
-AUDIO_LDLIBS  :=
-
-ifeq ($(HOST_OS),darwin)
-  CONFIG_COREAUDIO ?= yes
-  AUDIO_CFLAGS += -DHOST_BSD=1
-endif
-
-ifeq ($(HOST_OS),windows)
-  CONFIG_WINAUDIO ?= yes
-endif
-
-ifeq ($(HOST_OS),linux)
-  CONFIG_OSS  ?= yes
-  CONFIG_ALSA ?= yes
-  CONFIG_PULSEAUDIO ?= yes
-  CONFIG_ESD  ?= yes
-endif
-
-ifeq ($(HOST_OS),freebsd)
-  CONFIG_OSS ?= yes
-endif
-
-ifeq ($(CONFIG_COREAUDIO),yes)
-  AUDIO_SOURCES += coreaudio.c
-  AUDIO_CFLAGS  += -DCONFIG_COREAUDIO
-  AUDIO_LDLIBS  += -Wl,-framework,CoreAudio
-endif
-
-ifeq ($(CONFIG_WINAUDIO),yes)
-  AUDIO_SOURCES += winaudio.c
-  AUDIO_CFLAGS  += -DCONFIG_WINAUDIO
-endif
-
-ifeq ($(CONFIG_PULSEAUDIO),yes)
-  AUDIO_SOURCES += paaudio.c audio_pt_int.c
-  AUDIO_CFLAGS  += -DCONFIG_PULSEAUDIO
-endif
-
-ifeq ($(CONFIG_ALSA),yes)
-  AUDIO_SOURCES += alsaaudio.c audio_pt_int.c
-  AUDIO_CFLAGS  += -DCONFIG_ALSA
-endif
-
-ifeq ($(CONFIG_ESD),yes)
-  AUDIO_SOURCES += esdaudio.c
-  AUDIO_CFLAGS  += -DCONFIG_ESD
-endif
-
-ifeq ($(CONFIG_OSS),yes)
-  AUDIO_SOURCES += ossaudio.c
-  AUDIO_CFLAGS  += -DCONFIG_OSS
-endif
-
-AUDIO_SOURCES := $(call sort,$(AUDIO_SOURCES:%=audio/%))
-
-# determine whether we're going to use the prebuilt
-# audio library (this is useful on Linux to avoid requiring
-# all sound-related development packages to be installed on
-# the build and developer machines).
-#
-# note that you can define BUILD_QEMU_AUDIO_LIB to true
-# in your environment to force recompilation.
-#
-QEMU_AUDIO_LIB :=
-
-ifneq ($(BUILD_STANDALONE_EMULATOR),true)
-  QEMU_AUDIO_LIB := $(wildcard \
-	prebuilt/$(QEMU_HOST_TAG)/emulator/libqemu-audio.a)
-endif
-
-ifeq ($(BUILD_QEMU_AUDIO_LIB),true)
-  include $(CLEAR_VARS)
-  LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-  LOCAL_CC                        := $(MY_CC)
-  LOCAL_MODULE                    := libqemu-audio
-  LOCAL_LDLIBS                    := $(MY_LDLIBS)
-
-  LOCAL_CFLAGS := -Wno-sign-compare \
-                  -fno-strict-aliasing -W -Wall -Wno-unused-parameter \
-                  -I$(LOCAL_PATH) \
-                  -I$(LOCAL_PATH)/$(EMULATOR_TARGET_CPU) \
-                  -I$(LOCAL_PATH)/fpu \
-
-  # this is very important, otherwise the generated binaries may
-  # not link properly on our build servers
-  ifeq ($(HOST_OS),linux)
-    LOCAL_CFLAGS += -fno-stack-protector
-  endif
-
-  LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) $(AUDIO_CFLAGS)
-
-  LOCAL_CFLAGS += $(SDL_CFLAGS)
-
-  LOCAL_SRC_FILES += $(AUDIO_SOURCES)
-
-  include $(BUILD_HOST_STATIC_LIBRARY)
-  QEMU_AUDIO_LIB := $(LOCAL_BUILT_MODULE)
-
-endif  # !QEMU_AUDIO_LIB
-
-##############################################################################
-# Common CFLAGS for UI and Core builds
-
-# add the build ID to the default macro definitions
-UI_AND_CORE_CFLAGS := -DANDROID_BUILD_ID="$(strip $(BUILD_ID))-$(strip $(BUILD_NUMBER))"
-
-# For non-standalone builds, extract the major version number from the Android SDK
-# tools revision number.
-ifneq ($(BUILD_STANDALONE_EMULATOR),true)
-    ANDROID_SDK_TOOLS_REVISION := $(shell awk -F= '/Pkg.Revision/ { print $$2; }' sdk/files/tools_source.properties)
-endif
-
-ANDROID_SDK_TOOLS_REVISION := $(strip $(ANDROID_SDK_TOOLS_REVISION))
-ifdef ANDROID_SDK_TOOLS_REVISION
-    UI_AND_CORE_CFLAGS += -DANDROID_SDK_TOOLS_REVISION=$(ANDROID_SDK_TOOLS_REVISION)
-endif
-
-UI_AND_CORE_CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-
-
-##############################################################################
-# Build emulator core library.
-# This library contains "pure" emulation code separated from the intricacies
-# of the UI.
-#
-include $(CLEAR_VARS)
-
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-LOCAL_MODULE                    := emulator-core
-
-# don't remove the -fno-strict-aliasing, or you'll break things
-# (e.g. slirp-android/network support)
-#
-EMULATOR_CORE_CFLAGS := -fno-PIC -Wno-sign-compare \
-                -fno-strict-aliasing -g -W -Wall -Wno-unused-parameter
-
-# Needed by the upstream code
-EMULATOR_CORE_CFLAGS += -DNEED_CPU_H
-
-# Common includes for the emulator
-EMULATOR_CORE_CFLAGS += -I$(LOCAL_PATH)/ \
-                        -I$(LOCAL_PATH)/$(EMULATOR_TARGET_CPU) \
-                        -I$(LOCAL_PATH)/fpu \
-                        $(TCG_CFLAGS) \
-                        $(HW_CFLAGS) \
-
-# Required by block.c, default value is empty in upstream
-EMULATOR_CORE_CFLAGS += -DCONFIG_BDRV_WHITELIST=""
-
-# Required
-EMULATOR_CORE_CFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE=1
-# include slirp-android code, i.e. the user-level networking stuff
-#
-SLIRP_SOURCES := bootp.c     cksum.c      debug.c  if.c     ip_icmp.c  ip_input.c   ip_output.c  \
-                 mbuf.c      misc.c       sbuf.c   slirp.c  socket.c   tcp_input.c  tcp_output.c \
-                 tcp_subr.c  tcp_timer.c  tftp.c   udp.c
-
-LOCAL_SRC_FILES += $(SLIRP_SOURCES:%=slirp-android/%)
-EMULATOR_CORE_CFLAGS += -I$(LOCAL_PATH)/slirp-android
-
-# socket proxy support
-#
-PROXY_SOURCES := \
-    proxy_common.c \
-    proxy_http.c \
-    proxy_http_connector.c \
-    proxy_http_rewriter.c \
-
-LOCAL_SRC_FILES += $(PROXY_SOURCES:%=proxy/%)
-EMULATOR_CORE_CFLAGS += -I$(LOCAL_PATH)/proxy
-
-# include telephony stuff
-#
-TELEPHONY_SOURCES := android_modem.c modem_driver.c gsm.c sim_card.c sysdeps_qemu.c sms.c remote_call.c
-LOCAL_SRC_FILES += $(TELEPHONY_SOURCES:%=telephony/%)
-EMULATOR_CORE_CFLAGS += -I$(LOCAL_PATH)/telephony
-
-# include android related stuff
-#
-ANDROID_SOURCES := qemu-setup.c
-LOCAL_SRC_FILES += $(ANDROID_SOURCES:%=android/%)
-
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) $(EMULATOR_CORE_CFLAGS)
-LOCAL_CFLAGS += $(UI_AND_CORE_CFLAGS)
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-##############################################################################
-# Build emulator UI library.
-# This library contains some emulator related UI components.
-#
-include $(CLEAR_VARS)
-
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-LOCAL_MODULE                    := emulator-uilib
-
-EMULATOR_UI_CFLAGS :=
-
-# include the SDL sources
-#
-
-# IMPORTANT: Normally, we should add SDLMAIN_SOURCES here, however this breaks
-#            the Linux mingw32 build. Apparently, the i586-mingw32-ld wants the
-#            implementation of _WinMain@16 to be in an object file on the final
-#            link command used to generate the executable, and will not search
-#            in the static libraries that are used to build it.
-#
-LOCAL_SRC_FILES += $(SDL_SOURCES) #$(SDLMAIN_SOURCES)
-EMULATOR_UI_CFLAGS += $(SDL_CFLAGS) -I$(LOCAL_PATH)/$(SDL_DIR)/include
-
-# the skin support sources
-#
-SKIN_SOURCES := rect.c \
-                region.c \
-                image.c \
-                trackball.c \
-                keyboard.c \
-                keyset.c \
-                file.c \
-                window.c \
-                scaler.c \
-                composer.c \
-                surface.c \
-
-LOCAL_SRC_FILES += $(SKIN_SOURCES:%=android/skin/%)
-EMULATOR_UI_CFLAGS += -I$(LOCAL_PATH)/skin
-
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) $(EMULATOR_CORE_CFLAGS) $(EMULATOR_UI_CFLAGS)
-
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-##############################################################################
-# lists of source files used to build the emulator core
-#
-
-# block sources
-#
-CORE_BLOCK_SOURCES = block.c \
-                     blockdev.c \
-                     block/qcow.c \
-                     block/qcow2.c \
-                     block/qcow2-refcount.c \
-                     block/qcow2-snapshot.c \
-                     block/qcow2-cluster.c \
-                     block/cloop.c \
-                     block/dmg.c \
-                     block/vvfat.c \
-                     block/raw.c
-ifeq ($(HOST_OS),windows)
-  CORE_BLOCK_SOURCES += block/raw-win32.c
-else
-  CORE_BLOCK_SOURCES += block/raw-posix.c
-endif
-
-# hw sources
-#
-ifeq ($(TARGET_ARCH),arm)
-CORE_HW_SOURCES = hw/arm_boot.c \
-                  hw/android_arm.c
-endif
-
-ifeq ($(TARGET_ARCH),x86)
-CORE_HW_SOURCES = hw/pc.c
-endif
-
-# migration sources
-#
-CORE_MIGRATION_SOURCES = iolooper-select.c
-ifeq ($(HOST_OS),windows)
-  CORE_MIGRATION_SOURCES += migration-dummy-android.c
-else
-  CORE_MIGRATION_SOURCES += migration.c \
-                            migration-exec.c \
-                            migration-tcp-android.c
-endif
-
-# misc. sources
-#
-CORE_MISC_SOURCES = vl-android.c \
-                    async.c \
-                    console.c \
-                    qemu-malloc.c \
-                    cutils.c \
-                    osdep.c \
-                    loader.c \
-                    monitor.c \
-                    readline.c \
-                    qemu-char-android.c \
-                    outputchannel.c \
-                    qemu-error.c \
-                    qerror.c \
-                    disas.c \
-                    aes.c \
-                    d3des.c \
-                    vnc-android.c \
-                    acl.c \
-                    keymaps.c \
-                    buffered_file.c \
-                    cbuffer.c \
-                    gdbstub.c \
-                    input.c \
-                    ioport.c \
-                    notify.c \
-                    path.c \
-                    shaper.c \
-                    charpipe.c \
-                    tcpdump.c \
-                    qemu-option.c \
-                    savevm.c \
-                    net-android.c \
-                    aio-android.c \
-                    dma-helpers.c \
-                    qemu-config.c \
-                    qemu-sockets-android.c \
-                    bt-host.c \
-                    bt-vhci.c \
-                    module.c \
-                    qemu-timer.c \
-                    android/boot-properties.c \
-                    android/hw-kmsg.c \
-                    android/hw-lcd.c \
-                    android/gps.c \
-                    android/hw-events.c \
-                    android/hw-control.c \
-                    android/console.c \
-                    android/hw-sensors.c \
-                    android/hw-qemud.c \
-                    android/core-init-utils.c   \
-                    android/config.c \
-                    android/snapshot.c \
-                    android/utils/timezone.c \
-
-ifeq ($(TARGET_ARCH),arm)
-    CORE_MISC_SOURCES += arm-dis.c
-endif
-
-ifeq ($(HOST_ARCH),x86)
-    CORE_MISC_SOURCES += i386-dis.c
-endif
-ifeq ($(HOST_ARCH),x86_64)
-    CORE_MISC_SOURCES += i386-dis.c
-endif
-ifeq ($(HOST_ARCH),ppc)
-    CORE_MISC_SOURCES += ppc-dis.c \
-                         cache-utils.c
-endif
-
-ifeq ($(HOST_OS),linux)
-    CORE_MISC_SOURCES += usb-linux.c \
-                         qemu-thread.c
-else
-    CORE_MISC_SOURCES += usb-dummy-android.c
-endif
-
-ifeq ($(HOST_OS),windows)
-  CORE_MISC_SOURCES   += tap-win32.c
-else
-  CORE_MISC_SOURCES   += posix-aio-compat.c
-endif
-
-# sources inherited from upstream, but not fully
-# integrated into android emulator
-#
-CORE_UPSTREAM_SOURCES = json-lexer.c \
-                        json-parser.c \
-                        json-streamer.c \
-                        qjson.c \
-                        qbool.c \
-                        qdict.c \
-                        qfloat.c \
-                        qint.c \
-                        qlist.c \
-                        qstring.c \
-
-
-CORE_SOURCES = $(CORE_BLOCK_SOURCES) $(CORE_HW_SOURCES)
-CORE_SOURCES += $(CORE_MIGRATION_SOURCES) $(CORE_MISC_SOURCES)
-CORE_SOURCES += $(CORE_UPSTREAM_SOURCES)
-
-CORE_SOURCES += android/audio-test.c
-
-##############################################################################
-# lists of source files used to build the emulator UI
-#
-
-UI_SOURCES = loadpng.c \
-             android/user-config.c \
-             android/resource.c \
-             android/qemulator.c \
-             android/keycode.c \
-             android/help.c \
-             android/avd/info.c \
-
-##############################################################################
-# lists of source files used by both, emulator UI and emulator core
-#
-
-UI_AND_CORE_SOURCES = \
-                      sockets.c \
-                      android/keycode-array.c \
-                      android/charmap.c \
-                      android/async-utils.c \
-                      android/sync-utils.c \
-                      android/async-console.c \
-                      android/utils/assert.c \
-                      android/utils/bufprint.c \
-                      android/utils/debug.c \
-                      android/utils/path.c \
-                      android/utils/dirscanner.c \
-                      android/utils/filelock.c \
-                      android/utils/mapfile.c \
-                      android/utils/misc.c \
-                      android/utils/panic.c \
-                      android/utils/reflist.c \
-                      android/utils/refset.c \
-                      android/utils/stralloc.c \
-                      android/utils/system.c \
-                      android/utils/tempfile.c \
-                      android/utils/vector.c \
-                      android/avd/hw-config.c \
-                      android/utils/ini.c \
-
-# include the Zlib sources
-#
-UI_AND_CORE_SOURCES += $(ZLIB_SOURCES)
-UI_AND_CORE_CFLAGS  += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
+# A varient of end-emulator-library for host programs instead
+end-emulator-program = \
+    $(eval LOCAL_LDLIBS += $(QEMU_SYSTEM_LDLIBS)) \
+    $(eval include $(BUILD_HOST_EXECUTABLE))
 
-# include the Libpng sources
-#
-UI_AND_CORE_SOURCES += $(LIBPNG_SOURCES)
-UI_AND_CORE_CFLAGS  += $(LIBPNG_CFLAGS) -I$(LOCAL_PATH)/$(LIBPNG_DIR)
 
 # The common libraries
 #
@@ -890,471 +189,57 @@
   QEMU_SYSTEM_LDLIBS += -Wl,-framework,Cocoa
 endif
 
+include $(LOCAL_PATH)/Makefile.common
+
+# We want to build all variants of the emulator binaries. This makes
+# it easier to catch target-specific regressions during emulator development.
+EMULATOR_TARGET_ARCH := arm
+include $(LOCAL_PATH)/Makefile.target
+
+EMULATOR_TARGET_ARCH := x86
+include $(LOCAL_PATH)/Makefile.target
 
 ##############################################################################
-# now build the emulator itself
-#
-include $(CLEAR_VARS)
+##############################################################################
+###
+###  emulator-ui: UI FRONT-END PROGRAM
+###
+###
+$(call start-emulator-program, emulator-ui)
 
-LOCAL_GENERATED_SOURCES :=
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_MODULE                    := emulator
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_STATIC_LIBRARIES          := emulator-memcheck emulator-hw emulator-arm emulator-tcg
-endif
-ifeq ($(TARGET_ARCH),x86)
-LOCAL_STATIC_LIBRARIES          := emulator-memcheck emulator-hw emulator-i386 emulator-tcg
-endif
-LOCAL_STATIC_LIBRARIES          += emulator-elff
-LOCAL_STATIC_LIBRARIES          += emulator-core emulator-uilib
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) $(EMULATOR_CORE_CFLAGS) $(EMULATOR_UI_CFLAGS)
-
-# add the build ID to the default macro definitions
-LOCAL_CFLAGS += $(UI_AND_CORE_CFLAGS)
-
-# include sound support source files. we first try to see if we have a prebuilt audio
-# library. if not, we build things the "hard" way.
-#
-# note that to generate the prebuilt audio library, you should do the following:
-#
-#   cd tools/qemu
-#   ./android-rebuild.sh
-#   distrib/update-audio.sh
-#
-ifeq ($(QEMU_AUDIO_LIB),)
-  LOCAL_SRC_FILES += $(AUDIO_SOURCES)
-endif  # !QEMU_AUDIO_LIB
-
-LOCAL_CFLAGS  += $(AUDIO_CFLAGS)
-LOCAL_LDLIBS  += $(AUDIO_LDLIBS)
-
-# the linux-user sources, I doubt we really need these
-#
-#LINUX_SOURCES := main.c elfload.c mmap.c signal.c path.c syscall.c
-#LOCAL_SRC_FILES += $(LINUX_SOURCES:%=linux-user/%)
-
-ifeq ($(HOST_ARCH),x86)
-# enable MMX code for our skin scaler
-LOCAL_CFLAGS += -DUSE_MMX=1 -mmmx -DNEED_CPU_H
-endif
-
-# include other sources
-#
-VL_SOURCES := android/framebuffer.c \
-              user-events-qemu.c \
-              android/cmdline-option.c \
-              android/display.c \
-              android/looper-qemu.c \
-              android/protocol/ui-commands-qemu.c \
-              android/protocol/core-commands-qemu.c \
-              android/main-common.c \
-              android/main.c \
-
-# Add common system libraries
-#
-LOCAL_LDLIBS += $(QEMU_SYSTEM_LDLIBS)
-
-LOCAL_SRC_FILES += $(VL_SOURCES) $(CORE_SOURCES) $(UI_SOURCES) $(UI_AND_CORE_SOURCES)
-
-# add SDL-specific flags
-#
-LOCAL_CFLAGS += $(SDL_CFLAGS)
-LOCAL_LDLIBS += $(SDL_LDLIBS)
-LOCAL_STATIC_LIBRARIES += $(SDL_STATIC_LIBRARIES)
-
-# add ELFF-specific flags
-#
-LOCAL_LDLIBS += $(ELFF_LDLIBS)
-
-# on Windows, link the icon file as well into the executable
-# unfortunately, our build system doesn't help us much, so we need
-# to use some weird pathnames to make this work...
-#
-ifeq ($(HOST_OS),windows)
-
-# Locate windres executable
-WINDRES := windres
-ifneq ($(USE_MINGW),)
-  # When building the Windows emulator under Linux, use the MinGW one
-  WINDRES := i586-mingw32msvc-windres
-endif
-
-INTERMEDIATE     := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
-ANDROID_ICON_OBJ := android_icon.o
-ANDROID_ICON_PATH := $(LOCAL_PATH)/images
-$(ANDROID_ICON_PATH)/$(ANDROID_ICON_OBJ): $(ANDROID_ICON_PATH)/android_icon.rc
-	$(WINDRES) $< -I $(ANDROID_ICON_PATH) -o $@
-
-# seems to be the only way to add an object file that was not generated from
-# a C/C++/Java source file to our build system. and very unfortunately,
-# $(TOPDIR)/$(LOCALPATH) will always be prepended to this value, which forces
-# us to put the object file in the source directory...
-#
-LOCAL_PREBUILT_OBJ_FILES += images/$(ANDROID_ICON_OBJ)
-endif
-
-# qemu-options.h is generated from qemu-options.hx with the "hxtool" shell script
-#
-intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
-
-QEMU_OPTIONS_H := $(intermediates)/qemu-options.h
-$(QEMU_OPTIONS_H): PRIVATE_PATH := $(LOCAL_PATH)
-$(QEMU_OPTIONS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/hxtool -h < $< > $@
-$(QEMU_OPTIONS_H): $(LOCAL_PATH)/qemu-options.hx $(LOCAL_PATH)/hxtool
-	$(transform-generated-source)
-
-$(intermediates)/vl-android.o: $(QEMU_OPTIONS_H)
-
-LOCAL_GENERATED_SOURCES += $(QEMU_OPTIONS_H)
-
-# qemu-monitor.h is generated from qemu-monitor.hx with the "hxtool" shell script
-#
-intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
-
-QEMU_MONITOR_H := $(intermediates)/qemu-monitor.h
-$(QEMU_MONITOR_H): PRIVATE_PATH := $(LOCAL_PATH)
-$(QEMU_MONITOR_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/hxtool -h < $< > $@
-$(QEMU_MONITOR_H): $(LOCAL_PATH)/qemu-monitor.hx $(LOCAL_PATH)/hxtool
-	$(transform-generated-source)
-
-$(intermediates)/vl-android.o: $(QEMU_MONITOR_H)
-
-LOCAL_GENERATED_SOURCES += $(QEMU_MONITOR_H)
+LOCAL_STATIC_LIBRARIES := \
+    emulator-common \
+    emulator-libui \
+    emulator-common \
 
 
-# gdbstub-xml.c contains C-compilable arrays corresponding to the content
-# of $(LOCAL_PATH)/gdb-xml/, and is generated with the 'feature_to_c.sh' script.
-#
-ifeq ($(QEMU_TARGET_XML_SOURCES),)
-    QEMU_TARGET_XML_SOURCES := arm-core arm-neon arm-vfp arm-vfp3
-    QEMU_TARGET_XML_SOURCES := $(QEMU_TARGET_XML_SOURCES:%=$(LOCAL_PATH)/gdb-xml/%.xml)
-endif
+LOCAL_CFLAGS += -DCONFIG_STANDALONE_UI=1
 
-QEMU_GDBSTUB_XML_C := $(intermediates)/gdbstub-xml.c
-$(QEMU_GDBSTUB_XML_C): PRIVATE_PATH := $(LOCAL_PATH)
-$(QEMU_GDBSTUB_XML_C): PRIVATE_SOURCES := $(TARGET_XML_SOURCES)
-$(QEMU_GDBSTUB_XML_C): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/feature_to_c.sh $@ $(QEMU_TARGET_XML_SOURCES)
-$(QEMU_GDBSTUB_XML_C): $(QEMU_TARGET_XML_SOURCES) $(LOCAL_PATH)/feature_to_c.sh
-	$(hide) rm -f $@
-	$(transform-generated-source)
+LOCAL_CFLAGS += $(EMULATOR_COMMON_CFLAGS) $(EMULATOR_LIBUI_CFLAGS)
+LOCAL_LDLIBS += $(EMULATOR_COMMON_LDLIBS) $(EMULATOR_LIBUI_LDLIBS)
 
-$(intermediates)/vl-android.o: $(QEMU_GDBSTUB_XML_C)
+LOCAL_SRC_FILES := \
+    android/cmdline-option.c \
+    android/config.c \
+    android/help.c \
+    android/looper-generic.c \
+    android/snapshot.c \
+    android/main-common.c \
+    android/main.c \
+    vl-android-ui.c \
+    android/protocol/core-connection.c \
+    android/protocol/attach-ui-impl.c \
+    android/protocol/fb-updates-impl.c \
+    android/protocol/ui-commands-impl.c \
+    android/protocol/core-commands-proxy.c \
+    android/protocol/user-events-proxy.c \
 
-LOCAL_GENERATED_SOURCES += $(QEMU_GDBSTUB_XML_C)
-
-# hw-config-defs.h is generated from android/avd/hardware-properties.ini
-#
-QEMU_HARDWARE_PROPERTIES_INI := $(LOCAL_PATH)/android/avd/hardware-properties.ini
-QEMU_HW_CONFIG_DEFS_H := $(LOCAL_PATH)/android/avd/hw-config-defs.h
-$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_PATH := $(LOCAL_PATH)
-$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_SOURCES := $(QEMU_HARDWARE_PROPERTIES_INI)
-$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/android/tools/gen-hw-config.py $(QEMU_HARDWARE_PROPERTIES_INI) $@
-$(QEMU_HW_CONFIG_DEFS_H): $(QEMU_HARDWARE_PROPERTIES_INI) $(LOCAL_PATH)/android/tools/gen-hw-config.py
-	$(hide) rm -f $@
-	$(transform-generated-source)
-
-$(LOCAL_PATH)/android/avd/hw-config.h: $(QEMU_HW_CONFIG_DEFS_H)
-
-LOCAL_GENERATED_SOURCES += $(QEMU_HW_CONFIG_DEFS_H)
-
-# this is already done by the Android build system, but is done for the
-# benefit of the stand-alone one.
-#
-ifeq ($(BUILD_STANDALONE_EMULATOR),true)
-  LOCAL_CFLAGS += -I$(intermediates)
-endif
-
-LOCAL_LDLIBS += $(QEMU_AUDIO_LIB)
-
-# Generate a completely static executable if needed.
-# Note that this means no sound and graphics on Linux.
-#
-ifeq ($(CONFIG_STATIC_EXECUTABLE),true)
-    LOCAL_SRC_FILES += dynlink-static.c
-    LOCAL_LDLIBS    += -static
-endif
-
-LOCAL_MODULE := emulator
-
-# See comment about SDLMAIN_SOURCES in the 'emulator-uilib' module declarations.
 LOCAL_SRC_FILES += $(SDLMAIN_SOURCES)
 
-include $(BUILD_HOST_EXECUTABLE)
-
-##############################################################################
-# Build standalone emulator core.
-#
-include $(CLEAR_VARS)
-
-LOCAL_GENERATED_SOURCES         :=
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_MODULE                    := qemu-android-$(TARGET_ARCH)
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_STATIC_LIBRARIES          := emulator-memcheck emulator-hw emulator-arm emulator-tcg
-endif
-ifeq ($(TARGET_ARCH),x86)
-LOCAL_STATIC_LIBRARIES          := emulator-memcheck emulator-hw emulator-i386 emulator-tcg
-endif
-
-LOCAL_STATIC_LIBRARIES          += emulator-elff
-LOCAL_STATIC_LIBRARIES          += emulator-core
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) $(EMULATOR_CORE_CFLAGS)
-LOCAL_CFLAGS += $(UI_AND_CORE_CFLAGS) -DCONFIG_STANDALONE_CORE
-
-# include sound support source files. we first try to see if we have a prebuilt audio
-# library. if not, we build things the "hard" way.
-#
-# note that to generate the prebuilt audio library, you should do the following:
-#
-#   cd tools/qemu
-#   ./android-rebuild.sh
-#   distrib/update-audio.sh
-#
-ifeq ($(QEMU_AUDIO_LIB),)
-  LOCAL_SRC_FILES += $(AUDIO_SOURCES)
-endif  # !QEMU_AUDIO_LIB
-
-LOCAL_CFLAGS  += $(AUDIO_CFLAGS)
-LOCAL_LDLIBS  += $(AUDIO_LDLIBS)
-
-# the linux-user sources, I doubt we really need these
-#
-#LINUX_SOURCES := main.c elfload.c mmap.c signal.c path.c syscall.c
-#LOCAL_SRC_FILES += $(LINUX_SOURCES:%=linux-user/%)
-
-# include other sources
-#
-VL_SOURCES := android/framebuffer.c \
-              user-events-qemu.c \
-              android/looper-qemu.c \
-              android/looper-generic.c \
-              android/display-core.c \
-              android/protocol/attach-ui-proxy.c \
-              android/protocol/fb-updates-proxy.c \
-              android/protocol/user-events-impl.c \
-              android/protocol/ui-commands-proxy.c \
-              android/protocol/core-commands-impl.c \
-
-# Add common system libraries
-#
-LOCAL_LDLIBS += $(QEMU_SYSTEM_LDLIBS)
-
-LOCAL_SRC_FILES += $(VL_SOURCES) $(CORE_SOURCES) $(UI_AND_CORE_SOURCES)
-
-# add ELFF-specific flags
-#
-LOCAL_LDLIBS += $(ELFF_LDLIBS)
-
-# on Windows, link the icon file as well into the executable
-# unfortunately, our build system doesn't help us much, so we need
-# to use some weird pathnames to make this work...
-#
-ifeq ($(HOST_OS),windows)
-
-# Locate windres executable
-WINDRES := windres
-ifneq ($(USE_MINGW),)
-  # When building the Windows emulator under Linux, use the MinGW one
-  WINDRES := i586-mingw32msvc-windres
-endif
-
-INTERMEDIATE     := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
-ANDROID_ICON_OBJ := android_icon.o
-ANDROID_ICON_PATH := $(LOCAL_PATH)/images
-$(ANDROID_ICON_PATH)/$(ANDROID_ICON_OBJ): $(ANDROID_ICON_PATH)/android_icon.rc
-	$(WINDRES) $< -I $(ANDROID_ICON_PATH) -o $@
-
-# seems to be the only way to add an object file that was not generated from
-# a C/C++/Java source file to our build system. and very unfortunately,
-# $(TOPDIR)/$(LOCALPATH) will always be prepended to this value, which forces
-# us to put the object file in the source directory...
-#
-LOCAL_PREBUILT_OBJ_FILES += images/$(ANDROID_ICON_OBJ)
-endif
-
-# qemu-options.h is generated from qemu-options.hx with the "hxtool" shell script
-#
-intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
-
-QEMU_OPTIONS_H := $(intermediates)/qemu-options.h
-$(QEMU_OPTIONS_H): PRIVATE_PATH := $(LOCAL_PATH)
-$(QEMU_OPTIONS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/hxtool -h < $< > $@
-$(QEMU_OPTIONS_H): $(LOCAL_PATH)/qemu-options.hx $(LOCAL_PATH)/hxtool
-	$(transform-generated-source)
-
-$(intermediates)/vl-android.o: $(QEMU_OPTIONS_H)
-
-LOCAL_GENERATED_SOURCES += $(QEMU_OPTIONS_H)
-
-# qemu-monitor.h is generated from qemu-monitor.hx with the "hxtool" shell script
-#
-intermediates := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
-
-QEMU_MONITOR_H := $(intermediates)/qemu-monitor.h
-$(QEMU_MONITOR_H): PRIVATE_PATH := $(LOCAL_PATH)
-$(QEMU_MONITOR_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/hxtool -h < $< > $@
-$(QEMU_MONITOR_H): $(LOCAL_PATH)/qemu-monitor.hx $(LOCAL_PATH)/hxtool
-	$(transform-generated-source)
-
-$(intermediates)/vl-android.o: $(QEMU_MONITOR_H)
-
-LOCAL_GENERATED_SOURCES += $(QEMU_MONITOR_H)
-
-
-# gdbstub-xml.c contains C-compilable arrays corresponding to the content
-# of $(LOCAL_PATH)/gdb-xml/, and is generated with the 'feature_to_c.sh' script.
-#
-ifeq ($(QEMU_TARGET_XML_SOURCES),)
-    QEMU_TARGET_XML_SOURCES := arm-core arm-neon arm-vfp arm-vfp3
-    QEMU_TARGET_XML_SOURCES := $(QEMU_TARGET_XML_SOURCES:%=$(LOCAL_PATH)/gdb-xml/%.xml)
-endif
-
-QEMU_GDBSTUB_XML_C := $(intermediates)/gdbstub-xml.c
-$(QEMU_GDBSTUB_XML_C): PRIVATE_PATH := $(LOCAL_PATH)
-$(QEMU_GDBSTUB_XML_C): PRIVATE_SOURCES := $(TARGET_XML_SOURCES)
-$(QEMU_GDBSTUB_XML_C): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/feature_to_c.sh $@ $(QEMU_TARGET_XML_SOURCES)
-$(QEMU_GDBSTUB_XML_C): $(QEMU_TARGET_XML_SOURCES) $(LOCAL_PATH)/feature_to_c.sh
-	$(hide) rm -f $@
-	$(transform-generated-source)
-
-$(intermediates)/vl-android.o: $(QEMU_GDBSTUB_XML_C)
-
-LOCAL_GENERATED_SOURCES += $(QEMU_GDBSTUB_XML_C)
-
-# this is already done by the Android build system, but is done for the
-# benefit of the stand-alone one.
-#
-ifeq ($(BUILD_STANDALONE_EMULATOR),true)
-  LOCAL_CFLAGS += -I$(intermediates)
-endif
-
-# other flags
-ifneq ($(HOST_OS),windows)
-    LOCAL_LDLIBS += -ldl
-endif
-
-LOCAL_LDLIBS += $(QEMU_AUDIO_LIB)
-
-ifeq ($(HOST_OS),darwin)
-    FRAMEWORKS := OpenGL Cocoa QuickTime ApplicationServices Carbon IOKit
-    LOCAL_LDLIBS += $(FRAMEWORKS:%=-Wl,-framework,%)
-endif
-
-# Generate a completely static executable if needed.
-# Note that this means no sound and graphics on Linux.
-#
-ifeq ($(CONFIG_STATIC_EXECUTABLE),true)
-    LOCAL_SRC_FILES += dynlink-static.c
-    LOCAL_LDLIBS    += -static
-endif
-
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_HOST_EXECUTABLE)
-
-##############################################################################
-# now build the emulator UI
-#
-include $(CLEAR_VARS)
-
-LOCAL_GENERATED_SOURCES :=
-LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
-LOCAL_CC                        := $(MY_CC)
-LOCAL_MODULE                    := emulator-ui
-LOCAL_STATIC_LIBRARIES          := emulator-uilib
-LOCAL_LDLIBS                    := $(MY_LDLIBS)
-
-LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) $(EMULATOR_UI_CFLAGS) $(EMULATOR_CORE_CFLAGS)
-
-# add the build ID to the default macro definitions
-LOCAL_CFLAGS += $(UI_AND_CORE_CFLAGS) -DCONFIG_STANDALONE_UI
-
-ifeq ($(HOST_ARCH),x86)
-# enable MMX code for our skin scaler
-LOCAL_CFLAGS += -DUSE_MMX=1 -mmmx
-endif
-
-# include other sources
-#
-VL_SOURCES := android/framebuffer.c \
-              android/cmdline-option.c \
-              android/config.c \
-              android/looper-generic.c \
-              android/snapshot.c \
-              android/main-common.c \
-              android/main-ui.c \
-              vl-android-ui.c \
-              iolooper-select.c \
-              android/protocol/core-connection.c \
-              android/protocol/attach-ui-impl.c \
-              android/protocol/fb-updates-impl.c \
-              android/protocol/ui-commands-impl.c \
-              android/protocol/core-commands-proxy.c \
-              android/protocol/user-events-proxy.c \
-
-# Add common system libraries
-#
-LOCAL_LDLIBS += $(QEMU_SYSTEM_LDLIBS)
-
-LOCAL_SRC_FILES += $(VL_SOURCES) $(UI_SOURCES) $(UI_AND_CORE_SOURCES)
-
-# add SDL-specific flags
-#
-LOCAL_CFLAGS += $(SDL_CFLAGS)
-LOCAL_LDLIBS += $(SDL_LDLIBS)
 LOCAL_STATIC_LIBRARIES += $(SDL_STATIC_LIBRARIES)
 
-# on Windows, link the icon file as well into the executable
-# unfortunately, our build system doesn't help us much, so we need
-# to use some weird pathnames to make this work...
-#
-ifeq ($(HOST_OS),windows)
+$(call end-emulator-program)
 
-# Locate windres executable
-WINDRES := windres
-ifneq ($(USE_MINGW),)
-  # When building the Windows emulator under Linux, use the MinGW one
-  WINDRES := i586-mingw32msvc-windres
-endif
-
-INTERMEDIATE     := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
-ANDROID_ICON_OBJ := android_icon.o
-ANDROID_ICON_PATH := $(LOCAL_PATH)/images
-$(ANDROID_ICON_PATH)/$(ANDROID_ICON_OBJ): $(ANDROID_ICON_PATH)/android_icon.rc
-	$(WINDRES) $< -I $(ANDROID_ICON_PATH) -o $@
-
-# seems to be the only way to add an object file that was not generated from
-# a C/C++/Java source file to our build system. and very unfortunately,
-# $(TOPDIR)/$(LOCALPATH) will always be prepended to this value, which forces
-# us to put the object file in the source directory...
-#
-LOCAL_PREBUILT_OBJ_FILES += images/$(ANDROID_ICON_OBJ)
-endif
-
-# this is already done by the Android build system, but is done for the
-# benefit of the stand-alone one.
-#
-ifeq ($(BUILD_STANDALONE_EMULATOR),true)
-  LOCAL_CFLAGS += -I$(intermediates)
-endif
-
-# Generate a completely static executable if needed.
-# Note that this means no sound and graphics on Linux.
-#
-ifeq ($(CONFIG_STATIC_EXECUTABLE),true)
-    LOCAL_SRC_FILES += dynlink-static.c
-    LOCAL_LDLIBS    += -static
-endif
-
-# See comment about SDLMAIN_SOURCES in the 'emulator-uilib' module declarations.
-LOCAL_SRC_FILES += $(SDLMAIN_SOURCES)
-
-include $(BUILD_HOST_EXECUTABLE)
+## VOILA!!
 
 endif  # TARGET_ARCH == arm || TARGET_ARCH == x86
diff --git a/Makefile.common b/Makefile.common
new file mode 100644
index 0000000..e872734
--- /dev/null
+++ b/Makefile.common
@@ -0,0 +1,613 @@
+# When building this project, we actually generate several components which
+# are the following:
+#
+#  - the emulator-ui program (which is target-agnostic)
+#  - the target-specific qemu-android-$ARCH programs (headless emulation engines)
+#  - the "standalone" emulator programs (embed both UI and engine in a single
+#    binary and process), i.e. "emulator" for ARM and "emulator-x86" for x86.
+#
+# This file defines static host libraries that will be used by at least two
+# of these components.
+#
+
+##############################################################################
+##############################################################################
+###
+###  emulator-common: LIBRARY OF COMMON FUNCTIONS
+###
+###  THESE ARE POTENTIALLY USED BY ALL COMPONENTS
+###
+
+$(call start-emulator-library, emulator-common)
+
+EMULATOR_COMMON_CFLAGS :=
+
+# Needed by everything about the host
+EMULATOR_COMMON_CFLAGS += \
+    -I$(LOCAL_PATH)/android/config/$(QEMU_HOST_TAG)
+
+# add the build ID to the default macro definitions
+ifeq ($(BUILD_STANDALONE_EMULATOR),)
+EMULATOR_COMMON_CFLAGS += -DANDROID_BUILD_ID="$(strip $(BUILD_ID))-$(strip $(BUILD_NUMBER))"
+endif
+
+# For non-standalone builds, extract the major version number from the Android SDK
+# tools revision number.
+ifneq ($(BUILD_STANDALONE_EMULATOR),true)
+    ANDROID_SDK_TOOLS_REVISION := $(shell awk -F= '/Pkg.Revision/ { print $$2; }' sdk/files/tools_source.properties)
+endif
+
+ANDROID_SDK_TOOLS_REVISION := $(strip $(ANDROID_SDK_TOOLS_REVISION))
+ifdef ANDROID_SDK_TOOLS_REVISION
+    EMULATOR_COMMON_CFLAGS += -DANDROID_SDK_TOOLS_REVISION=$(ANDROID_SDK_TOOLS_REVISION)
+endif
+
+# Enable large-file support (i.e. make off_t a 64-bit value)
+ifeq ($(HOST_OS),linux)
+EMULATOR_COMMON_CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+endif
+
+###########################################################
+# Zlib sources
+#
+ZLIB_DIR := distrib/zlib-1.2.3
+include $(LOCAL_PATH)/$(ZLIB_DIR)/sources.make
+EMULATOR_COMMON_CFLAGS += -I$(LOCAL_PATH)/$(ZLIB_DIR)
+
+LOCAL_SRC_FILES += $(ZLIB_SOURCES)
+
+###########################################################
+# Android utility functions
+#
+LOCAL_SRC_FILES += \
+	sockets.c \
+	iolooper-select.c \
+	android/async-console.c \
+	android/async-utils.c \
+	android/charmap.c \
+	android/framebuffer.c \
+	android/keycode-array.c \
+	android/avd/hw-config.c \
+	android/avd/info.c \
+	android/sync-utils.c \
+	android/utils/assert.c \
+	android/utils/bufprint.c \
+	android/utils/debug.c \
+	android/utils/dirscanner.c \
+	android/utils/filelock.c \
+	android/utils/ini.c \
+	android/utils/mapfile.c \
+	android/utils/misc.c \
+	android/utils/panic.c \
+	android/utils/path.c \
+	android/utils/reflist.c \
+	android/utils/refset.c \
+	android/utils/stralloc.c \
+	android/utils/system.c \
+	android/utils/tempfile.c \
+	android/utils/vector.c \
+
+LOCAL_CFLAGS += $(EMULATOR_COMMON_CFLAGS)
+
+$(call end-emulator-library)
+
+##############################################################################
+##############################################################################
+###
+###  emulator-libui: LIBRARY OF UI-RELATED FUNCTIONS
+###
+###  THESE ARE USED BY 'emulator-ui' AND THE STANDALONE PROGRAMS
+###
+
+$(call start-emulator-library, emulator-libui)
+
+EMULATOR_LIBUI_CFLAGS :=
+
+LOCAL_CFLAGS += $(EMULATOR_COMMON_CFLAGS)
+
+###########################################################
+# Libpng configuration
+#
+LIBPNG_DIR := distrib/libpng-1.2.19
+include $(LOCAL_PATH)/$(LIBPNG_DIR)/sources.make
+
+EMULATOR_LIBUI_CFLAGS += \
+    $(LIBPNG_CFLAGS) \
+    -I$(LOCAL_PATH)/$(LIBPNG_DIR)
+
+LOCAL_SRC_FILES += $(LIBPNG_SOURCES) loadpng.c
+
+##############################################################################
+# SDL-related definitions
+#
+
+# Build SDL from sources except in certain cases where we use
+# prebuilt libraries instead.
+#
+BUILD_SDL_FROM_SOURCES := true
+
+# On linux-x86, using the prebuilts avoid installing all the X11
+# development packages on our build servers.
+#
+ifeq ($(QEMU_HOST_TAG),linux-x86)
+    BUILD_SDL_FROM_SOURCES := false
+endif
+
+# On darwin-x86, a bug in the Android build system prevents the compilation
+# of Objective-C sources. Fixed recently in AOSP, but we still use the
+# prebuilts for the benefit of older platform branches.
+#
+ifeq ($(QEMU_HOST_TAG),darwin-x86)
+    BUILD_SDL_FROM_SOURCES := false
+endif
+
+# If we're building with android-configure.sh && make, always build from
+# sources to catch regressions as soon as they happen.
+#
+ifeq ($(BUILD_STANDALONE_EMULATOR),true)
+    BUILD_SDL_FROM_SOURCES := true
+endif
+
+# Except if we used android-configure.sh --sdl-config=<script>
+#
+ifneq ($(SDL_CONFIG),)
+   BUILD_SDL_FROM_SOURCES := false
+endif
+
+ifneq ($(BUILD_SDL_FROM_SOURCES),true)
+
+    SDL_CONFIG ?= prebuilt/$(QEMU_HOST_TAG)/sdl/bin/sdl-config
+    SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags)
+
+    # We need to filter out the _GNU_SOURCE variable because it breaks recent
+    # releases of Cygwin when using the -mno-cygwin option. Moreover, we don't
+    # need this macro at all to build the Android emulator.
+    SDL_CFLAGS := $(filter-out -D_GNU_SOURCE=1,$(SDL_CFLAGS))
+    SDL_LDLIBS := $(filter-out %.a %.lib,$(shell $(SDL_CONFIG) --static-libs))
+
+    # Circular dependencies between libSDL and libSDLmain
+    # We repeat the libraries in the final link to work around it
+    SDL_STATIC_LIBRARIES := libSDL libSDLmain libSDL libSDLmain
+
+else # BUILD_SDL_FROM_SOURCES
+
+    SDL_DIR := distrib/sdl-1.2.12
+    include $(LOCAL_PATH)/$(SDL_DIR)/sources.make
+    LOCAL_SRC_FILES += $(SDL_SOURCES)
+
+    EMULATOR_LIBUI_CFLAGS += \
+        -I$(LOCAL_PATH)/$(SDL_DIR)/include
+
+    SDL_STATIC_LIBRARIES :=
+
+endif # BUILD_SDL_FROM_SOURCES
+
+EMULATOR_LIBUI_CFLAGS += $(SDL_CFLAGS)
+EMULATOR_LIBUI_LDLIBS += $(SDL_LDLIBS)
+
+# The following is needed by SDL_LoadObject
+ifneq ($(HOST_OS),windows)
+    EMULATOR_LIBUI_LDLIBS += -ldl
+endif
+
+# the skin support sources
+#
+SKIN_SOURCES := rect.c \
+                region.c \
+                image.c \
+                trackball.c \
+                keyboard.c \
+                keyset.c \
+                file.c \
+                window.c \
+                scaler.c \
+                composer.c \
+                surface.c \
+
+LOCAL_SRC_FILES += $(SKIN_SOURCES:%=android/skin/%)
+
+LOCAL_SRC_FILES += \
+             android/user-config.c \
+             android/resource.c \
+             android/qemulator.c \
+             android/keycode.c \
+
+# enable MMX code for our skin scaler
+ifeq ($(HOST_ARCH),x86)
+LOCAL_CFLAGS += -DUSE_MMX=1 -mmmx
+endif
+
+LOCAL_CFLAGS += $(EMULATOR_LIBUI_CFLAGS)
+
+$(call end-emulator-library)
+
+##############################################################################
+##############################################################################
+###
+###  emulator-libqemu: TARGET-INDEPENDENT QEMU FUNCTIONS
+###
+###  THESE ARE USED BY EVERYTHING EXCEPT 'emulator-ui'
+###
+
+$(call start-emulator-library, emulator-libqemu)
+
+EMULATOR_LIBQEMU_CFLAGS :=
+
+LOCAL_CFLAGS += $(EMULATOR_COMMON_CFLAGS)
+
+AUDIO_SOURCES := noaudio.c wavaudio.c wavcapture.c mixeng.c
+AUDIO_CFLAGS  := -I$(LOCAL_PATH)/audio -DHAS_AUDIO
+AUDIO_LDLIBS  :=
+
+LOCAL_CFLAGS += -Wall -Wno-missing-field-initializers
+
+ifeq ($(HOST_OS),darwin)
+  CONFIG_COREAUDIO ?= yes
+  AUDIO_CFLAGS += -DHOST_BSD=1
+endif
+
+ifeq ($(HOST_OS),windows)
+  CONFIG_WINAUDIO ?= yes
+endif
+
+ifeq ($(HOST_OS),linux)
+  CONFIG_OSS  ?= yes
+  CONFIG_ALSA ?= yes
+  CONFIG_PULSEAUDIO ?= yes
+  CONFIG_ESD  ?= yes
+endif
+
+ifeq ($(HOST_OS),freebsd)
+  CONFIG_OSS ?= yes
+endif
+
+ifeq ($(CONFIG_COREAUDIO),yes)
+  AUDIO_SOURCES += coreaudio.c
+  AUDIO_CFLAGS  += -DCONFIG_COREAUDIO
+  AUDIO_LDLIBS  += -Wl,-framework,CoreAudio
+endif
+
+ifeq ($(CONFIG_WINAUDIO),yes)
+  AUDIO_SOURCES += winaudio.c
+  AUDIO_CFLAGS  += -DCONFIG_WINAUDIO
+endif
+
+ifeq ($(CONFIG_PULSEAUDIO),yes)
+  AUDIO_SOURCES += paaudio.c audio_pt_int.c
+  AUDIO_CFLAGS  += -DCONFIG_PULSEAUDIO
+endif
+
+ifeq ($(CONFIG_ALSA),yes)
+  AUDIO_SOURCES += alsaaudio.c audio_pt_int.c
+  AUDIO_CFLAGS  += -DCONFIG_ALSA
+endif
+
+ifeq ($(CONFIG_ESD),yes)
+  AUDIO_SOURCES += esdaudio.c
+  AUDIO_CFLAGS  += -DCONFIG_ESD
+endif
+
+ifeq ($(CONFIG_OSS),yes)
+  AUDIO_SOURCES += ossaudio.c
+  AUDIO_CFLAGS  += -DCONFIG_OSS
+endif
+
+AUDIO_SOURCES := $(call sort,$(AUDIO_SOURCES:%=audio/%))
+
+LOCAL_CFLAGS += -Wno-sign-compare \
+                -fno-strict-aliasing -W -Wall -Wno-unused-parameter \
+
+# this is very important, otherwise the generated binaries may
+# not link properly on our build servers
+ifeq ($(HOST_OS),linux)
+LOCAL_CFLAGS += -fno-stack-protector
+endif
+
+LOCAL_SRC_FILES += $(AUDIO_SOURCES)
+LOCAL_SRC_FILES += \
+    android/audio-test.c
+
+# other flags
+ifneq ($(HOST_OS),windows)
+    AUDIO_LDLIBS += -ldl
+else
+endif
+
+
+EMULATOR_LIBQEMU_CFLAGS += $(AUDIO_CFLAGS)
+EMULATOR_LIBQEMU_LDLIBS += $(AUDIO_LDLIBS)
+
+LOCAL_CFLAGS += -Wno-missing-field-initializers
+
+# migration sources
+#
+ifeq ($(HOST_OS),windows)
+  LOCAL_SRC_FILES += migration-dummy-android.c
+else
+  LOCAL_SRC_FILES += migration.c \
+                     migration-exec.c \
+                     migration-tcp-android.c
+endif
+
+# misc. sources
+#
+CORE_MISC_SOURCES = \
+    acl.c \
+    aes.c \
+    aio-android.c \
+    async.c \
+    bt-host.c \
+    bt-vhci.c \
+    buffered_file.c \
+    cbuffer.c \
+    charpipe.c \
+    console.c \
+    cutils.c \
+    d3des.c \
+    input.c \
+    ioport.c \
+    module.c \
+    net-android.c \
+    notify.c \
+    osdep.c \
+    outputchannel.c \
+    path.c \
+    qemu-char-android.c \
+    qemu-config.c \
+    qemu-error.c \
+    qemu-malloc.c \
+    qemu-option.c \
+    qemu-sockets-android.c \
+    qerror.c \
+    readline.c \
+    savevm.c \
+    shaper.c \
+    tcpdump.c \
+    vnc-android.c \
+    android/boot-properties.c \
+    android/config.c \
+    android/core-init-utils.c   \
+    android/gps.c \
+    android/hw-kmsg.c \
+    android/hw-lcd.c \
+    android/hw-events.c \
+    android/hw-control.c \
+    android/hw-sensors.c \
+    android/hw-qemud.c \
+    android/looper-qemu.c \
+    android/qemu-setup.c \
+    android/snapshot.c \
+    android/utils/timezone.c \
+
+ifeq ($(HOST_ARCH),x86)
+    CORE_MISC_SOURCES += i386-dis.c
+endif
+ifeq ($(HOST_ARCH),x86_64)
+    CORE_MISC_SOURCES += i386-dis.c
+endif
+ifeq ($(HOST_ARCH),ppc)
+    CORE_MISC_SOURCES += ppc-dis.c \
+                         cache-utils.c
+endif
+
+ifeq ($(HOST_OS),linux)
+    CORE_MISC_SOURCES += usb-linux.c \
+                         qemu-thread.c
+else
+    CORE_MISC_SOURCES += usb-dummy-android.c
+endif
+
+ifeq ($(HOST_OS),windows)
+  CORE_MISC_SOURCES   += tap-win32.c
+else
+  CORE_MISC_SOURCES   += posix-aio-compat.c
+endif
+
+LOCAL_SRC_FILES += $(CORE_MISC_SOURCES)
+
+# Required
+LOCAL_CFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE=1
+
+SLIRP_SOURCES := \
+    bootp.c \
+    cksum.c \
+    debug.c \
+    if.c \
+    ip_icmp.c \
+    ip_input.c \
+    ip_output.c \
+    mbuf.c \
+    misc.c \
+    sbuf.c \
+    slirp.c \
+    socket.c \
+    tcp_input.c \
+    tcp_output.c \
+    tcp_subr.c \
+    tcp_timer.c \
+    tftp.c \
+    udp.c
+
+LOCAL_SRC_FILES += $(SLIRP_SOURCES:%=slirp-android/%)
+EMULATOR_LIBQEMU_CFLAGS += -I$(LOCAL_PATH)/slirp-android
+
+# socket proxy support
+#
+PROXY_SOURCES := \
+    proxy_common.c \
+    proxy_http.c \
+    proxy_http_connector.c \
+    proxy_http_rewriter.c \
+
+LOCAL_SRC_FILES += $(PROXY_SOURCES:%=proxy/%)
+EMULATOR_LIBQEMU_CFLAGS += -I$(LOCAL_PATH)/proxy
+
+# include telephony stuff
+#
+TELEPHONY_SOURCES := \
+    android_modem.c \
+    modem_driver.c \
+    gsm.c \
+    sim_card.c \
+    sysdeps_qemu.c \
+    sms.c \
+    remote_call.c
+
+LOCAL_SRC_FILES += $(TELEPHONY_SOURCES:%=telephony/%)
+EMULATOR_LIBQEMU_CFLAGS += -I$(LOCAL_PATH)/telephony
+
+# sources inherited from upstream, but not fully
+# integrated into android emulator
+#
+LOCAL_SRC_FILES += \
+    json-lexer.c \
+    json-parser.c \
+    json-streamer.c \
+    qjson.c \
+    qbool.c \
+    qdict.c \
+    qfloat.c \
+    qint.c \
+    qlist.c \
+    qstring.c \
+
+# hw-config-defs.h is generated from android/avd/hardware-properties.ini
+#
+QEMU_HARDWARE_PROPERTIES_INI := $(LOCAL_PATH)/android/avd/hardware-properties.ini
+QEMU_HW_CONFIG_DEFS_H := $(LOCAL_PATH)/android/avd/hw-config-defs.h
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_SOURCES := $(QEMU_HARDWARE_PROPERTIES_INI)
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/android/tools/gen-hw-config.py $(QEMU_HARDWARE_PROPERTIES_INI) $@
+$(QEMU_HW_CONFIG_DEFS_H): $(QEMU_HARDWARE_PROPERTIES_INI) $(LOCAL_PATH)/android/tools/gen-hw-config.py
+	$(hide) rm -f $@
+	$(transform-generated-source)
+
+$(LOCAL_PATH)/android/avd/hw-config.h: $(QEMU_HW_CONFIG_DEFS_H)
+
+# gdbstub-xml.c contains C-compilable arrays corresponding to the content
+# of $(LOCAL_PATH)/gdb-xml/, and is generated with the 'feature_to_c.sh' script.
+#
+intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,$(LOCAL_MODULE),true)
+
+ifeq ($(QEMU_TARGET_XML_SOURCES),)
+    QEMU_TARGET_XML_SOURCES := arm-core arm-neon arm-vfp arm-vfp3
+    QEMU_TARGET_XML_SOURCES := $(QEMU_TARGET_XML_SOURCES:%=$(LOCAL_PATH)/gdb-xml/%.xml)
+endif
+
+QEMU_GDBSTUB_XML_C := $(intermediates)/gdbstub-xml.c
+$(QEMU_GDBSTUB_XML_C): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_GDBSTUB_XML_C): PRIVATE_SOURCES := $(TARGET_XML_SOURCES)
+$(QEMU_GDBSTUB_XML_C): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/feature_to_c.sh $@ $(QEMU_TARGET_XML_SOURCES)
+$(QEMU_GDBSTUB_XML_C): $(QEMU_TARGET_XML_SOURCES) $(LOCAL_PATH)/feature_to_c.sh
+	$(hide) rm -f $@
+	$(transform-generated-source)
+
+LOCAL_GENERATED_SOURCES += $(QEMU_GDBSTUB_XML_C)
+
+EMULATOR_LIBQEMU_CFLAGS += -I$(intermediates)
+
+LOCAL_CFLAGS += $(EMULATOR_LIBQEMU_CFLAGS)
+
+$(call end-emulator-library)
+
+# Block sources, we must compile them with each executable because they
+# are only referenced by the rest of the code using constructor functions.
+# If their object files are put in a static library, these are never compiled
+# into the final linked executable that uses them.
+#
+# Normally, one would solve thus using LOCAL_WHOLE_STATIC_LIBRARIES, but
+# the Darwin linker doesn't support -Wl,--whole-archive or equivalent :-(
+#
+BLOCK_SOURCES += \
+    block.c \
+    blockdev.c \
+    block/qcow.c \
+    block/qcow2.c \
+    block/qcow2-refcount.c \
+    block/qcow2-snapshot.c \
+    block/qcow2-cluster.c \
+    block/cloop.c \
+    block/dmg.c \
+    block/vvfat.c \
+    block/raw.c
+
+ifeq ($(HOST_OS),windows)
+    BLOCK_SOURCES += block/raw-win32.c
+else
+    BLOCK_SOURCES += block/raw-posix.c
+endif
+
+BLOCK_CFLAGS += $(EMULATOR_COMMON_CFLAGS)
+BLOCK_CFLAGS += -DCONFIG_BDRV_WHITELIST=""
+
+
+##############################################################################
+##############################################################################
+###
+###  emulator-libelff: TARGET-INDEPENDENT ELF/DWARD PARSER
+###
+###  THESE ARE USED BY EVERYTHING EXCEPT 'emulator-ui', BUT WE CANNOT PUT
+###  THEM IN emulator-libqemu SINCE THE SOURCES ARE C++
+###
+
+$(call start-emulator-library, emulator-libelff)
+
+LOCAL_CPP_EXTENSION := .cc
+
+ELFF_CFLAGS := -I$(LOCAL_PATH)/elff
+ELFF_LDLIBS := -lstdc++
+
+ELFF_SOURCES := \
+    dwarf_cu.cc \
+    dwarf_die.cc \
+    dwarf_utils.cc \
+    elf_alloc.cc \
+    elf_file.cc \
+    elf_mapped_section.cc \
+    elff_api.cc \
+
+LOCAL_SRC_FILES += $(ELFF_SOURCES:%=elff/%)
+
+LOCAL_CFLAGS += \
+    -fno-exceptions \
+    $(ELFF_CFLAGS) \
+
+$(call end-emulator-library)
+
+
+##############################################################################
+##############################################################################
+###
+###  gen-hx-header: Generate headers from .hx file with "hxtool" script.
+###
+###  The 'hxtool' script is used to generate header files from an input
+###  file with the .hx suffix. I.e. foo.hx --> foo.h
+###
+###  Due to the way the Android build system works, we need to regenerate
+###  it for each module (the output will go into a module-specific directory).
+###
+###  This defines a function that can be used inside a module definition
+###
+###  $(call gen-hx-header,<input>,<source-files>)
+###
+###  Where: <input> is the input file, with a .hx suffix (e.g. foo.hx)
+###         <source-files> is a list of source files that include the header
+###
+
+
+gen-hx-header = $(eval $(call gen-hx-header-ev,$1,$2,$3))
+
+define gen-hx-header-ev
+intermediates := $$(call intermediates-dir-for,EXECUTABLES,$$(LOCAL_MODULE),true)
+
+QEMU_HEADER_H := $$(intermediates)/$$(1:%.hx=%.h)
+$$(QEMU_HEADER_H): PRIVATE_PATH := $$(LOCAL_PATH)
+$$(QEMU_HEADER_H): PRIVATE_CUSTOM_TOOL = $$(PRIVATE_PATH)/hxtool -h < $$< > $$@
+$$(QEMU_HEADER_H): $$(LOCAL_PATH)/$$1 $$(LOCAL_PATH)/hxtool
+	$$(transform-generated-source)
+
+LOCAL_GENERATED_SOURCES += $$(QEMU_HEADER_H)
+_objects := $$(patsubst %,$$(intermediates)/%,$$(2:.c=.o))
+$$(_objects): $$(QEMU_HEADER_H)
+endef
+
diff --git a/Makefile.target b/Makefile.target
new file mode 100644
index 0000000..fa76ed7
--- /dev/null
+++ b/Makefile.target
@@ -0,0 +1,362 @@
+# This file is included several times to build target-specific
+# modules for the Android emulator. It will be called several times
+# (e.g. once for the arm target, and once for the x86 target).
+#
+
+ifndef EMULATOR_TARGET_ARCH
+$(error EMULATOR_TARGET_ARCH is not defined!)
+endif
+
+EMULATOR_TARGET_CPU := $(EMULATOR_TARGET_ARCH)
+ifeq ($(EMULATOR_TARGET_CPU),x86)
+  EMULATOR_TARGET_CPU := i386
+endif
+
+##############################################################################
+##############################################################################
+###
+###  emulator-target-$CPU: target-specific emulation code.
+###
+###  Used by both the core and standalone programs.
+###
+
+# Common compiler flags for all target-dependent libraries
+EMULATOR_TARGET_CFLAGS := \
+    -I$(LOCAL_PATH)/android/config/$(HOST_PREBUILT_TAG) \
+    -I$(LOCAL_PATH)/android/config/target-$(EMULATOR_TARGET_ARCH) \
+    -I$(LOCAL_PATH)/target-$(EMULATOR_TARGET_CPU) \
+    -I$(LOCAL_PATH)/fpu \
+    -DNEED_CPU_H \
+
+TCG_TARGET := $(HOST_ARCH)
+ifeq ($(TCG_TARGET),x86)
+  TCG_TARGET := i386
+endif
+
+EMULATOR_TARGET_CFLAGS += \
+    -I$(LOCAL_PATH)/tcg \
+    -I$(LOCAL_PATH)/tcg/$(TCG_TARGET) \
+    -DTARGET_ARCH=\"$(EMULATOR_TARGET_ARCH)\"
+
+
+$(call start-emulator-library, emulator-target-$(EMULATOR_TARGET_CPU))
+
+# The following is to ensure that "config.h" will map to a target-specific
+# configuration file header.
+LOCAL_CFLAGS += $(EMULATOR_TARGET_CFLAGS)
+
+LOCAL_SRC_FILES += \
+    tcg/tcg.c \
+
+##############################################################################
+# Emulated hardware devices.
+#
+
+HW_SOURCES := \
+    bt.c \
+    bt-hci.c \
+    bt-hid.c \
+    bt-l2cap.c \
+    bt-sdp.c \
+    cdrom.c \
+    dma.c \
+    irq.c \
+    goldfish_audio.c \
+    goldfish_device.c \
+    goldfish_events_device.c \
+    goldfish_fb.c \
+    goldfish_battery.c \
+    goldfish_mmc.c   \
+    goldfish_memlog.c \
+    goldfish_nand.c \
+    goldfish_tty.c \
+    msmouse.c \
+    pci.c \
+    qdev.c \
+    scsi-disk.c \
+    sysbus.c \
+    usb-hid.c \
+    usb-hub.c \
+    usb-msd.c \
+    usb-ohci.c \
+    usb.c \
+    watchdog.c
+
+ifeq ($(EMULATOR_TARGET_ARCH),arm)
+HW_SOURCES += android_arm.c \
+    arm_pic.c \
+    goldfish_interrupt.c \
+    goldfish_switch.c \
+    goldfish_timer.c \
+    goldfish_trace.c \
+    arm_boot.c \
+
+# The following sources must be compiled with the final executables
+# because they contain device_init() or machine_init() statements.
+HW_OBJ_SOURCES := hw/smc91c111.c
+HW_OBJ_CFLAGS  := $(EMULATOR_TARGET_CFLAGS)
+
+LOCAL_SRC_FILES += arm-dis.c
+
+# smc91c111.c requires <zlib.h>
+LOCAL_CFLAGS += $(ZLIB_CFLAGS)
+endif
+
+ifeq ($(EMULATOR_TARGET_ARCH),x86)
+HW_SOURCES += \
+    apic.c \
+    i8259.c \
+    mc146818rtc.c \
+    piix_pci.c \
+    i8254.c \
+    pckbd.c \
+    ioapic.c \
+    ps2.c \
+    smbios.c \
+    fw_cfg.c
+
+# The following sources must be compiled with the final executables
+# because they contain device_init() or machine_init() statements.
+HW_OBJ_SOURCES := \
+    hw/ne2000.c \
+    hw/pc.c
+
+HW_OBJ_CFLAGS  := $(EMULATOR_TARGET_CFLAGS)
+
+endif
+
+LOCAL_SRC_FILES += $(HW_SOURCES:%=hw/%)
+
+LOCAL_SRC_FILES += \
+    exec.c \
+    cpu-exec.c  \
+    translate-all.c \
+    trace.c \
+    varint.c \
+    dcache.c \
+    softmmu_outside_jit.c \
+
+##############################################################################
+# CPU-specific emulation.
+#
+LOCAL_CFLAGS += -fno-PIC -fomit-frame-pointer -Wno-sign-compare
+
+ifeq ($(HOST_ARCH),ppc)
+    LOCAL_CFLAGS += -D__powerpc__
+endif
+
+ifeq ($(EMULATOR_TARGET_ARCH),arm)
+LOCAL_SRC_FILES += \
+    target-arm/op_helper.c \
+    target-arm/iwmmxt_helper.c \
+    target-arm/neon_helper.c \
+    target-arm/helper.c \
+    target-arm/translate.c \
+    target-arm/machine.c \
+    hw/armv7m.c \
+    hw/armv7m_nvic.c \
+    arm-semi.c \
+
+LOCAL_SRC_FILES += fpu/softfloat.c
+endif
+
+ifeq ($(EMULATOR_TARGET_ARCH), x86)
+LOCAL_SRC_FILES += \
+    target-i386/op_helper.c \
+    target-i386/helper.c \
+    target-i386/translate.c \
+    target-i386/machine.c \
+
+LOCAL_SRC_FILES += fpu/softfloat-native.c
+endif
+
+# compile KVM only if target is x86 on x86 Linux
+ifeq ($(QEMU_HOST_TAG)-$(EMULATOR_TARGET_ARCH),linux-x86-x86)
+# the following is to include linux/kvm.h
+LOCAL_CFLAGS += -I /usr/include
+LOCAL_SRC_FILES += \
+    target-i386/kvm.c \
+    kvm-all.c
+endif
+
+##############################################################################
+# Memory-access checking support.
+# Memory access checker uses information collected by instrumented code in
+# libc.so in order to keep track of memory blocks allocated from heap. Memory
+# checker then uses this information to make sure that every access to allocated
+# memory is within allocated block. This information also allows detecting
+# memory leaks and attempts to free/realloc invalid pointers.
+#
+LOCAL_CFLAGS += \
+    -I$(LOCAL_PATH)/memcheck \
+    -I$(LOCAL_PATH)/elff
+
+MCHK_SOURCES := \
+    memcheck.c \
+    memcheck_proc_management.c \
+    memcheck_malloc_map.c \
+    memcheck_mmrange_map.c \
+    memcheck_util.c \
+
+LOCAL_SRC_FILES += $(MCHK_SOURCES:%=memcheck/%)
+
+
+$(call end-emulator-library)
+
+##############################################################################
+##############################################################################
+###
+###  qemu-android-$CPU: headless emulator core program
+###
+###
+$(call start-emulator-program, qemu-android-$(EMULATOR_TARGET_ARCH))
+
+LOCAL_CFLAGS += \
+    $(EMULATOR_COMMON_CFLAGS) \
+    $(ELFF_CFLAGS) \
+    $(EMULATOR_LIBQEMU_CFLAGS) \
+    $(EMULATOR_TARGET_CFLAGS) \
+    -DCONFIG_STANDALONE_CORE \
+
+LOCAL_CFLAGS += -Wno-missing-field-initializers
+
+
+LOCAL_STATIC_LIBRARIES := \
+    emulator-libqemu \
+    emulator-target-$(EMULATOR_TARGET_CPU) \
+    emulator-libelff \
+    emulator-common \
+
+
+LOCAL_LDLIBS += \
+    $(EMULATOR_COMMON_LDLIBS) \
+    $(EMULATOR_LIBQEMU_LDLIBS) \
+    $(ELFF_LDLIBS) \
+
+LOCAL_SRC_FILES := \
+    audio/audio.c \
+    disas.c \
+    dma-helpers.c \
+    gdbstub.c \
+    keymaps.c \
+    loader.c \
+    monitor.c \
+    qemu-timer.c \
+    user-events-qemu.c \
+    vl-android.c \
+    android/console.c \
+    android/display-core.c \
+    android/protocol/attach-ui-proxy.c \
+    android/protocol/fb-updates-proxy.c \
+    android/protocol/user-events-impl.c \
+    android/protocol/ui-commands-proxy.c \
+    android/protocol/core-commands-impl.c \
+    android/protocol/core-commands-qemu.c \
+
+$(call gen-hx-header,qemu-monitor.hx,monitor.c)
+$(call gen-hx-header,qemu-options.hx,vl-android.c)
+
+ifeq ($(HOST_OS),darwin)
+    FRAMEWORKS := OpenGL Cocoa QuickTime ApplicationServices Carbon IOKit
+    LOCAL_LDLIBS += $(FRAMEWORKS:%=-Wl,-framework,%)
+endif
+
+# Generate a completely static executable if needed.
+# Note that this means no sound and graphics on Linux.
+#
+ifeq ($(CONFIG_STATIC_EXECUTABLE),true)
+    LOCAL_SRC_FILES += dynlink-static.c
+    LOCAL_LDLIBS    += -static
+endif
+
+# The following files cannot be in static libraries because they contain
+# constructor functions that are otherwise stripped by the final linker
+LOCAL_SRC_FILES += $(HW_OBJ_SOURCES)
+LOCAL_CFLAGS    += $(HW_OBJ_CFLAGS)
+
+LOCAL_SRC_FILES += $(BLOCK_SOURCES)
+LOCAL_CFLAGS    += $(BLOCK_CFLAGS)
+
+LOCAL_MODULE_TAGS := debug
+
+$(call end-emulator-program)
+
+##############################################################################
+##############################################################################
+###
+###  emulator-$ARCH: Standalone emulator program
+###
+###
+
+# Special case, "emulator-arm" is named "emulator" for now.
+ifeq ($(EMULATOR_TARGET_ARCH),arm)
+$(call start-emulator-program, emulator)
+else
+$(call start-emulator-program, emulator-$(EMULATOR_TARGET_ARCH))
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+    emulator-libui \
+    emulator-libqemu \
+    emulator-target-$(EMULATOR_TARGET_CPU) \
+    emulator-libelff \
+    emulator-common \
+
+LOCAL_LDLIBS += \
+    $(EMULATOR_COMMON_LDLIBS) \
+    $(EMULATOR_LIBQEMU_LDLIBS) \
+    $(EMULATOR_LIBUI_LDLIBS) \
+    $(ELFF_LDLIBS) \
+
+LOCAL_CFLAGS += \
+    $(EMULATOR_TARGET_CFLAGS) \
+    $(EMULATOR_COMMON_CFLAGS) \
+    $(EMULATOR_LIBQEMU_CFLAGS) \
+    $(EMULATOR_LIBUI_CFLAGS)
+
+LOCAL_SRC_FILES := \
+    audio/audio.c \
+    disas.c \
+    dma-helpers.c \
+    gdbstub.c \
+    keymaps.c \
+    loader.c \
+    monitor.c \
+    qemu-timer.c \
+    user-events-qemu.c \
+    vl-android.c \
+    android/cmdline-option.c \
+    android/console.c \
+    android/display.c \
+    android/display-core.c \
+    android/help.c \
+    android/main-common.c \
+    android/main.c \
+    android/protocol/core-commands-qemu.c \
+    android/protocol/ui-commands-qemu.c \
+    android/
+
+$(call gen-hx-header,qemu-monitor.hx,monitor.c)
+$(call gen-hx-header,qemu-options.hx,vl-android.c)
+
+# The following files cannot be in static libraries because they contain
+# constructor functions that are otherwise stripped by the final linker
+LOCAL_SRC_FILES += $(HW_OBJ_SOURCES)
+LOCAL_CFLAGS    += $(HW_OBJ_CFLAGS)
+
+LOCAL_SRC_FILES += $(BLOCK_SOURCES)
+LOCAL_CFLAGS    += $(BLOCK_CFLAGS)
+
+LOCAL_SRC_FILES += $(SDLMAIN_SOURCES)
+
+# Generate a completely static executable if needed.
+# Note that this means no sound and graphics on Linux.
+#
+ifeq ($(CONFIG_STATIC_EXECUTABLE),true)
+    LOCAL_SRC_FILES += dynlink-static.c
+    LOCAL_LDLIBS    += -static
+endif
+
+LOCAL_STATIC_LIBRARIES += $(SDL_STATIC_LIBRARIES)
+
+$(call end-emulator-program)
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini
index 6b106f4..6b5caae 100644
--- a/android/avd/hardware-properties.ini
+++ b/android/avd/hardware-properties.ini
@@ -24,6 +24,8 @@
 #
 
 # Ram size
+# Default value will be computed based on screen pixels
+# or skin version
 name        = hw.ramSize
 type        = integer
 default     = 0
@@ -134,6 +136,11 @@
 abstract    = SD Card support
 description = Whether the device supports insertion/removal of virtual SD Cards.
 
+name        = hw.sdCard.path
+type        = string
+default     =
+abstract    = SD Card image path
+
 # Cache partition
 name        = disk.cachePartition
 type        = boolean
@@ -141,11 +148,34 @@
 abstract    = Cache partition support
 description = Whether we use a /cache partition on the device.
 
+name        = disk.cachePartition.path
+type        = string
+default     =
+abstract    = Cache partition
+description = Cache partition to use on the device. Ignored if disk.cachePartition is not 'yes'.
+
 name        = disk.cachePartition.size
 type        = diskSize
 abstract    = Cache partition size
 default     = 66MB
 
+# LCD width
+name        = hw.lcd.width
+type        = integer
+default     = 320
+abstract    = LCD pixel width
+
+name        = hw.lcd.height
+type        = integer
+default     = 640
+abstract    = LCD pixel height
+
+name        = hw.lcd.depth
+type        = integer
+default     = 16
+abstract    = LCD color depth
+description = Must be 16 or 32. Color bit depth of emulated framebuffer.
+
 # LCD density
 name        = hw.lcd.density
 type        = integer
@@ -155,9 +185,10 @@
 
 # Maximum VM heap size
 # Higher values are required for high-dpi devices
+# Default will depend on RAM size.
 name        = vm.heapSize
 type        = integer
-default     = 16
+default     = 0
 abstract    = Max VM application heap size
 description = The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes.
 
@@ -167,3 +198,89 @@
 default     = yes
 abstract    = Proximity support
 description = Whether there is an proximity in the device.
+
+# Kernel image.
+#
+# kernel.path        specified the path to the kernel image
+# kernel.parameters  specifies the string of kernel boot parameters.
+#
+name        = kernel.path
+type        = string
+default     =
+abstract    = Path to the kernel image
+description = Path to the kernel image.
+
+name        = kernel.parameters
+type        = string
+default     =
+abstract    = kernel boot parameters string.
+
+# Path to the ramdisk image.
+name        = disk.ramdisk.path
+type        = string
+default     =
+abstract    = Path to the ramdisk image
+description = Path to the ramdisk image.
+
+# System partition image(s).
+#
+# disk.systemPartition.path points to the read/write system partition image.
+#   if empty, a temporary file will be created, initialized with the content
+#   of .initPath
+#
+# disk.systemPartition.initPath is only used when .path is empty. It must
+# then point to a read-only initialization system image file.
+#
+# disk.systemPartition.size is the ideal size of the system partition. The
+# size is ignored if the actual system partition image is larger. Otherwise,
+# it indicates the maximum size the disk image file can grow to.
+#
+name        = disk.systemPartition.path
+type        = string
+default     =
+abstract    = Path to runtime system partition image
+
+name        = disk.systemPartition.initPath
+type        = string
+default     =
+abstract    = Initial system partition image
+
+name        = disk.systemPartition.size
+type        = diskSize
+default     = 0
+abstract    = Ideal size of system partition
+
+# Path to the data partition.
+name        = disk.dataPartition.path
+type        = string
+default     = <temp>
+abstract    = Path to data partition file
+description = Path to data partition file. Cannot be empty. Special value <temp> means using a temporary file. If disk.dataPartition.initPath is not empty, its content will be copied to the disk.dataPartition.path file at boot-time.
+
+# Initial path to the data partition.
+name        = disk.dataPartition.initPath
+type        = string
+default     =
+abstract    = Initial data partition
+description = If not empty, its content will be copied to the disk.dataPartition.path file at boot-time.
+
+# Data partition size.
+name        = disk.dataPartition.size
+type        = diskSize
+default     = 0
+abstract    = Ideal size of data partition
+
+# Path to the snapshots storage file.
+name        = disk.snapStorage.path
+type        = string
+default     =
+abstract    = Path to snapshot storage
+description = Path to a 'snapshot storage' file, where all snapshots are stored.
+
+# Android AVD name
+# This is set automatically before launching a core.
+#
+name        = avd.name
+type        = string
+default     = <build>
+abstract    = Name of the AVD being run
diff --git a/android/avd/hw-config-defs.h b/android/avd/hw-config-defs.h
index 0c87bdb..0ab1f0f 100644
--- a/android/avd/hw-config-defs.h
+++ b/android/avd/hw-config-defs.h
@@ -129,6 +129,13 @@
   "SD Card support",
   "Whether the device supports insertion/removal of virtual SD Cards.")
 
+HWCFG_STRING(
+  hw_sdCard_path,
+  "hw.sdCard.path",
+  "",
+  "SD Card image path",
+  "")
+
 HWCFG_BOOL(
   disk_cachePartition,
   "disk.cachePartition",
@@ -136,6 +143,13 @@
   "Cache partition support",
   "Whether we use a /cache partition on the device.")
 
+HWCFG_STRING(
+  disk_cachePartition_path,
+  "disk.cachePartition.path",
+  "",
+  "Cache partition",
+  "Cache partition to use on the device. Ignored if disk.cachePartition is not 'yes'.")
+
 HWCFG_DISKSIZE(
   disk_cachePartition_size,
   "disk.cachePartition.size",
@@ -144,6 +158,27 @@
   "")
 
 HWCFG_INT(
+  hw_lcd_width,
+  "hw.lcd.width",
+  320,
+  "LCD pixel width",
+  "")
+
+HWCFG_INT(
+  hw_lcd_height,
+  "hw.lcd.height",
+  640,
+  "LCD pixel height",
+  "")
+
+HWCFG_INT(
+  hw_lcd_depth,
+  "hw.lcd.depth",
+  16,
+  "LCD color depth",
+  "Must be 16 or 32. Color bit depth of emulated framebuffer.")
+
+HWCFG_INT(
   hw_lcd_density,
   "hw.lcd.density",
   160,
@@ -153,7 +188,7 @@
 HWCFG_INT(
   vm_heapSize,
   "vm.heapSize",
-  16,
+  0,
   "Max VM application heap size",
   "The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes.")
 
@@ -164,6 +199,83 @@
   "Proximity support",
   "Whether there is an proximity in the device.")
 
+HWCFG_STRING(
+  kernel_path,
+  "kernel.path",
+  "",
+  "Path to the kernel image",
+  "Path to the kernel image.")
+
+HWCFG_STRING(
+  kernel_parameters,
+  "kernel.parameters",
+  "",
+  "kernel boot parameters string.",
+  "")
+
+HWCFG_STRING(
+  disk_ramdisk_path,
+  "disk.ramdisk.path",
+  "",
+  "Path to the ramdisk image",
+  "Path to the ramdisk image.")
+
+HWCFG_STRING(
+  disk_systemPartition_path,
+  "disk.systemPartition.path",
+  "",
+  "Path to runtime system partition image",
+  "")
+
+HWCFG_STRING(
+  disk_systemPartition_initPath,
+  "disk.systemPartition.initPath",
+  "",
+  "Initial system partition image",
+  "")
+
+HWCFG_DISKSIZE(
+  disk_systemPartition_size,
+  "disk.systemPartition.size",
+  "0",
+  "Ideal size of system partition",
+  "")
+
+HWCFG_STRING(
+  disk_dataPartition_path,
+  "disk.dataPartition.path",
+  "<temp>",
+  "Path to data partition file",
+  "Path to data partition file. Cannot be empty. Special value <temp> means using a temporary file. If disk.dataPartition.initPath is not empty, its content will be copied to the disk.dataPartition.path file at boot-time.")
+
+HWCFG_STRING(
+  disk_dataPartition_initPath,
+  "disk.dataPartition.initPath",
+  "",
+  "Initial data partition",
+  "If not empty, its content will be copied to the disk.dataPartition.path file at boot-time.")
+
+HWCFG_DISKSIZE(
+  disk_dataPartition_size,
+  "disk.dataPartition.size",
+  "0",
+  "Ideal size of data partition",
+  "")
+
+HWCFG_STRING(
+  disk_snapStorage_path,
+  "disk.snapStorage.path",
+  "",
+  "Path to snapshot storage",
+  "Path to a 'snapshot storage' file, where all snapshots are stored.")
+
+HWCFG_STRING(
+  avd_name,
+  "avd.name",
+  "<build>",
+  "Name of the AVD being run",
+  "")
+
 #undef HWCFG_INT
 #undef HWCFG_BOOL
 #undef HWCFG_DISKSIZE
diff --git a/android/avd/info.c b/android/avd/info.c
index 058226c..aaf1111 100644
--- a/android/avd/info.c
+++ b/android/avd/info.c
@@ -84,6 +84,11 @@
  */
 #define  SKIN_PATH       "skin.path"
 
+/* the config.ini key that will be used to indicate the default skin's name.
+ * this is ignored if there is a valid SKIN_PATH entry in the file.
+ */
+#define  SKIN_NAME       "skin.name"
+
 /* default skin name */
 #define  SKIN_DEFAULT    "HVGA"
 
@@ -93,6 +98,12 @@
  */
 #define  SDCARD_PATH     "sdcard.path"
 
+/* the name of the .ini file that will contain the complete hardware
+ * properties for the AVD. This will be used to launch the corresponding
+ * core from the UI.
+ */
+#define  CORE_HARDWARE_INI   "hardware-qemu.ini"
+
 /* certain disk image files are mounted read/write by the emulator
  * to ensure that several emulators referencing the same files
  * do not corrupt these files, we need to lock them and respond
@@ -124,6 +135,7 @@
     char      inAndroidBuild;
     char*     androidOut;
     char*     androidBuildRoot;
+    char*     targetArch;
 
     /* for the normal virtual device case */
     char*     deviceName;
@@ -132,13 +144,14 @@
     char*     searchPaths[ MAX_SEARCH_PATHS ];
     int       numSearchPaths;
     char*     contentPath;
-    IniFile*  rootIni;      /* root <foo>.ini file */
-    IniFile*  configIni;    /* virtual device's config.ini */
-    IniFile*  hardwareIni;  /* skin-specific hardware.ini */
+    IniFile*  rootIni;      /* root <foo>.ini file, empty if missing */
+    IniFile*  configIni;    /* virtual device's config.ini, NULL if missing */
+    IniFile*  skinHardwareIni;  /* skin-specific hardware.ini */
 
     /* for both */
     char*     skinName;     /* skin name */
     char*     skinDirPath;  /* skin directory */
+    char*     coreHardwareIniPath;  /* core hardware.ini path */
 
     /* image files */
     char*     imagePath [ AVD_IMAGE_MAX ];
@@ -157,6 +170,7 @@
 
         AFREE(i->skinName);
         AFREE(i->skinDirPath);
+        AFREE(i->coreHardwareIniPath);
 
         for (nn = 0; nn < i->numSearchPaths; nn++)
             AFREE(i->searchPaths[nn]);
@@ -168,9 +182,9 @@
             i->configIni = NULL;
         }
 
-        if (i->hardwareIni) {
-            iniFile_free(i->hardwareIni);
-            i->hardwareIni = NULL;
+        if (i->skinHardwareIni) {
+            iniFile_free(i->skinHardwareIni);
+            i->skinHardwareIni = NULL;
         }
 
         if (i->rootIni) {
@@ -208,80 +222,99 @@
 /***************************************************************
  ***************************************************************
  *****
- *****    NORMAL VIRTUAL DEVICE SUPPORT
+ *****    UTILITY FUNCTIONS
+ *****
+ *****  The following functions do not depend on the AvdInfo
+ *****  structure and could easily be moved elsewhere.
  *****
  *****/
 
-/* compute path to the root SDK directory
- * assume we are in $SDKROOT/tools/emulator[.exe]
+/* Return the path to the Android SDK root installation.
+ *
+ * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT
+ * environment variable, or 0 otherwise.
+ *
+ * Caller must free() returned string.
  */
-static int
-_getSdkRoot( AvdInfo*  i )
+static char*
+_getSdkRoot( char *pFromEnv )
 {
     const char*  env;
+    char*        sdkPath;
     char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
 
+    /* If ANDROID_SDK_ROOT is defined is must point to a directory
+     * containing a valid SDK installation.
+     */
 #define  SDK_ROOT_ENV  "ANDROID_SDK_ROOT"
 
     env = getenv(SDK_ROOT_ENV);
     if (env != NULL && env[0] != 0) {
         if (path_exists(env)) {
             D("found " SDK_ROOT_ENV ": %s", env);
-            i->sdkRootPath = ASTRDUP(env);
-            i->sdkRootPathFromEnv = 1;
-            return 0;
+            *pFromEnv = 1;
+            return ASTRDUP(env);
         }
         D(SDK_ROOT_ENV " points to unknown directory: %s", env);
     }
 
-    (void) bufprint_app_dir(temp, end);
+    *pFromEnv = 0;
 
-    i->sdkRootPath = path_parent(temp, 1);
-    if (i->sdkRootPath == NULL) {
+    /* We assume the emulator binary is under tools/ so use its
+     * parent as the Android SDK root.
+     */
+    (void) bufprint_app_dir(temp, end);
+    sdkPath = path_parent(temp, 1);
+    if (sdkPath == NULL) {
         derror("can't find root of SDK directory");
-        return -1;
+        return NULL;
     }
-    D("found SDK root at %s", i->sdkRootPath);
-    return 0;
+    D("found SDK root at %s", sdkPath);
+    return sdkPath;
 }
 
-static void
-_getSearchPaths( AvdInfo*  i )
+/* Parse a given config.ini file and extract the list of SDK search paths
+ * from it. Returns the number of valid paths stored in 'searchPaths', or -1
+ * in case of problem.
+ *
+ * Relative search paths in the config.ini will be stored as full pathnames
+ * relative to 'sdkRootPath'.
+ *
+ * 'searchPaths' must be an array of char* pointers of at most 'maxSearchPaths'
+ * entries.
+ */
+static int
+_getSearchPaths( IniFile*    configIni,
+                 const char* sdkRootPath,
+                 int         maxSearchPaths,
+                 char**      searchPaths )
 {
     char  temp[PATH_MAX], *p = temp, *end= p+sizeof temp;
     int   nn, count = 0;
 
-
-
-    for (nn = 0; nn < MAX_SEARCH_PATHS; nn++) {
+    for (nn = 0; nn < maxSearchPaths; nn++) {
         char*  path;
 
         p = bufprint(temp, end, "%s%d", SEARCH_PREFIX, nn+1 );
         if (p >= end)
             continue;
 
-        path = iniFile_getString( i->configIni, temp, NULL );
+        path = iniFile_getString(configIni, temp, NULL);
         if (path != NULL) {
             DD("    found image search path: %s", path);
             if (!path_is_absolute(path)) {
-                p = bufprint(temp, end, "%s/%s", i->sdkRootPath, path);
+                p = bufprint(temp, end, "%s/%s", sdkRootPath, path);
                 AFREE(path);
                 path = ASTRDUP(temp);
             }
-            i->searchPaths[count++] = path;
+            searchPaths[count++] = path;
         }
     }
-
-    i->numSearchPaths = count;
-    if (count == 0) {
-        derror("no search paths found in this AVD's configuration.\n"
-               "Weird, the AVD's config.ini file is malformed. Try re-creating it.\n");
-        exit(2);
-    }
-    else
-        DD("found a total of %d search paths for this AVD", count);
+    return count;
 }
 
+/* Check that an AVD name is valid. Returns 1 on success, 0 otherwise.
+ */
 static int
 _checkAvdName( const char*  name )
 {
@@ -292,533 +325,120 @@
     return (len == len2);
 }
 
-/* parse the root config .ini file. it is located in
+/* Return the path to the AVD's root configuration .ini file. it is located in
  * ~/.android/avd/<name>.ini or Windows equivalent
+ *
+ * This file contains the path to the AVD's content directory, which
+ * includes its own config.ini.
  */
-static int
-_getRootIni( AvdInfo*  i )
+static char*
+_getRootIniPath( const char*  avdName )
 {
-    char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+    char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
 
     p = bufprint_config_path(temp, end);
-    p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", i->deviceName);
+    p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", avdName);
     if (p >= end) {
-        derror("device name too long");
-        return -1;
-    }
-
-    i->rootIni = iniFile_newFromFile(temp);
-    if (i->rootIni == NULL) {
-        derror("unknown virtual device name: '%s'", i->deviceName);
-        return -1;
-    }
-    D("root virtual device file at %s", temp);
-    return 0;
-}
-
-/* the .ini variable name that points to the content directory
- * in a root AVD ini file. This is required */
-#   define  ROOT_PATH_KEY    "path"
-
-static int
-_getContentPath( AvdInfo*  i )
-{
-    i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY, NULL);
-
-    if (i->contentPath == NULL) {
-        derror("bad config: %s",
-               "virtual device file lacks a "ROOT_PATH_KEY" entry");
-        return -1;
-    }
-    D("virtual device content at %s", i->contentPath);
-    return 0;
-}
-
-/* find and parse the config.ini file from the content directory */
-static int
-_getConfigIni(AvdInfo*  i)
-{
-    char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
-    p = bufprint(p, end, "%s/config.ini", i->contentPath);
-    if (p >= end) {
-        derror("can't access virtual device content directory");
-        return -1;
-    }
-
-#if 1   /* XXX: TODO: remove this in the future */
-    /* for now, allow a non-existing config.ini */
-    if (!path_exists(temp)) {
-        D("virtual device has no config file - no problem");
-        return 0;
-    }
-#endif
-
-    i->configIni = iniFile_newFromFile(temp);
-    if (i->configIni == NULL) {
-        derror("bad config: %s",
-               "virtual device directory lacks config.ini");
-        return -1;
-    }
-    D("virtual device config file: %s", temp);
-    return 0;
-}
-
-/***************************************************************
- ***************************************************************
- *****
- *****    KERNEL/DISK IMAGE LOADER
- *****
- *****/
-
-/* a structure used to handle the loading of
- * kernel/disk images.
- */
-typedef struct {
-    AvdInfo*        info;
-    AvdInfoParams*  params;
-    AvdImageType    id;
-    const char*     imageFile;
-    const char*     imageText;
-    char**          pPath;
-    char*           pState;
-    char            temp[PATH_MAX];
-} ImageLoader;
-
-static void
-imageLoader_init( ImageLoader*  l, AvdInfo*  info, AvdInfoParams*  params )
-{
-    memset(l, 0, sizeof(*l));
-    l->info    = info;
-    l->params  = params;
-}
-
-/* set the type of the image to load */
-static void
-imageLoader_set( ImageLoader*  l, AvdImageType  id )
-{
-    l->id        = id;
-    l->imageFile = _imageFileNames[id];
-    l->imageText = _imageFileText[id];
-    l->pPath     = &l->info->imagePath[id];
-    l->pState    = &l->info->imageState[id];
-
-    l->pState[0] = IMAGE_STATE_READONLY;
-}
-
-/* change the image path */
-static char*
-imageLoader_setPath( ImageLoader*  l, const char*  path )
-{
-    path = path ? ASTRDUP(path) : NULL;
-
-    AFREE(l->pPath[0]);
-    l->pPath[0] = (char*) path;
-
-    return (char*) path;
-}
-
-static char*
-imageLoader_extractPath( ImageLoader*  l )
-{
-    char*  result = l->pPath[0];
-    l->pPath[0] = NULL;
-    return result;
-}
-
-/* flags used when loading images */
-enum {
-    IMAGE_REQUIRED          = (1<<0),  /* image is required */
-    IMAGE_SEARCH_SDK        = (1<<1),  /* search image in SDK */
-    IMAGE_EMPTY_IF_MISSING  = (1<<2),  /* create empty file if missing */
-    IMAGE_DONT_LOCK         = (1<<4),  /* don't try to lock image */
-    IMAGE_IGNORE_IF_LOCKED  = (1<<5),  /* ignore file if it's locked */
-};
-
-#define  IMAGE_OPTIONAL  0
-
-/* find an image from the SDK search directories.
- * returns the full path or NULL if the file could not be found.
- *
- * note: this stores the result in the image's path as well
- */
-static char*
-imageLoader_lookupSdk( ImageLoader*  l  )
-{
-    AvdInfo*     i     = l->info;
-    const char*  image = l->imageFile;
-    char*        temp  = l->temp, *p = temp, *end = p + sizeof(l->temp);
-
-    do {
-        /* try the search paths */
-        int  nn;
-
-        for (nn = 0; nn < i->numSearchPaths; nn++) {
-            const char* searchDir = i->searchPaths[nn];
-
-            p = bufprint(temp, end, "%s/%s", searchDir, image);
-            if (p < end && path_exists(temp)) {
-                DD("found %s in search dir: %s", image, searchDir);
-                goto FOUND;
-            }
-            DD("    no %s in search dir: %s", image, searchDir);
-        }
-
-        return NULL;
-
-    } while (0);
-
-FOUND:
-    l->pState[0] = IMAGE_STATE_READONLY;
-
-    return imageLoader_setPath(l, temp);
-}
-
-/* search for a file in the content directory.
- * returns NULL if the file cannot be found.
- *
- * note that this formats l->temp with the file's path
- * allowing you to retrieve it if the function returns NULL
- */
-static char*
-imageLoader_lookupContent( ImageLoader*  l )
-{
-    AvdInfo*  i     = l->info;
-    char*     temp  = l->temp, *p = temp, *end = p + sizeof(l->temp);
-
-    p = bufprint(temp, end, "%s/%s", i->contentPath, l->imageFile);
-    if (p >= end) {
-        derror("content directory path too long");
-        exit(2);
-    }
-    if (!path_exists(temp)) {
-        DD("    no %s in content directory", l->imageFile);
         return NULL;
     }
-    DD("found %s in content directory", l->imageFile);
-
-    /* assume content image files must be locked */
-    l->pState[0] = IMAGE_STATE_MUSTLOCK;
-
-    return imageLoader_setPath(l, temp);
-}
-
-/* lock a file image depending on its state and user flags
- * note that this clears l->pPath[0] if the lock could not
- * be acquired and that IMAGE_IGNORE_IF_LOCKED is used.
- */
-static void
-imageLoader_lock( ImageLoader*  l, unsigned  flags )
-{
-    const char*  path = l->pPath[0];
-
-    if (flags & IMAGE_DONT_LOCK)
-        return;
-
-    if (l->pState[0] != IMAGE_STATE_MUSTLOCK)
-        return;
-
-    D("    locking %s image at %s", l->imageText, path);
-
-    if (filelock_create(path) != NULL) {
-        /* succesful lock */
-        l->pState[0] = IMAGE_STATE_LOCKED;
-        return;
+    if (!path_exists(temp)) {
+        return NULL;
     }
-
-    if (flags & IMAGE_IGNORE_IF_LOCKED) {
-        dwarning("ignoring locked %s image at %s", l->imageText, path);
-        imageLoader_setPath(l, NULL);
-        return;
-    }
-
-    derror("the %s image is used by another emulator. aborting",
-            l->imageText);
-    exit(2);
-}
-
-/* make a file image empty, this may require locking */
-static void
-imageLoader_empty( ImageLoader*  l, unsigned  flags )
-{
-    const char*  path;
-
-    imageLoader_lock(l, flags);
-
-    path = l->pPath[0];
-    if (path == NULL)  /* failed to lock, caller will handle it */
-        return;
-
-    if (path_empty_file(path) < 0) {
-        derror("could not create %s image at %s: %s",
-                l->imageText, path, strerror(errno));
-        exit(2);
-    }
-    l->pState[0] = IMAGE_STATE_LOCKED_EMPTY;
+    return ASTRDUP(temp);
 }
 
 
-/* copy image file from a given source 
- * assumes locking is needed.
- */
-static void
-imageLoader_copyFrom( ImageLoader*  l, const char*  srcPath )
-{
-    const char*  dstPath = NULL;
-
-    /* find destination file */
-    if (l->params) {
-        dstPath = l->params->forcePaths[l->id];
-    }
-    if (!dstPath) {
-        imageLoader_lookupContent(l);
-        dstPath = l->temp;
-    }
-
-    /* lock destination */
-    imageLoader_setPath(l, dstPath);
-    l->pState[0] = IMAGE_STATE_MUSTLOCK;
-    imageLoader_lock(l, 0);
-
-    /* make the copy */
-    if (path_copy_file(dstPath, srcPath) < 0) {
-        derror("can't initialize %s image from SDK: %s: %s",
-               l->imageText, dstPath, strerror(errno));
-        exit(2);
-    }
-}
-
-/* this will load and eventually lock and image file, depending
- * on the flags being used. on exit, this function udpates
- * l->pState[0] and l->pPath[0]
+/* Retrieves a string corresponding to the target architecture
+ * when in the Android platform tree. The only way to do that
+ * properly for now is to look at $OUT/system/build.prop:
  *
- * returns the path to the file. Note that it returns NULL
- * only if the file was optional and could not be found.
+ *   ro.product.cpu-abi=<abi>
  *
- * if the file is required and missing, the function aborts
- * the program.
+ * Where <abi> can be 'armeabi', 'armeabi-v7a' or 'x86'.
  */
-static char*
-imageLoader_load( ImageLoader*    l,
-                  unsigned        flags )
+static const char*
+_getBuildTargetArch( const char* androidOut )
 {
-    const char*  path = NULL;
+    const char* arch = "arm";
+    char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+    FILE*  file;
 
-    /* set image state */
-    l->pState[0] = (flags & IMAGE_DONT_LOCK) == 0
-                 ? IMAGE_STATE_MUSTLOCK 
-                 : IMAGE_STATE_READONLY;
+#define ABI_PREFIX       "ro.product.cpu.abi="
+#define ABI_PREFIX_LEN   (sizeof(ABI_PREFIX)-1)
 
-    /* check user-provided path */
-    path = l->params->forcePaths[l->id];
-    if (path != NULL) {
-        imageLoader_setPath(l, path);
-        if (path_exists(path)) {
-            DD("found user-provided %s image: %s", l->imageText, l->imageFile);
-            goto EXIT;
-        }
-        D("user-provided %s image does not exist: %s",
-          l->imageText, path);
-
-        /* if the file is required, abort */
-        if (flags & IMAGE_REQUIRED) {
-            derror("user-provided %s image at %s doesn't exist",
-                    l->imageText, path);
-            exit(2);
-        }
+    p = bufprint(temp, end, "%s/system/build.prop", androidOut);
+    if (p >= end) {
+        D("%s: ANDROID_PRODUCT_OUT too long: %s", __FUNCTION__, androidOut);
+        goto EXIT;
     }
-    else {
-        const char*  contentFile;
-
-        /* second, look in the content directory */
-        path = imageLoader_lookupContent(l);
-        if (path) goto EXIT;
-
-        contentFile = ASTRDUP(l->temp);
-
-        /* it's not there */
-        if (flags & IMAGE_SEARCH_SDK) {
-            /* third, look in the SDK directory */
-            path = imageLoader_lookupSdk(l);
-            if (path) {
-                AFREE((char*)contentFile);
-                goto EXIT;
-            }
-        }
-        DD("found no %s image (%s)", l->imageText, l->imageFile);
-
-        /* if the file is required, abort */
-        if (flags & IMAGE_REQUIRED) {
-            AvdInfo*  i = l->info;
-
-            derror("could not find required %s image (%s).", 
-                   l->imageText, l->imageFile);
-
-            if (i->inAndroidBuild) {
-                dprint( "Did you build everything ?" );
-            } else if (!i->sdkRootPathFromEnv) {
-                dprint( "Maybe defining %s to point to a valid SDK "
-                        "installation path might help ?", SDK_ROOT_ENV );
-            } else {
-                dprint( "Your %s is probably wrong: %s", SDK_ROOT_ENV,
-                        i->sdkRootPath );
-            }
-            exit(2);
-        }
-
-        path = imageLoader_setPath(l, contentFile);
-        AFREE((char*)contentFile);
+    file = fopen(temp, "rb");
+    if (file == NULL) {
+        D("Could not open file: %s: %s", temp, strerror(errno));
+        D("Default target architecture=%s", arch);
+        goto EXIT;
     }
 
-    /* otherwise, do we need to create it ? */
-    if (flags & IMAGE_EMPTY_IF_MISSING) {
-        imageLoader_empty(l, flags);
-        return l->pPath[0];
-    }
-    return NULL;
+    while (fgets(temp, sizeof temp, file) != NULL) {
+        /* Trim trailing newlines, if any */
+        p = memchr(temp, '\0', sizeof temp);
+        if (p == NULL)
+            p = end;
+        if (p > temp && p[-1] == '\n') {
+            *--p = '\0';
+        }
+        if (p > temp && p[-1] == '\r') {
+            *--p = '\0';
+        }
+        /* force zero-termination in case of full-buffer */
+        if (p == end)
+            *--p = '\0';
 
+        if (memcmp(temp, ABI_PREFIX, ABI_PREFIX_LEN) != 0) {
+            continue;
+        }
+        p = temp + ABI_PREFIX_LEN;
+        if (p >= end || !*p)
+            goto EXIT2;
+
+        if (!strcmp("armeabi",p))
+            arch = "arm";
+        else if (!strcmp("armeabi-v7a",p))
+            arch = "arm";
+        else
+            arch = p;
+
+        D("Found target ABI=%s, architecture=%s", p, arch);
+        goto EXIT2;
+    }
+
+    D("Could not find target architecture, defaulting to %s", arch);
+EXIT2:
+    fclose(file);
 EXIT:
-    imageLoader_lock(l, flags);
-    return l->pPath[0];
+    return arch;
 }
 
-/* Attempts to load an AVD image, but does not kill the process if loading
- * fails.
+/* Returns the full path of a given file.
+ *
+ * If 'fileName' is an absolute path, this returns a simple copy.
+ * Otherwise, this returns a new string corresponding to <rootPath>/<fileName>
+ *
+ * This returns NULL if the paths are too long.
  */
-static void
-imageLoader_loadOptional( ImageLoader *l, AvdImageType img_type,
-                           const char *forcedPath )
+static char*
+_getFullFilePath( const char* rootPath, const char* fileName )
 {
-    imageLoader_set (l, img_type);
-    imageLoader_load(l, IMAGE_OPTIONAL |
-                        IMAGE_IGNORE_IF_LOCKED);
+    if (path_is_absolute(fileName)) {
+        return ASTRDUP(fileName);
+    } else {
+        char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
 
-    /* if the file was not found, ignore it */
-    if (l->pPath[0] && !path_exists(l->pPath[0]))
-    {
-        D("ignoring non-existing %s at %s: %s",
-          l->imageText, l->pPath[0], strerror(errno));
-
-        /* if the user provided the path by hand, warn him. */
-        if (forcedPath != NULL)
-            dwarning("ignoring non-existing %s image", l->imageText);
-
-        imageLoader_setPath(l, NULL);
-    }
-}
-
-/* find the correct path of all image files we're going to need
- * and lock the files that need it.
- */
-static int
-_getImagePaths(AvdInfo*  i, AvdInfoParams*  params )
-{
-    int   wipeData    = (params->flags & AVDINFO_WIPE_DATA) != 0;
-    int   wipeCache   = (params->flags & AVDINFO_WIPE_CACHE) != 0;
-    int   noCache     = (params->flags & AVDINFO_NO_CACHE) != 0;
-    int   noSdCard    = (params->flags & AVDINFO_NO_SDCARD) != 0;
-#if CONFIG_ANDROID_SNAPSHOTS
-    int   noSnapshots = (params->flags & AVDINFO_NO_SNAPSHOTS) != 0;
-#endif
-
-    ImageLoader  l[1];
-
-    imageLoader_init(l, i, params);
-
-    /* pick up the kernel and ramdisk image files - these don't
-     * need a specific handling.
-     */
-    imageLoader_set ( l, AVD_IMAGE_KERNEL );
-    imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
-
-    imageLoader_set ( l, AVD_IMAGE_RAMDISK );
-    imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
-
-    /* the system image
-     *
-     * if there is one in the content directory just lock
-     * and use it.
-     */
-    imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
-    imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
-
-    /* the data partition - this one is special because if it
-     * is missing, we need to copy the initial image file into it.
-     *
-     * first, try to see if it is in the content directory
-     * (or the user-provided path)
-     */
-    imageLoader_set( l, AVD_IMAGE_USERDATA );
-    if ( !imageLoader_load( l, IMAGE_OPTIONAL |
-                               IMAGE_DONT_LOCK ) )
-    {
-        /* it's not, we're going to initialize it. simply
-         * forcing a data wipe should be enough */
-        D("initializing new data partition image: %s", l->pPath[0]);
-        wipeData = 1;
-    }
-
-    if (wipeData) {
-        /* find SDK source file */
-        const char*  srcPath;
-
-        imageLoader_set( l, AVD_IMAGE_INITDATA );
-        if (imageLoader_lookupSdk(l) == NULL) {
-            derror("can't locate initial %s image in SDK",
-                l->imageText);
-            exit(2);
+        p = bufprint(temp, end, "%s/%s", rootPath, fileName);
+        if (p >= end) {
+            return NULL;
         }
-        srcPath = imageLoader_extractPath(l);
-
-        imageLoader_set( l, AVD_IMAGE_USERDATA );
-        imageLoader_copyFrom( l, srcPath );
-        AFREE((char*) srcPath);
+        return ASTRDUP(temp);
     }
-    else
-    {
-        /* lock the data partition image */
-        l->pState[0] = IMAGE_STATE_MUSTLOCK;
-        imageLoader_lock( l, 0 );
-    }
-
-    /* the cache partition: unless the user doesn't want one,
-     * we're going to create it in the content directory
-     */
-    if (!noCache) {
-        imageLoader_set (l, AVD_IMAGE_CACHE);
-        imageLoader_load(l, IMAGE_OPTIONAL |
-                            IMAGE_EMPTY_IF_MISSING );
-
-        if (wipeCache) {
-            if (path_empty_file(l->pPath[0]) < 0) {
-                derror("cannot wipe %s image at %s: %s",
-                       l->imageText, l->pPath[0],
-                       strerror(errno));
-                exit(2);
-            }
-        }
-    }
-
-    /* the SD Card image. unless the user doesn't want to, we're
-     * going to mount it if available. Note that if the image is
-     * already used, we must ignore it.
-     */
-    if (!noSdCard) {
-        imageLoader_loadOptional(l, AVD_IMAGE_SDCARD,
-                                 params->forcePaths[AVD_IMAGE_SDCARD]);
-    }
-
-#if CONFIG_ANDROID_SNAPSHOTS
-    /* the state snapshot image. Mounting behaviour identical to
-     * SD card.
-     */
-    if (!noSnapshots) {
-        imageLoader_loadOptional(l, AVD_IMAGE_SNAPSHOTS,
-                                 params->forcePaths[AVD_IMAGE_SNAPSHOTS]);
-    }
-#endif
-
-    return 0;
 }
 
 /* check that a given directory contains a valid skin.
@@ -837,39 +457,35 @@
     return 1;
 }
 
-/* check that there is a skin named 'skinName' listed from 'skinDirRoot'
- * this returns 1 on success, 0 on failure
- * on success, the 'temp' buffer will get the path containing the real
- * skin directory (after alias expansion), including the skin name.
+/* Check that there is a skin named 'skinName' listed from 'skinDirRoot'
+ * this returns the full path of the skin directory (after alias expansions),
+ * including the skin name, or NULL on failure.
  */
-static int
-_checkSkinDir( char*        temp,
-               char*        end,
-               const char*  skinDirRoot,
+static char*
+_checkSkinSkinsDir( const char*  skinDirRoot,
                const char*  skinName )
 {
     DirScanner*  scanner;
-    char        *p;
-    int          result;
+    char*        result;
+    char         temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
 
-    p = bufprint(temp, end, "%s/skins/%s",
-                 skinDirRoot, skinName);
-
+    p = bufprint(temp, end, "%s/skins/%s", skinDirRoot, skinName);
+    DD("Probing skin directory: %s", temp);
     if (p >= end || !path_exists(temp)) {
         DD("    ignore bad skin directory %s", temp);
-        return 0;
+        return NULL;
     }
 
     /* first, is this a normal skin directory ? */
     if (_checkSkinPath(temp)) {
         /* yes */
         DD("    found skin directory: %s", temp);
-        return 1;
+        return ASTRDUP(temp);
     }
 
     /* second, is it an alias to another skin ? */
     *p      = 0;
-    result  = 0;
+    result  = NULL;
     scanner = dirScanner_new(temp);
     if (scanner != NULL) {
         for (;;) {
@@ -881,14 +497,12 @@
             if (strncmp(file, "alias-", 6) || file[6] == 0)
                 continue;
 
-            p = bufprint(temp, end, "%s/skins/%s",
-                            skinDirRoot, file+6);
-
+            p = bufprint(temp, end, "%s/skins/%s", skinDirRoot, file+6);
             if (p < end && _checkSkinPath(temp)) {
                 /* yes, it's an alias */
                 DD("    skin alias '%s' points to skin directory: %s",
                    file+6, temp);
-                result = 1;
+                result = ASTRDUP(temp);
                 break;
             }
         }
@@ -899,10 +513,14 @@
 
 /* try to see if the skin name leads to a magic skin or skin path directly
  * returns 1 on success, 0 on error.
- * on success, this sets up 'skinDirPath' and 'skinName' in the AvdInfo.
+ *
+ * on success, this sets up '*pSkinName' and '*pSkinDir'
  */
 static int
-_getSkinPathFromName( AvdInfo*  i, const char*  skinName )
+_getSkinPathFromName( const char*  skinName,
+                      const char*  sdkRootPath,
+                      char**       pSkinName,
+                      char**       pSkinDir )
 {
     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
 
@@ -914,19 +532,19 @@
         int  width, height;
         if (sscanf(skinName, "%dx%d", &width, &height) == 2) {
             D("'magic' skin format detected: %s", skinName);
-            i->skinName    = ASTRDUP(skinName);
-            i->skinDirPath = NULL;
+            *pSkinName = ASTRDUP(skinName);
+            *pSkinDir  = NULL;
             return 1;
         }
     }
 
     /* is the skin name a direct path to the skin directory ? */
-    if (_checkSkinPath(skinName)) {
+    if (path_is_absolute(skinName) && _checkSkinPath(skinName)) {
         goto FOUND_IT;
     }
 
     /* is the skin name a relative path from the SDK root ? */
-    p = bufprint(temp, end, "%s/%s", i->sdkRootPath, skinName);
+    p = bufprint(temp, end, "%s/%s", sdkRootPath, skinName);
     if (p < end && _checkSkinPath(temp)) {
         skinName = temp;
         goto FOUND_IT;
@@ -936,156 +554,230 @@
     return 0;
 
 FOUND_IT:
-    if (path_split(skinName, &i->skinDirPath, &i->skinName) < 0) {
+    if (path_split(skinName, pSkinDir, pSkinName) < 0) {
         derror("malformed skin name: %s", skinName);
         exit(2);
     }
-    D("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
+    D("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
     return 1;
 }
 
-/* return 0 on success, -1 on error */
+/***************************************************************
+ ***************************************************************
+ *****
+ *****    NORMAL VIRTUAL DEVICE SUPPORT
+ *****
+ *****/
+
+/* compute path to the root SDK directory
+ * assume we are in $SDKROOT/tools/emulator[.exe]
+ */
 static int
-_getSkin( AvdInfo*  i, AvdInfoParams*  params )
+_avdInfo_getSdkRoot( AvdInfo*  i )
 {
-    char*  skinName;
-    char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-    char   explicitSkin = 1;
 
-    /* this function is used to compute the 'skinName' and 'skinDirPath'
-     * fields of the AvdInfo.
-     */
-
-    /* processing here is a bit tricky, so here's how it happens
-     *
-     * - command-line option '-skin <name>' can be used to specify the
-     *   name of a skin, to override the AVD settings.
-     *
-     * - skins are searched from <dir>/../skins for each <dir> in the
-     *   images search list, unless a '-skindir <path>' option has been
-     *   provided on the command-line
-     *
-     * - otherwise, the config.ini can also contain a SKIN_PATH key that
-     *   shall  give the full path to the skin directory, either relative
-     *   to the SDK root, or an absolute path.
-     *
-     * - skin names like '320x480' corresponds to "magic skins" that
-     *   simply display a framebuffer, without any ornaments of the
-     *   corresponding size. They do not correspond to any real skin
-     *   directory / files and are handled later. But they must be
-     *   recognized here and report a NULL skindir.
-     */
-    if (params->skinName) {
-        skinName = ASTRDUP(params->skinName);
-    } else {
-        skinName = iniFile_getString( i->configIni, SKIN_PATH, NULL );
-        explicitSkin = 0;
-    }
-
-    /* first, check that the skin name is not magic or a direct
-     * directory path
-     */
-    if (skinName != NULL && _getSkinPathFromName(i, skinName)) {
-        AFREE(skinName);
-        return 0;
-    }
-
-    /* if not, the default skinName is "HVGA" */
-    if (skinName == NULL) {
-        skinName = ASTRDUP(SKIN_DEFAULT);
-        explicitSkin = 0;
-    }
-
-    i->skinName = skinName;
-
-    /* now try to find the skin directory for that name -
-     * first try the content directory */
-    do {
-        /* if there is a single 'skin' directory in
-         * the content directory, assume that's what the
-         * user wants,  unless an explicit name was given
-         */
-        if (!explicitSkin) {
-            p = bufprint(temp, end, "%s/skin", i->contentPath);
-            if (p < end && _checkSkinPath(temp)) {
-                D("using skin content from %s", temp);
-                AFREE(i->skinName);
-                i->skinName    = ASTRDUP("skin");
-                i->skinDirPath = ASTRDUP(i->contentPath);
-                return 0;
-            }
-        }
-
-        /* look in content directory */
-        if (_checkSkinDir(temp, end, i->contentPath, skinName))
-            break;
-
-        /* look in the search paths. For each <dir> in the list,
-         * look the skins in <dir>/.. */
-        {
-            int  nn;
-            for (nn = 0; nn < i->numSearchPaths; nn++) {
-                char*  parentDir = path_parent(i->searchPaths[nn], 1);
-                int    ret;
-                if (parentDir == NULL)
-                    continue;
-                ret=_checkSkinDir(temp, end, parentDir, skinName);
-                AFREE(parentDir);
-                if (ret)
-                  break;
-            }
-            if (nn < i->numSearchPaths)
-                break;
-        }
-
-        /* didn't find it */
-        if (explicitSkin) {
-            derror("could not find directory for skin '%s',"
-                   " please use a different name", skinName);
-            exit(2);
-        } else {
-            dwarning("no skin directory matched '%s', so reverted to default",
-                     skinName);
-            AFREE(i->skinName);
-            params->skinName = SKIN_DEFAULT;
-            return _getSkin(i, params);
-        }
-
+    i->sdkRootPath = _getSdkRoot(&i->sdkRootPathFromEnv);
+    if (i->sdkRootPath == NULL)
         return -1;
 
-    } while (0);
-
-    /* separate skin name from parent directory. the skin name
-     * returned in 'temp' might be different from the original
-     * one due to alias expansion so strip it.
-     */
-    AFREE(i->skinName);
-
-    if (path_split(temp, &i->skinDirPath, &i->skinName) < 0) {
-        derror("weird skin path: %s", temp);
-        return -1;
-    }
-    DD("found skin '%s' in directory: %s", i->skinName, i->skinDirPath);
     return 0;
 }
 
-/* If the user didn't explicitely provide an SD Card path,
- * check the SDCARD_PATH key in config.ini and use that if
- * available.
+/* parse the root config .ini file. it is located in
+ * ~/.android/avd/<name>.ini or Windows equivalent
+ */
+static int
+_avdInfo_getRootIni( AvdInfo*  i )
+{
+    char*  iniPath = _getRootIniPath( i->deviceName );
+
+    if (iniPath == NULL) {
+        derror("unknown virtual device name: '%s'", i->deviceName);
+        return -1;
+    }
+
+    D("Android virtual device file at: %s", iniPath);
+
+    i->rootIni = iniFile_newFromFile(iniPath);
+    AFREE(iniPath);
+
+    if (i->rootIni == NULL) {
+        derror("Corrupt virtual device config file!");
+        return -1;
+    }
+    return 0;
+}
+
+/* Returns the AVD's content path, i.e. the directory that contains
+ * the AVD's content files (e.g. data partition, cache, sd card, etc...).
+ *
+ * We extract this by parsing the root config .ini file, looking for
+ * a "path" elements.
+ */
+static int
+_avdInfo_getContentPath( AvdInfo*  i )
+{
+#   define  ROOT_PATH_KEY    "path"
+
+    i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY, NULL);
+
+    if (i->contentPath == NULL) {
+        derror("bad config: %s",
+               "virtual device file lacks a "ROOT_PATH_KEY" entry");
+        return -1;
+    }
+    D("virtual device content at %s", i->contentPath);
+    return 0;
+}
+
+/* Look for a named file inside the AVD's content directory.
+ * Returns NULL if it doesn't exist, or a strdup() copy otherwise.
+ */
+static char*
+_avdInfo_getContentFilePath(AvdInfo*  i, const char* fileName)
+{
+    char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
+
+    p = bufprint(p, end, "%s/%s", i->contentPath, fileName);
+    if (p >= end) {
+        derror("can't access virtual device content directory");
+        return NULL;
+    }
+    if (!path_exists(temp)) {
+        return NULL;
+    }
+    return ASTRDUP(temp);
+}
+
+/* find and parse the config.ini file from the content directory */
+static int
+_avdInfo_getConfigIni(AvdInfo*  i)
+{
+    char*  iniPath = _avdInfo_getContentFilePath(i, "config.ini");
+
+    /* Allow non-existing config.ini */
+    if (iniPath == NULL) {
+        D("virtual device has no config file - no problem");
+        return 0;
+    }
+
+    D("virtual device config file: %s", iniPath);
+    i->configIni = iniFile_newFromFile(iniPath);
+    AFREE(iniPath);
+
+    if (i->configIni == NULL) {
+        derror("bad config: %s",
+               "virtual device has corrupted config.ini");
+        return -1;
+    }
+    return 0;
+}
+
+/* The AVD's config.ini contains a list of search paths (all beginning
+ * with SEARCH_PREFIX) which are directory locations searched for
+ * AVD platform files.
  */
 static void
-_getSDCardPath( AvdInfo*  i, AvdInfoParams*  params )
+_avdInfo_getSearchPaths( AvdInfo*  i )
 {
-    const char*  path;
-
-    if (params->forcePaths[AVD_IMAGE_SDCARD] != NULL)
+    if (i->configIni == NULL)
         return;
 
-    path = iniFile_getString(i->configIni, SDCARD_PATH, NULL);
+    i->numSearchPaths = _getSearchPaths( i->configIni,
+                                         i->sdkRootPath,
+                                         MAX_SEARCH_PATHS,
+                                         i->searchPaths );
+    if (i->numSearchPaths == 0) {
+        derror("no search paths found in this AVD's configuration.\n"
+               "Weird, the AVD's config.ini file is malformed. Try re-creating it.\n");
+        exit(2);
+    }
+    else
+        DD("found a total of %d search paths for this AVD", i->numSearchPaths);
+}
+
+/* Search a file in the SDK search directories. Return NULL if not found,
+ * or a strdup() otherwise.
+ */
+static char*
+_avdInfo_getSdkFilePath(AvdInfo*  i, const char*  fileName)
+{
+    char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
+
+    do {
+        /* try the search paths */
+        int  nn;
+
+        for (nn = 0; nn < i->numSearchPaths; nn++) {
+            const char* searchDir = i->searchPaths[nn];
+
+            p = bufprint(temp, end, "%s/%s", searchDir, fileName);
+            if (p < end && path_exists(temp)) {
+                DD("found %s in search dir: %s", fileName, searchDir);
+                goto FOUND;
+            }
+            DD("    no %s in search dir: %s", fileName, searchDir);
+        }
+
+        return NULL;
+
+    } while (0);
+
+FOUND:
+    return ASTRDUP(temp);
+}
+
+/* Search for a file in the content directory, and if not found, in the
+ * SDK search directory. Returns NULL if not found.
+ */
+static char*
+_avdInfo_getContentOrSdkFilePath(AvdInfo*  i, const char*  fileName)
+{
+    char*  path;
+
+    path = _avdInfo_getContentFilePath(i, fileName);
+    if (path)
+        return path;
+
+    path = _avdInfo_getSdkFilePath(i, fileName);
+    if (path)
+        return path;
+
+    return NULL;
+}
+
+#if 0
+static int
+_avdInfo_findContentOrSdkImage(AvdInfo* i, AvdImageType id)
+{
+    const char* fileName = _imageFileNames[id];
+    char*       path     = _avdInfo_getContentOrSdkFilePath(i, fileName);
+
+    i->imagePath[id]  = path;
+    i->imageState[id] = IMAGE_STATE_READONLY;
+
     if (path == NULL)
-        return;
+        return -1;
+    else
+        return 0;
+}
+#endif
 
-    params->forcePaths[AVD_IMAGE_SDCARD] = path;
+/* Returns path to the core hardware .ini file. This contains the
+ * hardware configuration that is read by the core. The content of this
+ * file is auto-generated before launching a core, but we need to know
+ * its path before that.
+ */
+static int
+_avdInfo_getCoreHwIniPath( AvdInfo* i, const char* basePath )
+{
+    i->coreHardwareIniPath = _getFullFilePath(basePath, CORE_HARDWARE_INI);
+    if (i->coreHardwareIniPath == NULL) {
+        DD("Path too long for %s: %s", CORE_HARDWARE_INI, basePath);
+        return -1;
+    }
+    D("using core hw config path: %s", i->coreHardwareIniPath);
+    return 0;
 }
 
 AvdInfo*
@@ -1104,26 +796,22 @@
     ANEW0(i);
     i->deviceName = ASTRDUP(name);
 
-    if ( _getSdkRoot(i)     < 0 ||
-         _getRootIni(i)     < 0 ||
-         _getContentPath(i) < 0 ||
-         _getConfigIni(i)   < 0 )
+    if ( _avdInfo_getSdkRoot(i) < 0     ||
+         _avdInfo_getRootIni(i) < 0     ||
+         _avdInfo_getContentPath(i) < 0 ||
+         _avdInfo_getConfigIni(i)   < 0 ||
+         _avdInfo_getCoreHwIniPath(i, i->contentPath) < 0 )
         goto FAIL;
 
     /* look for image search paths. handle post 1.1/pre cupcake
      * obsolete SDKs.
      */
-    _getSearchPaths(i);
-    _getSDCardPath(i, params);
+    _avdInfo_getSearchPaths(i);
 
     /* don't need this anymore */
     iniFile_free(i->rootIni);
     i->rootIni = NULL;
 
-    if ( _getImagePaths(i, params) < 0 ||
-         _getSkin      (i, params) < 0 )
-        goto FAIL;
-
     return i;
 
 FAIL:
@@ -1155,246 +843,32 @@
  *****      the content directory, no SDK images search path.
  *****/
 
-/* used to fake a config.ini located in the content directory */
-static int
-_getBuildConfigIni( AvdInfo*  i )
-{
-    /* a blank file is ok at the moment */
-    i->configIni = iniFile_newFromMemory( "", 0 );
-    return 0;
-}
-
-static int
-_getBuildImagePaths( AvdInfo*  i, AvdInfoParams*  params )
-{
-    int   wipeData    = (params->flags & AVDINFO_WIPE_DATA) != 0;
-    int   noCache     = (params->flags & AVDINFO_NO_CACHE) != 0;
-    int   noSdCard    = (params->flags & AVDINFO_NO_SDCARD) != 0;
-#if CONFIG_ANDROID_SNAPSHOTS
-    int   noSnapshots = (params->flags & AVDINFO_NO_SNAPSHOTS) != 0;
-#endif
-
-    char         temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
-    char*        srcData;
-    ImageLoader  l[1];
-
-    imageLoader_init(l, i, params);
-
-    /** load the kernel image
-     **/
-
-    /* if it is not in the out directory, get it from prebuilt
-     */
-    imageLoader_set ( l, AVD_IMAGE_KERNEL );
-
-    if ( !imageLoader_load( l, IMAGE_OPTIONAL |
-                               IMAGE_DONT_LOCK ) )
-    {
-#ifdef TARGET_ARM
-#define  PREBUILT_KERNEL_PATH   "prebuilt/android-arm/kernel/kernel-qemu"
-#endif
-#ifdef TARGET_I386
-#define  PREBUILT_KERNEL_PATH   "prebuilt/android-x86/kernel/kernel-qemu"
-#endif
-        p = bufprint(temp, end, "%s/%s", i->androidBuildRoot,
-                        PREBUILT_KERNEL_PATH);
-        if (p >= end || !path_exists(temp)) {
-            derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
-            exit(1);
-        }
-        imageLoader_setPath(l, temp);
-    }
-
-    /** load the data partition. note that we use userdata-qemu.img
-     ** since we don't want to modify userdata.img at all
-     **/
-    imageLoader_set ( l, AVD_IMAGE_USERDATA );
-    imageLoader_load( l, IMAGE_OPTIONAL | IMAGE_DONT_LOCK );
-
-    /* get the path of the source file, and check that it actually exists
-     * if the user didn't provide an explicit data file
-     */
-    srcData = imageLoader_extractPath(l);
-    if (srcData == NULL && params->forcePaths[AVD_IMAGE_USERDATA] == NULL) {
-        derror("There is no %s image in your build directory. Please make a full build",
-                l->imageText, l->imageFile);
-        exit(2);
-    }
-
-    /* get the path of the target file */
-    l->imageFile = "userdata-qemu.img";
-    imageLoader_load( l, IMAGE_OPTIONAL |
-                         IMAGE_EMPTY_IF_MISSING |
-                         IMAGE_IGNORE_IF_LOCKED );
-
-    /* force a data wipe if we just created the image */
-    if (l->pState[0] == IMAGE_STATE_LOCKED_EMPTY)
-        wipeData = 1;
-
-    /* if the image was already locked, create a temp file
-     * then force a data wipe.
-     */
-    if (l->pPath[0] == NULL) {
-        TempFile*  temp = tempfile_create();
-        imageLoader_setPath(l, tempfile_path(temp));
-        dwarning( "Another emulator is running. user data changes will *NOT* be saved");
-        wipeData = 1;
-    }
-
-    /* in the case of a data wipe, copy userdata.img into
-     * the destination */
-    if (wipeData) {
-        if (srcData == NULL || !path_exists(srcData)) {
-            derror("There is no %s image in your build directory. Please make a full build",
-                   l->imageText, _imageFileNames[l->id]);
-            exit(2);
-        }
-        if (path_copy_file( l->pPath[0], srcData ) < 0) {
-            derror("could not initialize %s image from %s: %s",
-                   l->imageText, temp, strerror(errno));
-            exit(2);
-        }
-    }
-
-    AFREE(srcData);
-
-    /** load the ramdisk image
-     **/
-    imageLoader_set ( l, AVD_IMAGE_RAMDISK );
-    imageLoader_load( l, IMAGE_REQUIRED |
-                         IMAGE_DONT_LOCK );
-
-    /** load the system image. read-only. the caller must
-     ** take care of checking the state
-     **/
-    imageLoader_set ( l, AVD_IMAGE_INITSYSTEM );
-    imageLoader_load( l, IMAGE_REQUIRED | IMAGE_DONT_LOCK );
-
-    /* force the system image to read-only status */
-    l->pState[0] = IMAGE_STATE_READONLY;
-
-    /** cache partition handling
-     **/
-    if (!noCache) {
-        imageLoader_set (l, AVD_IMAGE_CACHE);
-
-        /* if the user provided one cache image, lock & use it */
-        if ( params->forcePaths[l->id] != NULL ) {
-            imageLoader_load(l, IMAGE_REQUIRED | 
-                                IMAGE_IGNORE_IF_LOCKED);
-        }
-    }
-
-    /** SD Card image
-     **/
-    if (!noSdCard) {
-        imageLoader_set (l, AVD_IMAGE_SDCARD);
-        imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED);
-    }
-
-#if CONFIG_ANDROID_SNAPSHOTS
-    /** State snapshots image
-     **/
-    if (!noSnapshots) {
-        imageLoader_set (l, AVD_IMAGE_SNAPSHOTS);
-        imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED);
-    }
-#endif
-
-    return 0;
-}
-
-static int
-_getBuildSkin( AvdInfo*  i, AvdInfoParams*  params )
-{
-    /* the (current) default skin name for our build system */
-    const char*  skinName = params->skinName;
-    const char*  skinDir  = params->skinRootPath;
-    char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-    char*        q;
-
-    if (!skinName) {
-        /* the (current) default skin name for the build system */
-        skinName = SKIN_DEFAULT;
-        D("selecting default skin name '%s'", skinName);
-    }
-
-    if (!skinDir) {
-
-#define  PREBUILT_SKINS_DIR  "development/tools/emulator/skins"
-#define  PRODUCT_SKIN_DIR "skin"
-
-        do {
-            /* look for the product skin in $ANDROID_PRODUCT_OUT/skin if no skin name is defined */
-            if (!params->skinName) {
-                /* look for <product_out>/skin first */
-                p = bufprint( temp, end, "%s/skin",
-                              i->androidOut );
-                if (path_exists(temp)) {
-                    p = bufprint( temp, end, "%s",
-                                  i->androidOut );
-                    skinName = PRODUCT_SKIN_DIR;
-                    D("selecting default product skin at '%s/%s'", temp, skinName);
-                    break;
-                }
-            }
-
-            /* next try in <sysdir>/../skins */
-            p = bufprint( temp, end, "%s/../skins",
-                          i->androidBuildRoot );
-            if (path_exists(temp))
-                break;
-
-            /* the (current) default skin directory */
-            p = bufprint( temp, end, "%s/%s",
-                        i->androidBuildRoot, PREBUILT_SKINS_DIR );
-        } while (0);
-
-    } else {
-        p = bufprint( temp, end, "%s", skinDir );
-    }
-
-    i->skinName = ASTRDUP(skinName);
-
-    q  = bufprint(p, end, "/%s/layout", skinName);
-    if (q >= end || !path_exists(temp)) {
-        DD("skin content directory does not exist: %s", temp);
-        if (skinDir)
-            dwarning("could not find valid skin '%s' in %s:\n",
-                     skinName, temp);
-        return -1;
-    }
-    *p = 0;
-    DD("found skin path: %s", temp);
-    i->skinDirPath = ASTRDUP(temp);
-
-    return 0;
-}
-
 /* Read a hardware.ini if it is located in the skin directory */
 static int
-_getBuildHardwareIni( AvdInfo*  i )
+_avdInfo_getBuildSkinHardwareIni( AvdInfo*  i )
 {
+    char* skinName;
+    char* skinDirPath;
     char  temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
 
-    if (i->skinDirPath == NULL || i->skinName == NULL)
+    avdInfo_getSkinInfo(i, &skinName, &skinDirPath);
+    if (skinDirPath == NULL)
         return 0;
 
-    p = bufprint(temp, end, "%s/%s/hardware.ini", i->skinDirPath, i->skinName);
+    p = bufprint(temp, end, "%s/%s/hardware.ini", skinDirPath, skinName);
     if (p >= end || !path_exists(temp)) {
-        DD("no skin-specific hardware.ini in %s", i->skinDirPath);
+        DD("no skin-specific hardware.ini in %s", skinDirPath);
         return 0;
     }
 
     D("found skin-specific hardware.ini: %s", temp);
-    i->hardwareIni = iniFile_newFromFile(temp);
-    if (i->hardwareIni == NULL)
+    i->skinHardwareIni = iniFile_newFromFile(temp);
+    if (i->skinHardwareIni == NULL)
         return -1;
 
     return 0;
 }
 
-
 AvdInfo*
 avdInfo_newForAndroidBuild( const char*     androidBuildRoot,
                             const char*     androidOut,
@@ -1408,17 +882,19 @@
     i->androidBuildRoot = ASTRDUP(androidBuildRoot);
     i->androidOut       = ASTRDUP(androidOut);
     i->contentPath      = ASTRDUP(androidOut);
+    i->targetArch       = ASTRDUP(_getBuildTargetArch(i->androidOut));
 
     /* TODO: find a way to provide better information from the build files */
     i->deviceName = ASTRDUP("<build>");
 
-    if (_getBuildConfigIni(i)          < 0 ||
-        _getBuildImagePaths(i, params) < 0 )
+    /* There is no config.ini in the build */
+    i->configIni = NULL;
+
+    if (_avdInfo_getCoreHwIniPath(i, i->androidOut) < 0 )
         goto FAIL;
 
-    /* we don't need to fail if there is no valid skin */
-    _getBuildSkin(i, params);
-    _getBuildHardwareIni(i);
+    /* Read the build skin's hardware.ini, if any */
+    _avdInfo_getBuildSkinHardwareIni(i);
 
     return i;
 
@@ -1466,16 +942,113 @@
     return (i->imageState[imageType] == IMAGE_STATE_READONLY);
 }
 
-const char*
-avdInfo_getSkinName( AvdInfo*  i )
+char*
+avdInfo_getKernelPath( AvdInfo*  i )
 {
-    return i->skinName;
+    const char* imageName = _imageFileNames[ AVD_IMAGE_KERNEL ];
+
+    char*  kernelPath = _avdInfo_getContentOrSdkFilePath(i, imageName);
+
+    if (kernelPath == NULL && i->inAndroidBuild) {
+        /* When in the Android build, look into the prebuilt directory
+         * for our target architecture.
+         */
+        char temp[PATH_MAX], *p = temp, *end = p + sizeof(temp);
+
+        p = bufprint(temp, end, "%s/prebuilt/android-%s/kernel/kernel-qemu",
+                     i->androidBuildRoot, i->targetArch);
+        if (p >= end || !path_exists(temp)) {
+            derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
+            exit(1);
+        }
+        kernelPath = ASTRDUP(temp);
+    }
+    return kernelPath;
 }
 
-const char*
-avdInfo_getSkinDir ( AvdInfo*  i )
+
+char*
+avdInfo_getRamdiskPath( AvdInfo* i )
 {
-    return i->skinDirPath;
+    const char* imageName = _imageFileNames[ AVD_IMAGE_RAMDISK ];
+    return _avdInfo_getContentOrSdkFilePath(i, imageName);
+}
+
+char*  avdInfo_getCachePath( AvdInfo*  i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
+    return _avdInfo_getContentFilePath(i, imageName);
+}
+
+char*  avdInfo_getDefaultCachePath( AvdInfo*  i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_CACHE ];
+    return _getFullFilePath(i->contentPath, imageName);
+}
+
+char*  avdInfo_getSdCardPath( AvdInfo* i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_SDCARD ];
+    char*       path;
+
+    /* Special case, the config.ini can have a SDCARD_PATH entry
+     * that gives the full path to the SD Card.
+     */
+    if (i->configIni != NULL) {
+        path = iniFile_getString(i->configIni, SDCARD_PATH, NULL);
+        if (path != NULL) {
+            if (path_exists(path))
+                return path;
+
+            dwarning("Ignoring invalid SDCard path: %s", path);
+            AFREE(path);
+        }
+    }
+
+    /* Otherwise, simply look into the content directory */
+    return _avdInfo_getContentFilePath(i, imageName);
+}
+
+char*
+avdInfo_getSnapStoragePath( AvdInfo* i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_SNAPSHOTS ];
+    return _avdInfo_getContentFilePath(i, imageName);
+}
+
+char*
+avdInfo_getSystemImagePath( AvdInfo*  i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_USERSYSTEM ];
+    return _avdInfo_getContentFilePath(i, imageName);
+}
+
+char*
+avdInfo_getSystemInitImagePath( AvdInfo*  i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_INITSYSTEM ];
+    return _avdInfo_getContentOrSdkFilePath(i, imageName);
+}
+
+char*
+avdInfo_getDataImagePath( AvdInfo*  i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
+    return _avdInfo_getContentFilePath(i, imageName);
+}
+
+char*
+avdInfo_getDefaultDataImagePath( AvdInfo*  i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_USERDATA ];
+    return _getFullFilePath(i->contentPath, imageName);
+}
+
+char*
+avdInfo_getDataInitImagePath( AvdInfo* i )
+{
+    const char* imageName = _imageFileNames[ AVD_IMAGE_INITDATA ];
+    return _avdInfo_getContentOrSdkFilePath(i, imageName);
 }
 
 int
@@ -1492,8 +1065,8 @@
     if (ini != i->configIni)
         iniFile_free(ini);
 
-    if (ret == 0 && i->hardwareIni != NULL) {
-        ret = androidHwConfig_read(hw, i->hardwareIni);
+    if (ret == 0 && i->skinHardwareIni != NULL) {
+        ret = androidHwConfig_read(hw, i->skinHardwareIni);
     }
 
     /* special product-specific hardware configuration */
@@ -1539,3 +1112,113 @@
     }
     return ASTRDUP(tmp);
 }
+
+const char*
+avdInfo_getCoreHwIniPath( AvdInfo* i )
+{
+    return i->coreHardwareIniPath;
+}
+
+
+void
+avdInfo_getSkinInfo( AvdInfo*  i, char** pSkinName, char** pSkinDir )
+{
+    char*  skinName = NULL;
+    char*  skinPath;
+    char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+    *pSkinName = NULL;
+    *pSkinDir  = NULL;
+
+    /* First, see if the config.ini contains a SKIN_PATH entry that
+     * names the full directory path for the skin.
+     */
+    if ( i->configIni != NULL ) {
+        skinPath = iniFile_getString( i->configIni, SKIN_PATH, NULL );
+        if (skinPath != NULL) {
+            /* If this skin name is magic or a direct directory path
+            * we have our result right here.
+            */
+            if (_getSkinPathFromName(skinPath, i->sdkRootPath,
+                                     pSkinName, pSkinDir )) {
+                AFREE(skinPath);
+                return;
+            }
+        }
+
+        /* The SKIN_PATH entry was not valid, so look at SKIN_NAME */
+        D("Warning: config.ini contains invalid %s entry: %s", SKIN_PATH, skinPath);
+        AFREE(skinPath);
+
+        skinName = iniFile_getString( i->configIni, SKIN_NAME, NULL );
+    }
+
+    if (skinName == NULL) {
+        /* If there is no skin listed in the config.ini, try to see if
+         * there is one single 'skin' directory in the content directory.
+         */
+        p = bufprint(temp, end, "%s/skin", i->contentPath);
+        if (p < end && _checkSkinPath(temp)) {
+            D("using skin content from %s", temp);
+            AFREE(i->skinName);
+            *pSkinName = ASTRDUP("skin");
+            *pSkinDir  = ASTRDUP(i->contentPath);
+            return;
+        }
+
+        /* otherwise, use the default name */
+        skinName = ASTRDUP(SKIN_DEFAULT);
+    }
+
+    /* now try to find the skin directory for that name -
+     */
+    do {
+        /* first try the content directory, i.e. $CONTENT/skins/<name> */
+        skinPath = _checkSkinSkinsDir(i->contentPath, skinName);
+        if (skinPath != NULL)
+            break;
+
+#define  PREBUILT_SKINS_ROOT "development/tools/emulator"
+
+        /* if we are in the Android build, try the prebuilt directory */
+        if (i->inAndroidBuild) {
+            p = bufprint( temp, end, "%s/%s",
+                        i->androidBuildRoot, PREBUILT_SKINS_ROOT );
+            if (p < end) {
+                skinPath = _checkSkinSkinsDir(temp, skinName);
+                if (skinPath != NULL)
+                    break;
+            }
+        }
+
+        /* look in the search paths. For each <dir> in the list,
+         * look into <dir>/../skins/<name>/ */
+        {
+            int  nn;
+            for (nn = 0; nn < i->numSearchPaths; nn++) {
+                char*  parentDir = path_parent(i->searchPaths[nn], 1);
+                if (parentDir == NULL)
+                    continue;
+                skinPath = _checkSkinSkinsDir(parentDir, skinName);
+                AFREE(parentDir);
+                if (skinPath != NULL)
+                  break;
+            }
+            if (nn < i->numSearchPaths)
+                break;
+        }
+
+        /* We didn't find anything ! */
+        return;
+
+    } while (0);
+
+    if (path_split(skinPath, pSkinDir, pSkinName) < 0) {
+        derror("weird skin path: %s", skinPath);
+        AFREE(skinPath);
+        return;
+    }
+    DD("found skin '%s' in directory: %s", *pSkinName, *pSkinDir);
+    AFREE(skinPath);
+    return;
+}
diff --git a/android/avd/info.h b/android/avd/info.h
index 2b2899f..aa3ddcd 100644
--- a/android/avd/info.h
+++ b/android/avd/info.h
@@ -47,11 +47,6 @@
  */
 
 
-#if CONFIG_ANDROID_SNAPSHOTS
-#define _AVD_IMG_SNAPSHOT _AVD_IMG(SNAPSHOTS,"snapshots.img","snapshots")
-#else
-#define _AVD_IMG_SNAPSHOT
-#endif
 /* a macro used to define the list of disk images managed by the
  * implementation. This macro will be expanded several times with
  * varying definitions of _AVD_IMG
@@ -65,7 +60,7 @@
     _AVD_IMG(USERDATA,"userdata-qemu.img", "user data") \
     _AVD_IMG(CACHE,"cache.img","cache") \
     _AVD_IMG(SDCARD,"sdcard.img","SD Card") \
-    _AVD_IMG_SNAPSHOT \
+    _AVD_IMG(SNAPSHOTS,"snapshots.img","snapshots") \
 
 /* define the enumared values corresponding to each AVD image type
  * examples are: AVD_IMAGE_KERNEL, AVD_IMAGE_SYSTEM, etc..
@@ -94,10 +89,8 @@
     AVDINFO_NO_SDCARD = (1 << 3),
     /* use to wipe the system image with new initial values */
     AVDINFO_WIPE_SYSTEM = (1 << 4),
-#if CONFIG_ANDROID_SNAPSHOTS
     /* use to ignore ignore state snapshot image (default or provided) */
     AVDINFO_NO_SNAPSHOTS = (1 << 5),
-#endif
 } AvdFlags;
 
 typedef struct {
@@ -137,6 +130,48 @@
  */
 const char*  avdInfo_getName( AvdInfo*  i );
 
+/* Returns the path to various images corresponding to a given AVD.
+ * NULL if the image cannot be found. Returned strings must be freed
+ * by the caller.
+ */
+char*  avdInfo_getKernelPath( AvdInfo*  i );
+char*  avdInfo_getRamdiskPath( AvdInfo*  i );
+char*  avdInfo_getSdCardPath( AvdInfo* i );
+char*  avdInfo_getSnapStoragePath( AvdInfo* i );
+
+/* This function returns NULL if the cache image file cannot be found.
+ * Use avdInfo_getDefaultCachePath() to retrieve the default path
+ * if you intend to create the partition file there.
+ */
+char*  avdInfo_getCachePath( AvdInfo*  i );
+char*  avdInfo_getDefaultCachePath( AvdInfo*  i );
+
+
+/* avdInfo_getSystemImagePath() will return NULL, except if the AVD content
+ * directory contains a file named "system-qemu.img".
+ */
+char*  avdInfo_getSystemImagePath( AvdInfo* i );
+
+/* avdInfo_getSystemInitImagePath() retrieves the path to the read-only
+ * initialization image for this disk image.
+ */
+char*  avdInfo_getSystemInitImagePath( AvdInfo*  i );
+
+char*  avdInfo_getDataImagePath( AvdInfo*  i );
+char*  avdInfo_getDefaultDataImagePath( AvdInfo*  i );
+char*  avdInfo_getDataInitImagePath( AvdInfo* i );
+
+/* Returns the path to a given AVD image file. This will return NULL if
+ * the file cannot be found / does not exist.
+ */
+const char*  avdInfo_getImagePath( AvdInfo*  i, AvdImageType  imageType );
+
+/* Returns the default path of a given AVD image file. This only makes sense
+ * if avdInfo_getImagePath() returned NULL.
+ */
+const char*  avdInfo_getImageDefaultPath( AvdInfo*  i, AvdImageType  imageType );
+
+
 /* Try to find the path of a given image file, returns NULL
  * if the corresponding file could not be found. the string
  * belongs to the AvdInfo object.
@@ -161,19 +196,18 @@
 /* Manually set the path of a given image file. */
 void         avdInfo_setImageFile( AvdInfo*  i, AvdImageType  imageType, const char*  imagePath );
 
-/* Returns the path of the skin directory */
-/* the string belongs to the AvdInfo object */
-const char*  avdInfo_getSkinPath( AvdInfo*  i );
-
-/* Returns the name of the virtual device's skin */
-const char*  avdInfo_getSkinName( AvdInfo*  i );
-
-/* Returns the root skin directory for this device */
-const char*  avdInfo_getSkinDir ( AvdInfo*  i );
-
 /* Returns the content path of the virtual device */
 const char*  avdInfo_getContentPath( AvdInfo*  i );
 
+/* Retrieve the AVD's specific skin information.
+ * On exit:
+ *   '*pSkinName' points to the skin's name.
+ *   '*pSkinDir' points to the skin's directory.
+ *
+ * Note that the skin's content will be under <skinDir>/<skinName>.
+ */
+void         avdInfo_getSkinInfo( AvdInfo*  i, char** pSkinName, char** pSkinDir );
+
 /* Returns TRUE iff in the Android build system */
 int          avdInfo_inAndroidBuild( AvdInfo*  i );
 
@@ -183,6 +217,12 @@
 /* Returns a *copy* of the path used to store trace 'foo'. result must be freed by caller */
 char*        avdInfo_getTracePath( AvdInfo*  i, const char*  traceName );
 
+/* Returns the path of the hardware.ini where we will write the AVD's
+ * complete hardware configuration before launching the corresponding
+ * core.
+ */
+const char*  avdInfo_getCoreHwIniPath( AvdInfo* i );
+
 /* */
 
 #endif /* ANDROID_AVD_INFO_H */
diff --git a/android/build/clear_vars.make b/android/build/clear_vars.make
index f4ca9b7..5cdce07 100644
--- a/android/build/clear_vars.make
+++ b/android/build/clear_vars.make
@@ -18,6 +18,7 @@
 LOCAL_NO_DEFAULT_COMPILER_FLAGS:=
 LOCAL_CC :=
 LOCAL_CXX :=
+LOCAL_AR :=
 LOCAL_CFLAGS :=
 LOCAL_LDFLAGS :=
 LOCAL_LDLIBS :=
diff --git a/android/build/definitions.make b/android/build/definitions.make
index ab9a34d..e31131b 100644
--- a/android/build/definitions.make
+++ b/android/build/definitions.make
@@ -55,7 +55,7 @@
 OBJ:=$$(LOCAL_OBJS_DIR)/$$(SRC:%.c=%.o)
 LOCAL_OBJECTS += $$(OBJ)
 DEPENDENCY_DIRS += $$(dir $$(OBJ))
-$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(OBJS_DIR)
+$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(LOCAL_OBJS_DIR)
 $$(OBJ): PRIVATE_CC     := $$(LOCAL_CC)
 $$(OBJ): PRIVATE_OBJ    := $$(OBJ)
 $$(OBJ): PRIVATE_MODULE := $$(LOCAL_MODULE)
@@ -75,7 +75,7 @@
 OBJ:=$$(LOCAL_OBJS_DIR)/$$(SRC:%$(LOCAL_CPP_EXTENSION)=%.o)
 LOCAL_OBJECTS += $$(OBJ)
 DEPENDENCY_DIRS += $$(dir $$(OBJ))
-$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(OBJS_DIR)
+$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(LOCAL_OBJS_DIR)
 $$(OBJ): PRIVATE_CXX    := $$(LOCAL_CC)
 $$(OBJ): PRIVATE_OBJ    := $$(OBJ)
 $$(OBJ): PRIVATE_MODULE := $$(LOCAL_MODULE)
@@ -95,7 +95,7 @@
 OBJ:=$$(LOCAL_OBJS_DIR)/$$(notdir $$(SRC:%.m=%.o))
 LOCAL_OBJECTS += $$(OBJ)
 DEPENDENCY_DIRS += $$(dir $$(OBJ))
-$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(OBJS_DIR)
+$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(LOCAL_OBJS_DIR)
 $$(OBJ): PRIVATE_CC     := $$(LOCAL_CC)
 $$(OBJ): PRIVATE_OBJ    := $$(OBJ)
 $$(OBJ): PRIVATE_MODULE := $$(LOCAL_MODULE)
@@ -115,7 +115,7 @@
 OBJ:=$$(LOCAL_OBJS_DIR)/$$(notdir $$(SRC:%.c=%.o))
 LOCAL_OBJECTS += $$(OBJ)
 DEPENDENCY_DIRS += $$(dir $$(OBJ))
-$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(OBJS_DIR)
+$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(LOCAL_OBJS_DIR)
 $$(OBJ): PRIVATE_CC     := $$(LOCAL_CC)
 $$(OBJ): PRIVATE_OBJ    := $$(OBJ)
 $$(OBJ): PRIVATE_MODULE := $$(LOCAL_MODULE)
@@ -148,7 +148,7 @@
 define copy-prebuilt-lib
 _SRC := $(1)
 _SRC1 := $$(notdir $$(_SRC))
-_DST := $$(OBJS_DIR)/$$(_SRC1)
+_DST := $$(LIBS_DIR)/$$(_SRC1)
 LIBRARIES += $$(_DST)
 $$(_DST): PRIVATE_DST := $$(_DST)
 $$(_DST): PRIVATE_SRC := $$(_SRC)
diff --git a/android/build/host_static_library.make b/android/build/host_static_library.make
index 3de5a99..38ff625 100644
--- a/android/build/host_static_library.make
+++ b/android/build/host_static_library.make
@@ -22,7 +22,10 @@
 LOCAL_CC ?= $(CC)
 include $(BUILD_SYSTEM)/binary.make
 
-LOCAL_AR ?= $(AR)
+LOCAL_AR := $(strip $(LOCAL_AR))
+ifndef LOCAL_AR
+    LOCAL_AR := $(AR)
+endif
 ARFLAGS := crs
 
 $(LOCAL_BUILT_MODULE): PRIVATE_AR := $(LOCAL_AR)
diff --git a/android/cmdline-options.h b/android/cmdline-options.h
index 273d151..b7d7bfa 100644
--- a/android/cmdline-options.h
+++ b/android/cmdline-options.h
@@ -75,7 +75,6 @@
 CFG_FLAG ( no_cache, "disable the cache partition" )
 CFG_FLAG ( nocache,  "same as -no-cache" )
 OPT_PARAM( sdcard, "<file>", "SD card image (default <system>/sdcard.img")
-#if CONFIG_ANDROID_SNAPSHOTS
 OPT_PARAM( snapstorage,    "<file>", "file that contains all state snapshots (default <datadir>/snapshots.img)")
 OPT_FLAG ( no_snapstorage, "do not mount a snapshot storage file (this disables all snapshot functionality)" )
 OPT_PARAM( snapshot,       "<name>", "name of snapshot within storage file for auto-start and auto-save (default 'default-boot')" )
@@ -84,8 +83,7 @@
 OPT_FLAG ( no_snapshot_load, "do not auto-start from snapshot: perform a full boot" )
 OPT_FLAG ( snapshot_list,  "show a list of available snapshots" )
 OPT_FLAG ( no_snapshot_update_time, "do not do try to correct snapshot time on restore" )
-#endif
-OPT_FLAG ( wipe_data, "reset the use data image (copy it from initdata)" )
+OPT_FLAG ( wipe_data, "reset the user data image (copy it from initdata)" )
 CFG_PARAM( avd, "<name>", "use a specific android virtual device" )
 CFG_PARAM( skindir, "<dir>", "search skins in <dir> (default <system>/skins)" )
 CFG_PARAM( skin, "<name>", "select a given skin" )
@@ -133,7 +131,6 @@
 OPT_PARAM( gps, "<device>", "redirect NMEA GPS to character device" )
 OPT_PARAM( keyset, "<name>", "specify keyset file name" )
 OPT_PARAM( shell_serial, "<device>", "specific character device for root shell" )
-OPT_FLAG ( old_system, "support old (pre 1.4) system images" )
 OPT_PARAM( tcpdump, "<file>", "capture network packets to file" )
 
 OPT_PARAM( bootchart, "<timeout>", "enable bootcharting")
diff --git a/android/config/config.h b/android/config/config.h
index fdfbe31..35cc9da 100644
--- a/android/config/config.h
+++ b/android/config/config.h
@@ -1,4 +1,9 @@
-/* Automatically generated by configure - do not modify */
+/* This file is included by target-specific files under
+ * android/config/target-$ARCH/config.h, but contains all config
+ * definitions that are independent of the target CPU.
+ *
+ * Do not include directly.
+ */
 #include "config-host.h"
 
 #define TARGET_PHYS_ADDR_BITS  32
@@ -10,14 +15,4 @@
 #ifndef _WIN32
 #define CONFIG_NAND_LIMITS 1
 #endif
-#define CONFIG_ANDROID_SNAPSHOTS 1
-
-#ifdef ARCH_FLAGS_x86
-#define TARGET_ARCH "x86"
-#define TARGET_I386 1
-#else
-#define TARGET_ARCH "arm"
-#define TARGET_ARM 1
-#define CONFIG_SOFTFLOAT 1
-#endif
-
+#define CONFIG_MEMCHECK 1
diff --git a/android/config/linux-x86/config-host.h b/android/config/linux-x86/config-host.h
index 2dba514..903e98b 100644
--- a/android/config/linux-x86/config-host.h
+++ b/android/config/linux-x86/config-host.h
@@ -12,6 +12,7 @@
 #define QEMU_VERSION    "0.10.50"
 #define QEMU_PKGVERSION "Android"
 #define HOST_I386    1
+#define CONFIG_KVM   1
 #define CONFIG_IOVEC 1
 #define CONFIG_LINUX   1
 #define CONFIG_ANDROID       1
diff --git a/android/config/target-arm/config.h b/android/config/target-arm/config.h
new file mode 100644
index 0000000..d6da04f
--- /dev/null
+++ b/android/config/target-arm/config.h
@@ -0,0 +1,5 @@
+/* ARM-specific configuration */
+#include "android/config/config.h"
+
+#define TARGET_ARM 1
+#define CONFIG_SOFTFLOAT 1
diff --git a/android/config/target-x86/config.h b/android/config/target-x86/config.h
new file mode 100644
index 0000000..ea31c39
--- /dev/null
+++ b/android/config/target-x86/config.h
@@ -0,0 +1,3 @@
+/* x86-specific configuration */
+#include "android/config/config.h"
+#define TARGET_I386 1
diff --git a/android/console.c b/android/console.c
index d883002..de32ddb 100644
--- a/android/console.c
+++ b/android/console.c
@@ -2049,8 +2049,6 @@
     { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
-#if CONFIG_ANDROID_SNAPSHOTS
-
 
 /********************************************************************************************/
 /********************************************************************************************/
@@ -2150,8 +2148,6 @@
 };
 
 
-#endif
-
 
 /********************************************************************************************/
 /********************************************************************************************/
@@ -2215,11 +2211,9 @@
     "'avd name' will return the name of this virtual device\r\n",
     NULL, do_avd_name, NULL },
 
-#if CONFIG_ANDROID_SNAPSHOTS
     { "snapshot", "state snapshot commands",
     "allows you to save and restore the virtual device state in snapshots\r\n",
     NULL, NULL, snapshot_commands },
-#endif
 
     { NULL, NULL, NULL, NULL, NULL, NULL }
 };
diff --git a/android/help.c b/android/help.c
index 7df6704..cd5a3a6 100644
--- a/android/help.c
+++ b/android/help.c
@@ -166,9 +166,7 @@
     "    system-qemu.img    an *optional* persistent system image\n"
     "    cache.img          an *optional* cache partition image\n"
     "    sdcard.img         an *optional* SD Card partition image\n\n"
-#if CONFIG_ANDROID_SNAPSHOTS
     "    snapshots.img      an *optional* state snapshots image\n\n"
-#endif
 
     "  If you use a virtual device, its content directory should store\n"
     "  all writable images, and read-only ones will be found from the\n"
@@ -184,11 +182,7 @@
     "  can still run the emulator by explicitely providing the paths to\n"
     "  *all* required disk images through a combination of the following\n"
     "  options: -sysdir, -datadir, -kernel, -ramdisk, -system, -data, -cache\n"
-#if CONFIG_ANDROID_SNAPSHOTS
     "  -sdcard and -snapstorage.\n\n"
-#else
-    "  and -sdcard.\n\n"
-#endif
 
     "  The actual logic being that the emulator should be able to find all\n"
     "  images from the options you give it.\n\n"
@@ -205,10 +199,8 @@
     "      -no-cache        do not use a cache partition, even if one is\n"
     "                       available.\n\n"
 
-#if CONFIG_ANDROID_SNAPSHOTS
     "      -no-snapstorage  do not use a state snapshot image, even if one is\n"
     "                       available.\n\n"
-#endif
     ,
     datadir );
 }
@@ -619,7 +611,6 @@
     );
 }
 
-#if CONFIG_ANDROID_SNAPSHOTS
 static void
 help_snapstorage(stralloc_t*  out)
 {
@@ -733,8 +724,6 @@
     );
 }
 
-#endif
-
 static void
 help_skindir(stralloc_t*  out)
 {
@@ -1344,20 +1333,6 @@
     );
 }
 
-static void
-help_old_system(stralloc_t*  out)
-{
-    PRINTF(
-    "  use '-old-system' if you want to use a recent emulator binary to run\n"
-    "  an old version of the Android SDK system images. Here, 'old' means anything\n"
-    "  older than version 1.4 of the emulator.\n\n"
-
-    "  NOTE: using '-old-system' with recent system images is likely to not work\n"
-    "        properly, though you may not notice it immediately (e.g. failure to\n"
-    "        start the emulated GPS hardware)\n\n"
-    );
-}
-
 #ifdef CONFIG_NAND_LIMITS
 static void
 help_nand_limits(stralloc_t*  out)
diff --git a/android/hw-sensors.c b/android/hw-sensors.c
index e191f68..c3ab12f 100644
--- a/android/hw-sensors.c
+++ b/android/hw-sensors.c
@@ -525,7 +525,7 @@
 
     /* check number of sensors */
     int32_t num_sensors = qemu_get_be32(f);
-    if (num_sensors != MAX_SENSORS) {
+    if (num_sensors > MAX_SENSORS) {
         D("%s: cannot load: snapshot requires %d sensors, %d available\n",
           __FUNCTION__, num_sensors, MAX_SENSORS);
         return -EIO;
@@ -533,7 +533,7 @@
 
     /* load sensor state */
     AndroidSensor i;
-    for (i = 0 ; i < MAX_SENSORS; i++) {
+    for (i = 0 ; i < num_sensors; i++) {
         Sensor* s = &h->sensors[i];
         s->enabled = qemu_get_be32(f);
 
@@ -567,6 +567,14 @@
         }
     }
 
+    /* The following is necessary when we resume a snaphost
+     * created by an older version of the emulator that provided
+     * less hardware sensors.
+     */
+    for ( ; i < MAX_SENSORS; i++ ) {
+        h->sensors[i].enabled = 0;
+    }
+
     return 0;
 }
 
diff --git a/android/hw-sensors.h b/android/hw-sensors.h
index 5cfc748..665cc6d 100644
--- a/android/hw-sensors.h
+++ b/android/hw-sensors.h
@@ -20,6 +20,9 @@
 /* NOTE: this list must be the same that the one defined in
  *       the sensors_qemu.c source of the libsensors.goldfish.so
  *       library.
+ *
+ *       DO NOT CHANGE THE ORDER IN THIS LIST, UNLESS YOU INTEND
+ *       TO BREAK SNAPSHOTS!
  */
 #define  SENSORS_LIST  \
     SENSOR_(ACCELERATION,"acceleration") \
diff --git a/android/main-common.c b/android/main-common.c
index bb07943..9cb97f8 100644
--- a/android/main-common.c
+++ b/android/main-common.c
@@ -27,6 +27,7 @@
 #include "android/utils/debug.h"
 #include "android/utils/path.h"
 #include "android/utils/bufprint.h"
+#include "android/utils/dirscanner.h"
 #include "android/main-common.h"
 #include "android/globals.h"
 #include "android/resource.h"
@@ -341,6 +342,7 @@
 parse_skin_files(const char*      skinDirPath,
                  const char*      skinName,
                  AndroidOptions*  opts,
+                 AndroidHwConfig* hwConfig,
                  AConfig*        *skinConfig,
                  char*           *skinPath)
 {
@@ -433,6 +435,53 @@
         skin_network_delay = aconfig_str(n, "delay", 0);
     }
 
+    /* extract framebuffer information from the skin.
+     *
+     * for version 1 of the skin format, they are in the top-level
+     * 'display' element.
+     *
+     * for version 2 of the skin format, they are under parts.device.display
+     */
+    n = aconfig_find(root, "display");
+    if (n == NULL) {
+        n = aconfig_find(root, "parts");
+        if (n != NULL) {
+            n = aconfig_find(root, "device");
+            if (n != NULL) {
+                n = aconfig_find(root, "display");
+            }
+        }
+    }
+
+    if (n != NULL) {
+        int  width  = aconfig_int(n, "width", hwConfig->hw_lcd_width);
+        int  height = aconfig_int(n, "height", hwConfig->hw_lcd_height);
+        int  depth  = aconfig_int(n, "bpp", hwConfig->hw_lcd_depth);
+
+        if (width > 0 && height > 0) {
+            /* The emulated framebuffer wants sizes that are multiples of 4 */
+            if (((width|height) & 3) != 0) {
+                width  = (width+3) & ~3;
+                height = (height+3) & ~3;
+                D("adjusting LCD dimensions to (%dx%dx)", width, height);
+            }
+
+            /* only depth values of 16 and 32 are correct. 16 is the default. */
+            if (depth != 32 && depth != 16) {
+                depth = 16;
+                D("adjusting LCD bit depth to %d", depth);
+            }
+
+            hwConfig->hw_lcd_width  = width;
+            hwConfig->hw_lcd_height = height;
+            hwConfig->hw_lcd_depth  = depth;
+        }
+        else {
+            D("ignoring invalid skin LCD dimensions (%dx%dx%d)",
+              width, height, depth);
+        }
+    }
+
     *skinConfig = root;
     *skinPath   = strdup(path);
     return;
@@ -537,21 +586,590 @@
     }
 }
 
-int64_t  get_screen_pixels(AConfig*  skinConfig)
+/* this function is used to perform auto-detection of the
+ * system directory in the case of a SDK installation.
+ *
+ * we want to deal with several historical usages, hence
+ * the slightly complicated logic.
+ *
+ * NOTE: the function returns the path to the directory
+ *       containing 'fileName'. this is *not* the full
+ *       path to 'fileName'.
+ */
+static char*
+_getSdkImagePath( const char*  fileName )
 {
-    int64_t  pixels = 0;
-    AConfig*  disp;
+    char   temp[MAX_PATH];
+    char*  p   = temp;
+    char*  end = p + sizeof(temp);
+    char*  q;
+    char*  app;
 
-    if (skinConfig != NULL) {
-        disp = aconfig_find(skinConfig, "display");
-        if (disp != NULL) {
-            int width = aconfig_int(disp, "width", 0);
-            int height = aconfig_int(disp, "height", 0);
-            pixels = (int64_t)width*height;
+    static const char* const  searchPaths[] = {
+        "",                                  /* program's directory */
+        "/lib/images",                       /* this is for SDK 1.0 */
+        "/../platforms/android-1.1/images",  /* this is for SDK 1.1 */
+        NULL
+    };
+
+    app = bufprint_app_dir(temp, end);
+    if (app >= end)
+        return NULL;
+
+    do {
+        int  nn;
+
+        /* first search a few well-known paths */
+        for (nn = 0; searchPaths[nn] != NULL; nn++) {
+            p = bufprint(app, end, "%s", searchPaths[nn]);
+            q = bufprint(p, end, "/%s", fileName);
+            if (q < end && path_exists(temp)) {
+                *p = 0;
+                goto FOUND_IT;
+            }
+        }
+
+        /* hmmm. let's assume that we are in a post-1.1 SDK
+         * scan ../platforms if it exists
+         */
+        p = bufprint(app, end, "/../platforms");
+        if (p < end) {
+            DirScanner*  scanner = dirScanner_new(temp);
+            if (scanner != NULL) {
+                int          found = 0;
+                const char*  subdir;
+
+                for (;;) {
+                    subdir = dirScanner_next(scanner);
+                    if (!subdir) break;
+
+                    q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
+                    if (q >= end || !path_exists(temp))
+                        continue;
+
+                    found = 1;
+                    p = bufprint(p, end, "/%s/images", subdir);
+                    break;
+                }
+                dirScanner_free(scanner);
+                if (found)
+                    break;
+            }
+        }
+
+        /* I'm out of ideas */
+        return NULL;
+
+    } while (0);
+
+FOUND_IT:
+    //D("image auto-detection: %s/%s", temp, fileName);
+    return android_strdup(temp);
+}
+
+static char*
+_getSdkImage( const char*  path, const char*  file )
+{
+    char  temp[MAX_PATH];
+    char  *p = temp, *end = p + sizeof(temp);
+
+    p = bufprint(temp, end, "%s/%s", path, file);
+    if (p >= end || !path_exists(temp))
+        return NULL;
+
+    return android_strdup(temp);
+}
+
+static char*
+_getSdkSystemImage( const char*  path, const char*  optionName, const char*  file )
+{
+    char*  image = _getSdkImage(path, file);
+
+    if (image == NULL) {
+        derror("Your system directory is missing the '%s' image file.\n"
+               "Please specify one with the '%s <filepath>' option",
+               file, optionName);
+        exit(2);
+    }
+    return image;
+}
+
+void sanitizeOptions( AndroidOptions* opts )
+{
+    /* legacy support: we used to use -system <dir> and -image <file>
+     * instead of -sysdir <dir> and -system <file>, so handle this by checking
+     * whether the options point to directories or files.
+     */
+    if (opts->image != NULL) {
+        if (opts->system != NULL) {
+            if (opts->sysdir != NULL) {
+                derror( "You can't use -sysdir, -system and -image at the same time.\n"
+                        "You should probably use '-sysdir <path> -system <file>'.\n" );
+                exit(2);
+            }
+        }
+        dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
+                  "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
+        opts->sysdir = opts->system;
+        opts->system = opts->image;
+        opts->image  = NULL;
+    }
+    else if (opts->system != NULL && path_is_dir(opts->system)) {
+        if (opts->sysdir != NULL) {
+            derror( "Option -system should now be followed by a file path, not a directory one.\n"
+                    "Please use '-sysdir <path>' to point to the system directory.\n" );
+            exit(1);
+        }
+        dwarning( "Please note that the -system option should now be used to point to the initial\n"
+                  "system image (like the obsolete -image option). To point to the system directory\n"
+                  "please now use '-sysdir <path>' instead.\n" );
+
+        opts->sysdir = opts->system;
+        opts->system = NULL;
+    }
+
+    if (opts->nojni) {
+        opts->no_jni = opts->nojni;
+        opts->nojni  = 0;
+    }
+
+    if (opts->nocache) {
+        opts->no_cache = opts->nocache;
+        opts->nocache  = 0;
+    }
+
+    if (opts->noaudio) {
+        opts->no_audio = opts->noaudio;
+        opts->noaudio  = 0;
+    }
+
+    if (opts->noskin) {
+        opts->no_skin = opts->noskin;
+        opts->noskin  = 0;
+    }
+
+    /* If -no-cache is used, ignore any -cache argument */
+    if (opts->no_cache) {
+        opts->cache = 0;
+    }
+
+    /* the purpose of -no-audio is to disable sound output from the emulator,
+     * not to disable Audio emulation. So simply force the 'none' backends */
+    if (opts->no_audio)
+        opts->audio = "none";
+
+    /* we don't accept -skindir without -skin now
+     * to simplify the autoconfig stuff with virtual devices
+     */
+    if (opts->no_skin) {
+        opts->skin    = "320x480";
+        opts->skindir = NULL;
+    }
+
+    if (opts->skindir) {
+        if (!opts->skin) {
+            derror( "the -skindir <path> option requires a -skin <name> option");
+            exit(1);
         }
     }
-    if (pixels == 0)
-        pixels = 320*240;
 
-    return pixels;
+    if (opts->bootchart) {
+        char*  end;
+        int    timeout = strtol(opts->bootchart, &end, 10);
+        if (timeout == 0)
+            opts->bootchart = NULL;
+        else if (timeout < 0 || timeout > 15*60) {
+            derror( "timeout specified for -bootchart option is invalid.\n"
+                    "please use integers between 1 and 900\n");
+            exit(1);
+        }
+    }
 }
+
+AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild)
+{
+    AvdInfo* ret = NULL;
+    char   tmp[MAX_PATH];
+    char*  tmpend = tmp + sizeof(tmp);
+    char*  android_build_root = NULL;
+    char*  android_build_out  = NULL;
+
+    /* If no AVD name was given, try to find the top of the
+     * Android build tree
+     */
+    if (opts->avd == NULL) {
+        do {
+            char*  out = getenv("ANDROID_PRODUCT_OUT");
+
+            if (out == NULL || out[0] == 0)
+                break;
+
+            if (!path_exists(out)) {
+                derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
+                    "You need to build the Android system before launching the emulator",
+                    out);
+                exit(2);
+            }
+
+            android_build_root = path_parent( out, 4 );
+            if (android_build_root == NULL || !path_exists(android_build_root)) {
+                derror("Can't find the Android build root from '%s'\n"
+                    "Please check the definition of the ANDROID_PRODUCT_OUT variable.\n"
+                    "It should point to your product-specific build output directory.\n",
+                    out );
+                exit(2);
+            }
+            android_build_out = out;
+            D( "found Android build root: %s", android_build_root );
+            D( "found Android build out:  %s", android_build_out );
+        } while (0);
+    }
+    /* if no virtual device name is given, and we're not in the
+     * Android build system, we'll need to perform some auto-detection
+     * magic :-)
+     */
+    if (opts->avd == NULL && !android_build_out)
+    {
+        char   dataDirIsSystem = 0;
+
+        if (!opts->sysdir) {
+            opts->sysdir = _getSdkImagePath("system.img");
+            if (!opts->sysdir) {
+                derror(
+                "You did not specify a virtual device name, and the system\n"
+                "directory could not be found.\n\n"
+                "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
+                "to start a given virtual device (see -help-avd for details).\n\n"
+
+                "Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
+                );
+                exit(2);
+            }
+            D("autoconfig: -sysdir %s", opts->sysdir);
+        }
+
+        if (!opts->system) {
+            opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
+            D("autoconfig: -image %s", opts->image);
+        }
+
+        if (!opts->kernel) {
+            opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
+            D("autoconfig: -kernel %s", opts->kernel);
+        }
+
+        if (!opts->ramdisk) {
+            opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
+            D("autoconfig: -ramdisk %s", opts->ramdisk);
+        }
+
+        /* if no data directory is specified, use the system directory */
+        if (!opts->datadir) {
+            opts->datadir   = android_strdup(opts->sysdir);
+            dataDirIsSystem = 1;
+            D("autoconfig: -datadir %s", opts->sysdir);
+        }
+
+        if (!opts->data) {
+            /* check for userdata-qemu.img in the data directory */
+            bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
+            if (!path_exists(tmp)) {
+                derror(
+                "You did not provide the name of an Android Virtual Device\n"
+                "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
+
+                "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
+                "to specify a data partition image file (I hope you know what you're doing).\n"
+                );
+                exit(2);
+            }
+
+            opts->data = android_strdup(tmp);
+            D("autoconfig: -data %s", opts->data);
+        }
+
+        if (!opts->snapstorage && opts->datadir) {
+            bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir);
+            if (path_exists(tmp)) {
+                opts->snapstorage = android_strdup(tmp);
+                D("autoconfig: -snapstorage %s", opts->snapstorage);
+            }
+        }
+    }
+
+    /* setup the virtual device differently depending on whether
+     * we are in the Android build system or not
+     */
+    if (opts->avd != NULL)
+    {
+        ret = avdInfo_new( opts->avd, android_avdParams );
+        if (ret == NULL) {
+            /* an error message has already been printed */
+            dprint("could not find virtual device named '%s'", opts->avd);
+            exit(1);
+        }
+    }
+    else
+    {
+        if (!android_build_out) {
+            android_build_out = android_build_root = opts->sysdir;
+        }
+        ret = avdInfo_newForAndroidBuild(
+                            android_build_root,
+                            android_build_out,
+                            android_avdParams );
+
+        if(ret == NULL) {
+            D("could not start virtual device\n");
+            exit(1);
+        }
+    }
+
+    if (android_build_out) {
+        *inAndroidBuild = 1;
+    } else {
+        *inAndroidBuild = 0;
+    }
+
+    return ret;
+}
+
+
+
+
+#ifdef CONFIG_STANDALONE_UI
+
+#include "android/protocol/core-connection.h"
+#include "android/protocol/fb-updates-impl.h"
+#include "android/protocol/user-events-proxy.h"
+#include "android/protocol/core-commands-proxy.h"
+#include "android/protocol/ui-commands-impl.h"
+#include "android/protocol/attach-ui-impl.h"
+
+/* Emulator's core port. */
+int android_base_port = 0;
+
+// Base console port
+#define CORE_BASE_PORT          5554
+
+// Maximum number of core porocesses running simultaneously on a machine.
+#define MAX_CORE_PROCS          16
+
+// Socket timeout in millisec (set to 5 seconds)
+#define CORE_PORT_TIMEOUT_MS    5000
+
+#include "android/async-console.h"
+
+typedef struct {
+    LoopIo                 io[1];
+    int                    port;
+    int                    ok;
+    AsyncConsoleConnector  connector[1];
+} CoreConsole;
+
+static void
+coreconsole_io_func(void* opaque, int fd, unsigned events)
+{
+    CoreConsole* cc = opaque;
+    AsyncStatus  status;
+    status = asyncConsoleConnector_run(cc->connector, cc->io);
+    if (status == ASYNC_COMPLETE) {
+        cc->ok = 1;
+    }
+}
+
+static void
+coreconsole_init(CoreConsole* cc, const SockAddress* address, Looper* looper)
+{
+    int fd = socket_create_inet(SOCKET_STREAM);
+    AsyncStatus status;
+    cc->port = sock_address_get_port(address);
+    cc->ok   = 0;
+    loopIo_init(cc->io, looper, fd, coreconsole_io_func, cc);
+    if (fd >= 0) {
+        status = asyncConsoleConnector_connect(cc->connector, address, cc->io);
+        if (status == ASYNC_ERROR) {
+            cc->ok = 0;
+        }
+    }
+}
+
+static void
+coreconsole_done(CoreConsole* cc)
+{
+    socket_close(cc->io->fd);
+    loopIo_done(cc->io);
+}
+
+/* List emulator core processes running on the given machine.
+ * This routine is called from main() if -list-cores parameter is set in the
+ * command line.
+ * Param:
+ *  host Value passed with -list-core parameter. Must be either "localhost", or
+ *  an IP address of a machine where core processes must be enumerated.
+ */
+static void
+list_running_cores(const char* host)
+{
+    Looper*         looper;
+    CoreConsole     cores[MAX_CORE_PROCS];
+    SockAddress     address;
+    int             nn, found;
+
+    if (sock_address_init_resolve(&address, host, CORE_BASE_PORT, 0) < 0) {
+        derror("Unable to resolve hostname %s: %s", host, errno_str);
+        return;
+    }
+
+    looper = looper_newGeneric();
+
+    for (nn = 0; nn < MAX_CORE_PROCS; nn++) {
+        int port = CORE_BASE_PORT + nn*2;
+        sock_address_set_port(&address, port);
+        coreconsole_init(&cores[nn], &address, looper);
+    }
+
+    looper_runWithTimeout(looper, CORE_PORT_TIMEOUT_MS*2);
+
+    found = 0;
+    for (nn = 0; nn < MAX_CORE_PROCS; nn++) {
+        int port = CORE_BASE_PORT + nn*2;
+        if (cores[nn].ok) {
+            if (found == 0) {
+                fprintf(stdout, "Running emulator core processes:\n");
+            }
+            fprintf(stdout, "Emulator console port %d\n", port);
+            found++;
+        }
+        coreconsole_done(&cores[nn]);
+    }
+    looper_free(looper);
+
+    if (found == 0) {
+       fprintf(stdout, "There were no running emulator core processes found on %s.\n",
+               host);
+    }
+}
+
+/* Attaches starting UI to a running core process.
+ * This routine is called from main() when -attach-core parameter is set,
+ * indicating that this UI instance should attach to a running core, rather than
+ * start a new core process.
+ * Param:
+ *  opts Android options containing non-NULL attach_core.
+ * Return:
+ *  0 on success, or -1 on failure.
+ */
+static int
+attach_to_core(AndroidOptions* opts) {
+    int iter;
+    SockAddress console_socket;
+    SockAddress** sockaddr_list;
+    QEmulator* emulator;
+
+    // Parse attach_core param extracting the host name, and the port name.
+    char* console_address = strdup(opts->attach_core);
+    char* host_name = console_address;
+    char* port_num = strchr(console_address, ':');
+    if (port_num == NULL) {
+        // The host name is ommited, indicating the localhost
+        host_name = "localhost";
+        port_num = console_address;
+    } else if (port_num == console_address) {
+        // Invalid.
+        derror("Invalid value %s for -attach-core parameter\n",
+               opts->attach_core);
+        return -1;
+    } else {
+        *port_num = '\0';
+        port_num++;
+        if (*port_num == '\0') {
+            // Invalid.
+            derror("Invalid value %s for -attach-core parameter\n",
+                   opts->attach_core);
+            return -1;
+        }
+    }
+
+    /* Create socket address list for the given address, and pull appropriate
+     * address to use for connection. Note that we're fine copying that address
+     * out of the list, since INET and IN6 will entirely fit into SockAddress
+     * structure. */
+    sockaddr_list =
+        sock_address_list_create(host_name, port_num, SOCKET_LIST_FORCE_INET);
+    free(console_address);
+    if (sockaddr_list == NULL) {
+        derror("Unable to resolve address %s: %s\n",
+               opts->attach_core, errno_str);
+        return -1;
+    }
+    for (iter = 0; sockaddr_list[iter] != NULL; iter++) {
+        if (sock_address_get_family(sockaddr_list[iter]) == SOCKET_INET ||
+            sock_address_get_family(sockaddr_list[iter]) == SOCKET_IN6) {
+            memcpy(&console_socket, sockaddr_list[iter], sizeof(SockAddress));
+            break;
+        }
+    }
+    if (sockaddr_list[iter] == NULL) {
+        derror("Unable to resolve address %s. Note that 'port' parameter passed to -attach-core\n"
+               "must be resolvable into an IP address.\n", opts->attach_core);
+        sock_address_list_free(sockaddr_list);
+        return -1;
+    }
+    sock_address_list_free(sockaddr_list);
+
+    if (attachUiImpl_create(&console_socket)) {
+        return -1;
+    }
+
+    // Save core's port, and set the title.
+    android_base_port = sock_address_get_port(&console_socket);
+    emulator = qemulator_get();
+    qemulator_set_title(emulator);
+
+    return 0;
+}
+
+
+void handle_ui_options( AndroidOptions* opts )
+{
+    // Lets see if user just wants to list core process.
+    if (opts->list_cores) {
+        fprintf(stdout, "Enumerating running core processes.\n");
+        list_running_cores(opts->list_cores);
+        exit(0);
+    }
+}
+
+int attach_ui_to_core( AndroidOptions* opts )
+{
+    // Lets see if we're attaching to a running core process here.
+    if (opts->attach_core) {
+        if (attach_to_core(opts)) {
+            return -1;
+        }
+        // Connect to the core's UI control services.
+        if (coreCmdProxy_create(attachUiImpl_get_console_socket())) {
+            return -1;
+        }
+        // Connect to the core's user events service.
+        if (userEventsProxy_create(attachUiImpl_get_console_socket())) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+#else  /* !CONFIG_STANDALONE_UI */
+
+void handle_ui_options( AndroidOptions* opts )
+{
+    return;
+}
+
+int attach_ui_to_core( AndroidOptions* opts )
+{
+    return 0;
+}
+
+#endif /* CONFIG_STANDALONE_UI */
diff --git a/android/main-common.h b/android/main-common.h
index c5131df..0d184d5 100644
--- a/android/main-common.h
+++ b/android/main-common.h
@@ -16,6 +16,7 @@
 #include "android/cmdline-option.h"
 #include "android/skin/keyset.h"
 #include "android/config.h"
+#include "android/avd/hw-config.h"
 
 /* Common routines used by both android/main.c and android/main-ui.c */
 
@@ -36,6 +37,9 @@
 void parse_keyset(const char*  keyset, AndroidOptions*  opts);
 void write_default_keyset( void );
 
+#define NETWORK_SPEED_DEFAULT  "full"
+#define NETWORK_DELAY_DEFAULT  "none"
+
 extern const char*  skin_network_speed;
 extern const char*  skin_network_delay;
 
@@ -45,6 +49,7 @@
 void parse_skin_files(const char*      skinDirPath,
                       const char*      skinName,
                       AndroidOptions*  opts,
+                      AndroidHwConfig* hwConfig,
                       AConfig*        *skinConfig,
                       char*           *skinPath);
 
@@ -55,4 +60,47 @@
                  const char*      skinPath,
                  AndroidOptions*  opts);
 
+/* Sanitize options. This deals with a few legacy options that are now
+ * handled differently. Call before anything else that needs to read
+ * the options list.
+ */
+void sanitizeOptions( AndroidOptions* opts );
+
+/* Creates and initializes AvdInfo instance for the given options.
+ * Param:
+ *  opts - Options passed to the main()
+ *  inAndroidBuild - Upon exit contains 0 if AvdInfo has been initialized from
+ *      AVD file, or 1 if AvdInfo has been initialized from the build directory.
+ * Return:
+ *  AvdInfo instance initialized for the given options.
+ */
+struct AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild);
+
+/* Populate the hwConfig fields corresponding to the kernel/disk images
+ * used by the emulator. This will zero *hwConfig first.
+ */
+void findImagePaths( AndroidHwConfig*  hwConfig,
+                     AndroidOptions*   opts );
+
+/* Updates hardware configuration for the given AVD and options.
+ * Param:
+ *  hwConfig - Hardware configuration to update.
+ *  avd - AVD info containig paths for the hardware configuration.
+ *  opts - Options passed to the main()
+ *  inAndroidBuild - 0 if AVD has been initialized from AVD file, or 1 if AVD
+ *      has been initialized from the build directory.
+ */
+void updateHwConfigFromAVD(AndroidHwConfig* hwConfig, struct AvdInfo* avd,
+                           AndroidOptions* opts, int inAndroidBuild);
+
+/* Called from android/main.c to handle options specific to the standalone
+ * UI program. This is a no-op otherwise.
+ */
+void handle_ui_options( AndroidOptions* opts );
+
+/* Called from android/main.c to potentially attach to a core from the
+ * standalone UI program. This is a no-op otherwise.
+ */
+int attach_ui_to_core( AndroidOptions* opts );
+
 #endif /* ANDROID_MAIN_COMMON_H */
diff --git a/android/main-ui.c b/android/main-ui.c
deleted file mode 100644
index 273f402..0000000
--- a/android/main-ui.c
+++ /dev/null
@@ -1,1518 +0,0 @@
-/* Copyright (C) 2006-2008 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 <signal.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/time.h>
-#ifdef _WIN32
-#include <process.h>
-#endif
-
-#include "sockets.h"
-
-#include "android/android.h"
-#include "qemu-common.h"
-#include "sysemu.h"
-#include "console.h"
-#include "user-events.h"
-
-#include <SDL.h>
-#include <SDL_syswm.h>
-
-#include "math.h"
-
-#include "android/charmap.h"
-#include "android/utils/debug.h"
-#include "android/config.h"
-#include "android/config/config.h"
-
-#include "android/user-config.h"
-#include "android/utils/bufprint.h"
-#include "android/utils/dirscanner.h"
-#include "android/utils/path.h"
-#include "android/utils/tempfile.h"
-
-#include "android/main-common.h"
-#include "android/help.h"
-#include "hw/goldfish_nand.h"
-
-#include "android/globals.h"
-
-#include "android/qemulator.h"
-#include "android/display.h"
-
-#include "android/snapshot.h"
-#include "android/protocol/core-connection.h"
-#include "android/protocol/fb-updates-impl.h"
-#include "android/protocol/user-events-proxy.h"
-#include "android/protocol/core-commands-proxy.h"
-#include "android/protocol/ui-commands-impl.h"
-#include "android/protocol/attach-ui-impl.h"
-
-#include "android/framebuffer.h"
-#include "iolooper.h"
-
-AndroidRotation  android_framebuffer_rotation;
-
-#define  STRINGIFY(x)   _STRINGIFY(x)
-#define  _STRINGIFY(x)  #x
-
-#ifdef ANDROID_SDK_TOOLS_REVISION
-#  define  VERSION_STRING  STRINGIFY(ANDROID_SDK_TOOLS_REVISION)".0"
-#else
-#  define  VERSION_STRING  "standalone"
-#endif
-
-#define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
-
-extern int  control_console_start( int  port );  /* in control.c */
-
-extern int qemu_milli_needed;
-
-/* the default device DPI if none is specified by the skin
- */
-#define  DEFAULT_DEVICE_DPI  165
-
-#if 0
-static int  opts->flashkeys;      /* forward */
-#endif
-
-#ifdef CONFIG_TRACE
-extern void  start_tracing(void);
-extern void  stop_tracing(void);
-#endif
-
-unsigned long   android_verbose;
-
-/* -ui-settings parameters received from the core on UI attachment. */
-char* core_ui_settings = "";
-
-/* Emulator's core port. */
-int android_base_port = 0;
-
-/* this is used by hw/events_device.c to send the charmap name to the system */
-extern const char*    android_skin_keycharmap;
-
-
-int qemu_main(int argc, char **argv);
-
-/* this function dumps the QEMU help */
-extern void  help( void );
-extern void  emulator_help( void );
-
-#define  VERBOSE_OPT(str,var)   { str, &var }
-
-#define  _VERBOSE_TAG(x,y)   { #x, VERBOSE_##x, y },
-static const struct { const char*  name; int  flag; const char*  text; }
-verbose_options[] = {
-    VERBOSE_TAG_LIST
-    { 0, 0, 0 }
-};
-
-void emulator_help( void )
-{
-    STRALLOC_DEFINE(out);
-    android_help_main(out);
-    printf( "%.*s", out->n, out->s );
-    stralloc_reset(out);
-    exit(1);
-}
-
-/* this function is used to perform auto-detection of the
- * system directory in the case of a SDK installation.
- *
- * we want to deal with several historical usages, hence
- * the slightly complicated logic.
- *
- * NOTE: the function returns the path to the directory
- *       containing 'fileName'. this is *not* the full
- *       path to 'fileName'.
- */
-static char*
-_getSdkImagePath( const char*  fileName )
-{
-    char   temp[MAX_PATH];
-    char*  p   = temp;
-    char*  end = p + sizeof(temp);
-    char*  q;
-    char*  app;
-
-    static const char* const  searchPaths[] = {
-        "",                                  /* program's directory */
-        "/lib/images",                       /* this is for SDK 1.0 */
-        "/../platforms/android-1.1/images",  /* this is for SDK 1.1 */
-        NULL
-    };
-
-    app = bufprint_app_dir(temp, end);
-    if (app >= end)
-        return NULL;
-
-    do {
-        int  nn;
-
-        /* first search a few well-known paths */
-        for (nn = 0; searchPaths[nn] != NULL; nn++) {
-            p = bufprint(app, end, "%s", searchPaths[nn]);
-            q = bufprint(p, end, "/%s", fileName);
-            if (q < end && path_exists(temp)) {
-                *p = 0;
-                goto FOUND_IT;
-            }
-        }
-
-        /* hmmm. let's assume that we are in a post-1.1 SDK
-         * scan ../platforms if it exists
-         */
-        p = bufprint(app, end, "/../platforms");
-        if (p < end) {
-            DirScanner*  scanner = dirScanner_new(temp);
-            if (scanner != NULL) {
-                int          found = 0;
-                const char*  subdir;
-
-                for (;;) {
-                    subdir = dirScanner_next(scanner);
-                    if (!subdir) break;
-
-                    q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
-                    if (q >= end || !path_exists(temp))
-                        continue;
-
-                    found = 1;
-                    p = bufprint(p, end, "/%s/images", subdir);
-                    break;
-                }
-                dirScanner_free(scanner);
-                if (found)
-                    break;
-            }
-        }
-
-        /* I'm out of ideas */
-        return NULL;
-
-    } while (0);
-
-FOUND_IT:
-    //D("image auto-detection: %s/%s", temp, fileName);
-    return android_strdup(temp);
-}
-
-static char*
-_getSdkImage( const char*  path, const char*  file )
-{
-    char  temp[MAX_PATH];
-    char  *p = temp, *end = p + sizeof(temp);
-
-    p = bufprint(temp, end, "%s/%s", path, file);
-    if (p >= end || !path_exists(temp))
-        return NULL;
-
-    return android_strdup(temp);
-}
-
-static char*
-_getSdkSystemImage( const char*  path, const char*  optionName, const char*  file )
-{
-    char*  image = _getSdkImage(path, file);
-
-    if (image == NULL) {
-        derror("Your system directory is missing the '%s' image file.\n"
-               "Please specify one with the '%s <filepath>' option",
-               file, optionName);
-        exit(2);
-    }
-    return image;
-}
-
-static void
-_forceAvdImagePath( AvdImageType  imageType,
-                   const char*   path,
-                   const char*   description,
-                   int           required )
-{
-    if (path == NULL)
-        return;
-
-    if (required && !path_exists(path)) {
-        derror("Cannot find %s image file: %s", description, path);
-        exit(1);
-    }
-    android_avdParams->forcePaths[imageType] = path;
-}
-
-static uint64_t
-_adjustPartitionSize( const char*  description,
-                      uint64_t     imageBytes,
-                      uint64_t     defaultBytes,
-                      int          inAndroidBuild )
-{
-    char      temp[64];
-    unsigned  imageMB;
-    unsigned  defaultMB;
-
-    if (imageBytes <= defaultBytes)
-        return defaultBytes;
-
-    imageMB   = convertBytesToMB(imageBytes);
-    defaultMB = convertBytesToMB(defaultBytes);
-
-    if (imageMB > defaultMB) {
-        snprintf(temp, sizeof temp, "(%d MB > %d MB)", imageMB, defaultMB);
-    } else {
-        snprintf(temp, sizeof temp, "(%lld bytes > %lld bytes)", imageBytes, defaultBytes);
-    }
-
-    if (inAndroidBuild) {
-        dwarning("%s partition size adjusted to match image file %s\n", description, temp);
-    }
-
-    return convertMBToBytes(imageMB);
-}
-
-// Base console port
-#define CORE_BASE_PORT          5554
-
-// Maximum number of core porocesses running simultaneously on a machine.
-#define MAX_CORE_PROCS          16
-
-// Socket timeout in millisec (set to 5 seconds)
-#define CORE_PORT_TIMEOUT_MS    5000
-
-#include "android/async-console.h"
-
-typedef struct {
-    LoopIo                 io[1];
-    int                    port;
-    int                    ok;
-    AsyncConsoleConnector  connector[1];
-} CoreConsole;
-
-static void
-coreconsole_io_func(void* opaque, int fd, unsigned events)
-{
-    CoreConsole* cc = opaque;
-    AsyncStatus  status;
-    status = asyncConsoleConnector_run(cc->connector, cc->io);
-    if (status == ASYNC_COMPLETE) {
-        cc->ok = 1;
-    }
-}
-
-static void
-coreconsole_init(CoreConsole* cc, const SockAddress* address, Looper* looper)
-{
-    int fd = socket_create_inet(SOCKET_STREAM);
-    AsyncStatus status;
-    cc->port = sock_address_get_port(address);
-    cc->ok   = 0;
-    loopIo_init(cc->io, looper, fd, coreconsole_io_func, cc);
-    if (fd >= 0) {
-        status = asyncConsoleConnector_connect(cc->connector, address, cc->io);
-        if (status == ASYNC_ERROR) {
-            cc->ok = 0;
-        }
-    }
-}
-
-static void
-coreconsole_done(CoreConsole* cc)
-{
-    socket_close(cc->io->fd);
-    loopIo_done(cc->io);
-}
-
-/* List emulator core processes running on the given machine.
- * This routine is called from main() if -list-cores parameter is set in the
- * command line.
- * Param:
- *  host Value passed with -list-core parameter. Must be either "localhost", or
- *  an IP address of a machine where core processes must be enumerated.
- */
-static void
-list_running_cores(const char* host)
-{
-    Looper*         looper;
-    CoreConsole     cores[MAX_CORE_PROCS];
-    SockAddress     address;
-    int             nn, found;
-
-    if (sock_address_init_resolve(&address, host, CORE_BASE_PORT, 0) < 0) {
-        derror("Unable to resolve hostname %s: %s", host, errno_str);
-        return;
-    }
-
-    looper = looper_newGeneric();
-
-    for (nn = 0; nn < MAX_CORE_PROCS; nn++) {
-        int port = CORE_BASE_PORT + nn*2;
-        sock_address_set_port(&address, port);
-        coreconsole_init(&cores[nn], &address, looper);
-    }
-
-    looper_runWithTimeout(looper, CORE_PORT_TIMEOUT_MS*2);
-
-    found = 0;
-    for (nn = 0; nn < MAX_CORE_PROCS; nn++) {
-        int port = CORE_BASE_PORT + nn*2;
-        if (cores[nn].ok) {
-            if (found == 0) {
-                fprintf(stdout, "Running emulator core processes:\n");
-            }
-            fprintf(stdout, "Emulator console port %d\n", port);
-            found++;
-        }
-        coreconsole_done(&cores[nn]);
-    }
-    looper_free(looper);
-
-    if (found == 0) {
-       fprintf(stdout, "There were no running emulator core processes found on %s.\n",
-               host);
-    }
-}
-
-/* Attaches starting UI to a running core process.
- * This routine is called from main() when -attach-core parameter is set,
- * indicating that this UI instance should attach to a running core, rather than
- * start a new core process.
- * Param:
- *  opts Android options containing non-NULL attach_core.
- * Return:
- *  0 on success, or -1 on failure.
- */
-static int
-attach_to_core(AndroidOptions* opts) {
-    int iter;
-    SockAddress console_socket;
-    SockAddress** sockaddr_list;
-    QEmulator* emulator;
-
-    // Parse attach_core param extracting the host name, and the port name.
-    char* console_address = strdup(opts->attach_core);
-    char* host_name = console_address;
-    char* port_num = strchr(console_address, ':');
-    if (port_num == NULL) {
-        // The host name is ommited, indicating the localhost
-        host_name = "localhost";
-        port_num = console_address;
-    } else if (port_num == console_address) {
-        // Invalid.
-        derror("Invalid value %s for -attach-core parameter\n",
-               opts->attach_core);
-        return -1;
-    } else {
-        *port_num = '\0';
-        port_num++;
-        if (*port_num == '\0') {
-            // Invalid.
-            derror("Invalid value %s for -attach-core parameter\n",
-                   opts->attach_core);
-            return -1;
-        }
-    }
-
-    /* Create socket address list for the given address, and pull appropriate
-     * address to use for connection. Note that we're fine copying that address
-     * out of the list, since INET and IN6 will entirely fit into SockAddress
-     * structure. */
-    sockaddr_list =
-        sock_address_list_create(host_name, port_num, SOCKET_LIST_FORCE_INET);
-    free(console_address);
-    if (sockaddr_list == NULL) {
-        derror("Unable to resolve address %s: %s\n",
-               opts->attach_core, errno_str);
-        return -1;
-    }
-    for (iter = 0; sockaddr_list[iter] != NULL; iter++) {
-        if (sock_address_get_family(sockaddr_list[iter]) == SOCKET_INET ||
-            sock_address_get_family(sockaddr_list[iter]) == SOCKET_IN6) {
-            memcpy(&console_socket, sockaddr_list[iter], sizeof(SockAddress));
-            break;
-        }
-    }
-    if (sockaddr_list[iter] == NULL) {
-        derror("Unable to resolve address %s. Note that 'port' parameter passed to -attach-core\n"
-               "must be resolvable into an IP address.\n", opts->attach_core);
-        sock_address_list_free(sockaddr_list);
-        return -1;
-    }
-    sock_address_list_free(sockaddr_list);
-
-    if (attachUiImpl_create(&console_socket)) {
-        return -1;
-    }
-
-    // Save core's port, and set the title.
-    android_base_port = sock_address_get_port(&console_socket);
-    emulator = qemulator_get();
-    qemulator_set_title(emulator);
-
-    return 0;
-}
-
-int main(int argc, char **argv)
-{
-    char   tmp[MAX_PATH];
-    char*  tmpend = tmp + sizeof(tmp);
-    char*  args[128];
-    int    n;
-    char*  opt;
-    int    use_sdcard_img = 0;
-    int    serial = 0;
-    int    gps_serial = 0;
-    int    radio_serial = 0;
-    int    qemud_serial = 0;
-    int    shell_serial = 0;
-    unsigned  cachePartitionSize = 0;
-    unsigned  systemPartitionSize = 0;
-    unsigned  dataPartitionSize = 0;
-    unsigned  defaultPartitionSize = convertMBToBytes(66);
-
-    AndroidHwConfig*  hw;
-    AvdInfo*          avd;
-    AConfig*          skinConfig;
-    char*             skinPath;
-
-    //const char *appdir = get_app_dir();
-    char*       android_build_root = NULL;
-    char*       android_build_out  = NULL;
-
-    AndroidOptions  opts[1];
-    /* LCD density value to pass to the core. */
-    char lcd_density[16];
-    /* net.shared_net_ip boot property value. */
-    char boot_prop_ip[64];
-    boot_prop_ip[0] = '\0';
-
-    args[0] = argv[0];
-
-    if ( android_parse_options( &argc, &argv, opts ) < 0 ) {
-        exit(1);
-    }
-
-#ifdef _WIN32
-    socket_init();
-#endif
-
-    // Lets see if user just wants to list core process.
-    if (opts->list_cores) {
-        fprintf(stdout, "Enumerating running core processes.\n");
-        list_running_cores(opts->list_cores);
-        exit(0);
-    }
-
-    while (argc-- > 1) {
-        opt = (++argv)[0];
-
-        if(!strcmp(opt, "-qemu")) {
-            argc--;
-            argv++;
-            break;
-        }
-
-        if (!strcmp(opt, "-help")) {
-            emulator_help();
-        }
-
-        if (!strncmp(opt, "-help-",6)) {
-            STRALLOC_DEFINE(out);
-            opt += 6;
-
-            if (!strcmp(opt, "all")) {
-                android_help_all(out);
-            }
-            else if (android_help_for_option(opt, out) == 0) {
-                /* ok */
-            }
-            else if (android_help_for_topic(opt, out) == 0) {
-                /* ok */
-            }
-            if (out->n > 0) {
-                printf("\n%.*s", out->n, out->s);
-                exit(0);
-            }
-
-            fprintf(stderr, "unknown option: -help-%s\n", opt);
-            fprintf(stderr, "please use -help for a list of valid topics\n");
-            exit(1);
-        }
-
-        if (opt[0] == '-') {
-            fprintf(stderr, "unknown option: %s\n", opt);
-            fprintf(stderr, "please use -help for a list of valid options\n");
-            exit(1);
-        }
-
-        fprintf(stderr, "invalid command-line parameter: %s.\n", opt);
-        fprintf(stderr, "Hint: use '@foo' to launch a virtual device named 'foo'.\n");
-        fprintf(stderr, "please use -help for more information\n");
-        exit(1);
-    }
-
-    if (opts->version) {
-        printf("Android emulator version %s\n"
-               "Copyright (C) 2006-2008 The Android Open Source Project and many others.\n"
-               "This program is a derivative of the QEMU CPU emulator (www.qemu.org).\n\n",
-#if defined ANDROID_BUILD_ID
-               VERSION_STRING " (build_id " STRINGIFY(ANDROID_BUILD_ID) ")" );
-#else
-               VERSION_STRING);
-#endif
-        printf("  This software is licensed under the terms of the GNU General Public\n"
-               "  License version 2, as published by the Free Software Foundation, and\n"
-               "  may be copied, distributed, and modified under those terms.\n\n"
-               "  This program is distributed in the hope that it will be useful,\n"
-               "  but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-               "  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
-               "  GNU General Public License for more details.\n\n");
-
-        exit(0);
-    }
-
-    /* Initialization of UI started with -attach-core should work differently
-     * than initialization of UI that starts the core. In particular....
-     */
-
-    /* -charmap is incompatible with -attach-core, because particular
-     * charmap gets set up in the running core. */
-    if (android_charmap_setup(opts->charmap)) {
-        exit(1);
-    }
-
-    /* legacy support: we used to use -system <dir> and -image <file>
-     * instead of -sysdir <dir> and -system <file>, so handle this by checking
-     * whether the options point to directories or files.
-     */
-    if (opts->image != NULL) {
-        if (opts->system != NULL) {
-            if (opts->sysdir != NULL) {
-                derror( "You can't use -sysdir, -system and -image at the same time.\n"
-                        "You should probably use '-sysdir <path> -system <file>'.\n" );
-                exit(2);
-            }
-        }
-        dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
-                  "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
-        opts->sysdir = opts->system;
-        opts->system = opts->image;
-        opts->image  = NULL;
-    }
-    else if (opts->system != NULL && path_is_dir(opts->system)) {
-        if (opts->sysdir != NULL) {
-            derror( "Option -system should now be followed by a file path, not a directory one.\n"
-                    "Please use '-sysdir <path>' to point to the system directory.\n" );
-            exit(1);
-        }
-        dwarning( "Please note that the -system option should now be used to point to the initial\n"
-                  "system image (like the obsolete -image option). To point to the system directory\n"
-                  "please now use '-sysdir <path>' instead.\n" );
-
-        opts->sysdir = opts->system;
-        opts->system = NULL;
-    }
-
-    if (opts->nojni)
-        opts->no_jni = opts->nojni;
-
-    if (opts->nocache)
-        opts->no_cache = opts->nocache;
-
-    if (opts->noaudio)
-        opts->no_audio = opts->noaudio;
-
-    if (opts->noskin)
-        opts->no_skin = opts->noskin;
-
-    /* If no AVD name was given, try to find the top of the
-     * Android build tree
-     */
-    if (opts->avd == NULL) {
-        do {
-            char*  out = getenv("ANDROID_PRODUCT_OUT");
-
-            if (out == NULL || out[0] == 0)
-                break;
-
-            if (!path_exists(out)) {
-                derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
-                    "You need to build the Android system before launching the emulator",
-                    out);
-                exit(2);
-            }
-
-            android_build_root = path_parent( out, 4 );
-            if (android_build_root == NULL || !path_exists(android_build_root)) {
-                derror("Can't find the Android build root from '%s'\n"
-                    "Please check the definition of the ANDROID_PRODUCT_OUT variable.\n"
-                    "It should point to your product-specific build output directory.\n",
-                    out );
-                exit(2);
-            }
-            android_build_out = out;
-            D( "found Android build root: %s", android_build_root );
-            D( "found Android build out:  %s", android_build_out );
-        } while (0);
-    }
-    /* if no virtual device name is given, and we're not in the
-     * Android build system, we'll need to perform some auto-detection
-     * magic :-)
-     */
-    if (opts->avd == NULL && !android_build_out)
-    {
-        char   dataDirIsSystem = 0;
-
-        if (!opts->sysdir) {
-            opts->sysdir = _getSdkImagePath("system.img");
-            if (!opts->sysdir) {
-                derror(
-                "You did not specify a virtual device name, and the system\n"
-                "directory could not be found.\n\n"
-                "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
-                "to start a given virtual device (see -help-avd for details).\n\n"
-
-                "Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
-                );
-                exit(2);
-            }
-            D("autoconfig: -sysdir %s", opts->sysdir);
-        }
-
-        if (!opts->system) {
-            opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
-            D("autoconfig: -image %s", opts->image);
-        }
-
-        if (!opts->kernel) {
-            opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
-            D("autoconfig: -kernel %s", opts->kernel);
-        }
-
-        if (!opts->ramdisk) {
-            opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
-            D("autoconfig: -ramdisk %s", opts->ramdisk);
-        }
-
-        /* if no data directory is specified, use the system directory */
-        if (!opts->datadir) {
-            opts->datadir   = android_strdup(opts->sysdir);
-            dataDirIsSystem = 1;
-            D("autoconfig: -datadir %s", opts->sysdir);
-        }
-
-        if (!opts->data) {
-            /* check for userdata-qemu.img in the data directory */
-            bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
-            if (!path_exists(tmp)) {
-                derror(
-                "You did not provide the name of an Android Virtual Device\n"
-                "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
-
-                "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
-                "to specify a data partition image file (I hope you know what you're doing).\n"
-                );
-                exit(2);
-            }
-
-            opts->data = android_strdup(tmp);
-            D("autoconfig: -data %s", opts->data);
-        }
-
-        if (!opts->sdcard && opts->datadir) {
-            bufprint(tmp, tmpend, "%s/sdcard.img", opts->datadir);
-            if (path_exists(tmp)) {
-                opts->sdcard = android_strdup(tmp);
-                D("autoconfig: -sdcard %s", opts->sdcard);
-            }
-        }
-
-#if CONFIG_ANDROID_SNAPSHOTS
-        if (!opts->snapstorage && opts->datadir) {
-            bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir);
-            if (path_exists(tmp)) {
-                opts->snapstorage = android_strdup(tmp);
-                D("autoconfig: -snapstorage %s", opts->snapstorage);
-            }
-        }
-#endif // CONFIG_ANDROID_SNAPSHOTS
-    }
-
-    /* setup the virtual device parameters from our options
-     */
-    if (opts->no_cache) {
-        android_avdParams->flags |= AVDINFO_NO_CACHE;
-    }
-    if (opts->wipe_data) {
-        android_avdParams->flags |= AVDINFO_WIPE_DATA | AVDINFO_WIPE_CACHE;
-    }
-#if CONFIG_ANDROID_SNAPSHOTS
-    if (opts->no_snapstorage) {
-        android_avdParams->flags |= AVDINFO_NO_SNAPSHOTS;
-    }
-#endif
-
-    /* if certain options are set, we can force the path of
-        * certain kernel/disk image files
-        */
-    _forceAvdImagePath(AVD_IMAGE_KERNEL,     opts->kernel,      "kernel", 1);
-    _forceAvdImagePath(AVD_IMAGE_INITSYSTEM, opts->system,      "system", 1);
-    _forceAvdImagePath(AVD_IMAGE_RAMDISK,    opts->ramdisk,     "ramdisk", 1);
-    _forceAvdImagePath(AVD_IMAGE_USERDATA,   opts->data,        "user data", 0);
-    _forceAvdImagePath(AVD_IMAGE_CACHE,      opts->cache,       "cache", 0);
-    _forceAvdImagePath(AVD_IMAGE_SDCARD,     opts->sdcard,      "SD Card", 0);
-#if CONFIG_ANDROID_SNAPSHOTS
-    _forceAvdImagePath(AVD_IMAGE_SNAPSHOTS,  opts->snapstorage, "snapshots", 0);
-#endif
-
-    /* we don't accept -skindir without -skin now
-     * to simplify the autoconfig stuff with virtual devices
-     */
-    if (opts->no_skin) {
-        opts->skin    = "320x480";
-        opts->skindir = NULL;
-    }
-
-    if (opts->skindir) {
-        if (!opts->skin) {
-            derror( "the -skindir <path> option requires a -skin <name> option");
-            exit(1);
-        }
-    }
-    android_avdParams->skinName     = opts->skin;
-    android_avdParams->skinRootPath = opts->skindir;
-
-    /* setup the virtual device differently depending on whether
-     * we are in the Android build system or not
-     */
-    if (opts->avd != NULL)
-    {
-        android_avdInfo = avdInfo_new( opts->avd, android_avdParams );
-        if (android_avdInfo == NULL) {
-            /* an error message has already been printed */
-            dprint("could not find virtual device named '%s'", opts->avd);
-            exit(1);
-        }
-    }
-    else
-    {
-        if (!android_build_out) {
-            android_build_out = android_build_root = opts->sysdir;
-        }
-        android_avdInfo = avdInfo_newForAndroidBuild(
-                            android_build_root,
-                            android_build_out,
-                            android_avdParams );
-
-        if(android_avdInfo == NULL) {
-            D("could not start virtual device\n");
-            exit(1);
-        }
-    }
-
-    avd = android_avdInfo;
-
-    /* get the skin from the virtual device configuration */
-    opts->skin    = (char*) avdInfo_getSkinName( avd );
-    opts->skindir = (char*) avdInfo_getSkinDir( avd );
-
-    if (opts->skin) {
-        D("autoconfig: -skin %s", opts->skin);
-    }
-    if (opts->skindir) {
-        D("autoconfig: -skindir %s", opts->skindir);
-    }
-
-    /* Read hardware configuration */
-    hw = android_hw;
-    if (avdInfo_getHwConfig(avd, hw) < 0) {
-        derror("could not read hardware configuration ?");
-        exit(1);
-    }
-
-    if (opts->keyset) {
-        parse_keyset(opts->keyset, opts);
-        if (!android_keyset) {
-            fprintf(stderr,
-                    "emulator: WARNING: could not find keyset file named '%s',"
-                    " using defaults instead\n",
-                    opts->keyset);
-        }
-    }
-    if (!android_keyset) {
-        parse_keyset("default", opts);
-        if (!android_keyset) {
-            android_keyset = skin_keyset_new_from_text( skin_keyset_get_default() );
-            if (!android_keyset) {
-                fprintf(stderr, "PANIC: default keyset file is corrupted !!\n" );
-                fprintf(stderr, "PANIC: please update the code in android/skin/keyset.c\n" );
-                exit(1);
-            }
-            if (!opts->keyset)
-                write_default_keyset();
-        }
-    }
-
-    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");
-            exit(1);
-        }
-        snprintf(boot_prop_ip, sizeof(boot_prop_ip),
-                 "net.shared_net_ip=10.1.2.%ld", shared_net_id);
-    }
-
-
-    user_config_init();
-    parse_skin_files(opts->skindir, opts->skin, opts,
-                     &skinConfig, &skinPath);
-
-    if (!opts->netspeed) {
-        if (skin_network_speed)
-            D("skin network speed: '%s'", skin_network_speed);
-        opts->netspeed = (char*)skin_network_speed;
-    }
-    if (!opts->netdelay) {
-        if (skin_network_delay)
-            D("skin network delay: '%s'", skin_network_delay);
-        opts->netdelay = (char*)skin_network_delay;
-    }
-
-    if (opts->trace) {
-        char*   tracePath = avdInfo_getTracePath(avd, opts->trace);
-        int     ret;
-
-        if (tracePath == NULL) {
-            derror( "bad -trace parameter" );
-            exit(1);
-        }
-        ret = path_mkdir_if_needed( tracePath, 0755 );
-        if (ret < 0) {
-            fprintf(stderr, "could not create directory '%s'\n", tmp);
-            exit(2);
-        }
-        opts->trace = tracePath;
-    }
-
-    if (opts->no_cache)
-        opts->cache = 0;
-
-    n = 1;
-    /* generate arguments for the underlying qemu main() */
-    {
-        const char*  kernelFile    = avdInfo_getImageFile(avd, AVD_IMAGE_KERNEL);
-        int          kernelFileLen = strlen(kernelFile);
-
-        args[n++] = "-kernel";
-        args[n++] = (char*)kernelFile;
-
-        /* If the kernel image name ends in "-armv7", then change the cpu
-         * type automatically. This is a poor man's approach to configuration
-         * management, but should allow us to get past building ARMv7
-         * system images with dex preopt pass without introducing too many
-         * changes to the emulator sources.
-         *
-         * XXX:
-         * A 'proper' change would require adding some sort of hardware-property
-         * to each AVD config file, then automatically determine its value for
-         * full Android builds (depending on some environment variable), plus
-         * some build system changes. I prefer not to do that for now for reasons
-         * of simplicity.
-         */
-         if (kernelFileLen > 6 && !memcmp(kernelFile + kernelFileLen - 6, "-armv7", 6)) {
-            args[n++] = "-cpu";
-            args[n++] = "cortex-a8";
-         }
-    }
-
-    if (boot_prop_ip[0]) {
-        args[n++] = "-boot-property";
-        args[n++] = boot_prop_ip;
-    }
-
-    if (opts->tcpdump) {
-        args[n++] = "-tcpdump";
-        args[n++] = opts->tcpdump;
-    }
-
-#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";
-    }
-
-    /* the purpose of -no-audio is to disable sound output from the emulator,
-     * not to disable Audio emulation. So simply force the 'none' backends */
-    if (opts->no_audio)
-        opts->audio = "none";
-
-    if (opts->audio) {
-        args[n++] = "-audio";
-        args[n++] = opts->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;
-    }
-
-    args[n++] = "-initrd";
-    args[n++] = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_RAMDISK);
-
-    if (opts->partition_size) {
-        char*  end;
-        long   sizeMB = strtol(opts->partition_size, &end, 0);
-        long   minSizeMB = 10;
-        long   maxSizeMB = LONG_MAX / ONE_MB;
-
-        if (sizeMB < 0 || *end != 0) {
-            derror( "-partition-size must be followed by a positive integer" );
-            exit(1);
-        }
-        if (sizeMB < minSizeMB || sizeMB > maxSizeMB) {
-            derror( "partition-size (%d) must be between %dMB and %dMB",
-                    sizeMB, minSizeMB, maxSizeMB );
-            exit(1);
-        }
-        defaultPartitionSize = sizeMB * ONE_MB;
-    }
-
-    /* Check the size of the system partition image.
-     * If we have an AVD, it must be smaller than
-     * the disk.systemPartition.size hardware property.
-     *
-     * Otherwise, we need to adjust the systemPartitionSize
-     * automatically, and print a warning.
-     *
-     */
-    {
-        uint64_t   systemBytes  = avdInfo_getImageFileSize(avd, AVD_IMAGE_INITSYSTEM);
-        uint64_t   defaultBytes = defaultPartitionSize;
-
-        if (defaultBytes == 0 || opts->partition_size)
-            defaultBytes = defaultPartitionSize;
-
-        systemPartitionSize = _adjustPartitionSize("system", systemBytes, defaultBytes,
-                                                   android_build_out != NULL);
-    }
-
-    /* Check the size of the /data partition. The only interesting cases here are:
-     * - when the USERDATA image already exists and is larger than the default
-     * - when we're wiping data and the INITDATA is larger than the default.
-     */
-
-    {
-        const char*  dataPath     = avdInfo_getImageFile(avd, AVD_IMAGE_USERDATA);
-        uint64_t     defaultBytes = defaultPartitionSize;
-
-        if (defaultBytes == 0 || opts->partition_size)
-            defaultBytes = defaultPartitionSize;
-
-        if (dataPath == NULL || !path_exists(dataPath) || opts->wipe_data) {
-            dataPath = avdInfo_getImageFile(avd, AVD_IMAGE_INITDATA);
-        }
-        if (dataPath == NULL || !path_exists(dataPath)) {
-            dataPartitionSize = defaultBytes;
-        }
-        else {
-            uint64_t  dataBytes;
-            path_get_size(dataPath, &dataBytes);
-
-            dataPartitionSize = _adjustPartitionSize("data", dataBytes, defaultBytes,
-                                                     android_build_out != NULL);
-        }
-    }
-
-    {
-        const char*  filetype = "file";
-
-        if (avdInfo_isImageReadOnly(avd, AVD_IMAGE_INITSYSTEM))
-            filetype = "initfile";
-
-        bufprint(tmp, tmpend,
-             "system,size=0x%x,%s=%s", systemPartitionSize, filetype,
-             avdInfo_getImageFile(avd, AVD_IMAGE_INITSYSTEM));
-
-        args[n++] = "-nand";
-        args[n++] = strdup(tmp);
-    }
-
-    bufprint(tmp, tmpend,
-             "userdata,size=0x%x,file=%s",
-             dataPartitionSize,
-             avdInfo_getImageFile(avd, AVD_IMAGE_USERDATA));
-
-    args[n++] = "-nand";
-    args[n++] = strdup(tmp);
-
-    if (hw->disk_cachePartition) {
-        opts->cache = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_CACHE);
-        cachePartitionSize = hw->disk_cachePartition_size;
-    }
-    else if (opts->cache) {
-        dwarning( "Emulated hardware doesn't support a cache partition" );
-        opts->cache    = NULL;
-        opts->no_cache = 1;
-    }
-
-    if (opts->cache) {
-        /* use a specific cache file */
-        sprintf(tmp, "cache,size=0x%0x,file=%s", cachePartitionSize, opts->cache);
-        args[n++] = "-nand";
-        args[n++] = strdup(tmp);
-    }
-    else if (!opts->no_cache) {
-        /* create a temporary cache partition file */
-        sprintf(tmp, "cache,size=0x%0x", cachePartitionSize);
-        args[n++] = "-nand";
-        args[n++] = strdup(tmp);
-    }
-
-    if (hw->hw_sdCard != 0)
-        opts->sdcard = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_SDCARD);
-    else if (opts->sdcard) {
-        dwarning( "Emulated hardware doesn't support SD Cards" );
-        opts->sdcard = NULL;
-    }
-
-    if(opts->sdcard) {
-        uint64_t  size;
-        if (path_get_size(opts->sdcard, &size) == 0) {
-            /* see if we have an sdcard image.  get its size if it exists */
-            /* due to what looks like limitations of the MMC protocol, one has
-             * to use an SD Card image that is equal or larger than 9 MB
-             */
-            if (size < 9*1024*1024ULL) {
-                fprintf(stderr, "### WARNING: SD Card files must be at least 9MB, ignoring '%s'\n", opts->sdcard);
-            } else {
-                args[n++] = "-hda";
-                args[n++] = opts->sdcard;
-                use_sdcard_img = 1;
-            }
-        } else {
-            D("no SD Card image at '%s'", opts->sdcard);
-        }
-    }
-
-#if CONFIG_ANDROID_SNAPSHOTS
-    if (!opts->no_snapstorage) {
-        opts->snapstorage = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_SNAPSHOTS);
-        if(opts->snapstorage) {
-            if (path_exists(opts->snapstorage)) {
-                args[n++] = "-hdb";
-                args[n++] = opts->snapstorage;
-            } else {
-                D("no image at '%s', state snapshots disabled", opts->snapstorage);
-            }
-        }
-
-        if (!opts->no_snapshot) {
-            char* snapshot_name =
-                opts->snapshot ? opts->snapshot : "default-boot";
-            if (!opts->no_snapshot_load) {
-              args[n++] = "-loadvm";
-              args[n++] = snapshot_name;
-            }
-            if (!opts->no_snapshot_save) {
-              args[n++] = "-savevm-on-exit";
-              args[n++] = snapshot_name;
-            }
-        } else if (opts->snapshot) {
-            dwarning("option '-no-snapshot' overrides '-snapshot', continuing with boot sequence");
-        } else if (opts->no_snapshot_load || opts->no_snapshot_save) {
-            D("ignoring redundant option(s) '-no-snapshot-load' and/or '-no-snapshot-save' implied by '-no-snapshot'");
-        }
-        // TODO: Convey -no-snapshot-time-update to core subprocess (?)
-    } else if (opts->snapshot || opts->snapstorage) {
-        dwarning("option '-no-snapstorage' overrides '-snapshot' and '-snapstorage', "
-                 "continuing with full boot, state snapshots are disabled");
-    } else if (opts->no_snapshot) {
-        D("ignoring redundant option '-no-snapshot' implied by '-no-snapstorage'");
-    }
-
-    if (opts->snapshot_list) {
-        snapshot_print_and_exit(opts->snapstorage);
-    }
-#endif // CONFIG_ANDROID_SNAPSHOTS
-
-    if (!opts->logcat || opts->logcat[0] == 0) {
-        opts->logcat = getenv("ANDROID_LOG_TAGS");
-        if (opts->logcat && opts->logcat[0] == 0)
-            opts->logcat = NULL;
-    }
-
-#if 0
-    if (opts->console) {
-        derror( "option -console is obsolete. please use -shell instead" );
-        exit(1);
-    }
-#endif
-
-    /* we always send the kernel messages from ttyS0 to android_kmsg */
-    {
-        if (opts->show_kernel) {
-            args[n++] = "-show-kernel";
-        }
-
-        args[n++] = "-serial";
-        args[n++] = "android-kmsg";
-        serial++;
-    }
-
-    /* XXXX: TODO: implement -shell and -logcat through qemud instead */
-    if (!opts->shell_serial) {
-#ifdef _WIN32
-        opts->shell_serial = "con:";
-#else
-        opts->shell_serial = "stdio";
-#endif
-    }
-    else
-        opts->shell = 1;
-
-    if (opts->shell || opts->logcat) {
-        args[n++] = "-serial";
-        args[n++] = opts->shell_serial;
-        shell_serial = serial++;
-    }
-
-    if (opts->old_system)
-    {
-        if (opts->radio) {
-            args[n++] = "-serial";
-            args[n++] = opts->radio;
-            radio_serial = serial++;
-        }
-        else {
-            args[n++] = "-serial";
-            args[n++] = "android-modem";
-            radio_serial = serial++;
-        }
-        if (opts->gps) {
-            args[n++] = "-serial";
-            args[n++] = opts->gps;
-            gps_serial = serial++;
-        }
-    }
-    else /* !opts->old_system */
-    {
-        args[n++] = "-serial";
-        args[n++] = "android-qemud";
-        qemud_serial = serial++;
-
-        if (opts->radio) {
-            args[n++] = "-radio";
-            args[n++] = opts->radio;
-        }
-
-        if (opts->gps) {
-            args[n++] = "-gps";
-            args[n++] = opts->gps;
-        }
-    }
-
-    if (opts->memory) {
-        char*  end;
-        long   ramSize = strtol(opts->memory, &end, 0);
-        if (ramSize < 0 || *end != 0) {
-            derror( "-memory must be followed by a positive integer" );
-            exit(1);
-        }
-        if (ramSize < 32 || ramSize > 4096) {
-            derror( "physical memory size must be between 32 and 4096 MB" );
-            exit(1);
-        }
-    }
-    if (!opts->memory) {
-        int ramSize = hw->hw_ramSize;
-        if (ramSize <= 0) {
-            /* Compute the default RAM size based on the size of screen.
-             * This is only used when the skin doesn't provide the ram
-             * size through its hardware.ini (i.e. legacy ones) or when
-             * in the full Android build system.
-             */
-            int64_t pixels  = get_screen_pixels(skinConfig);
-
-            /* The following thresholds are a bit liberal, but we
-             * essentially want to ensure the following mappings:
-             *
-             *   320x480 -> 96
-             *   800x600 -> 128
-             *  1024x768 -> 256
-             *
-             * These are just simple heuristics, they could change in
-             * the future.
-             */
-            if (pixels <= 250000)
-                ramSize = 96;
-            else if (pixels <= 500000)
-                ramSize = 128;
-            else
-                ramSize = 256;
-        }
-        bufprint(tmp, tmpend, "%d", ramSize);
-        opts->memory = android_strdup(tmp);
-    }
-
-    if (opts->trace) {
-        args[n++] = "-trace";
-        args[n++] = opts->trace;
-        args[n++] = "-tracing";
-        args[n++] = "off";
-    }
-
-    /* Pass LCD density value to the core. */
-    snprintf(lcd_density, sizeof(lcd_density), "%d", hw->hw_lcd_density);
-    args[n++] = "-lcd-density";
-    args[n++] = lcd_density;
-
-    /* Pass boot properties to the core. */
-    if (opts->prop != NULL) {
-        ParamList*  pl = opts->prop;
-        for ( ; pl != NULL; pl = pl->next ) {
-            args[n++] = "-boot-property";
-            args[n++] = pl->param;
-        }
-    }
-
-    args[n++] = "-append";
-
-    if (opts->bootchart) {
-        char*  end;
-        int    timeout = strtol(opts->bootchart, &end, 10);
-        if (timeout == 0)
-            opts->bootchart = NULL;
-        else if (timeout < 0 || timeout > 15*60) {
-            derror( "timeout specified for -bootchart option is invalid.\n"
-                    "please use integers between 1 and 900\n");
-            exit(1);
-        }
-    }
-
-    /* Setup the kernel init options
-     */
-    {
-        static char  params[1024];
-        char        *p = params, *end = p + sizeof(params);
-
-        p = bufprint(p, end, "qemu=1 console=ttyS0" );
-
-        if (opts->shell || opts->logcat) {
-            p = bufprint(p, end, " androidboot.console=ttyS%d", shell_serial );
-        }
-
-        if (opts->trace) {
-            p = bufprint(p, end, " android.tracing=1");
-        }
-
-        if (!opts->no_jni) {
-            p = bufprint(p, end, " android.checkjni=1");
-        }
-
-        if (opts->no_boot_anim) {
-            p = bufprint( p, end, " android.bootanim=0" );
-        }
-
-        if (opts->logcat) {
-            char*  q = bufprint(p, end, " androidboot.logcat=%s", opts->logcat);
-
-            if (q < end) {
-                /* replace any space by a comma ! */
-                {
-                    int  nn;
-                    for (nn = 1; p[nn] != 0; nn++)
-                        if (p[nn] == ' ' || p[nn] == '\t')
-                            p[nn] = ',';
-                    p += nn;
-                }
-            }
-            p = q;
-        }
-
-        if (opts->old_system)
-        {
-            p = bufprint(p, end, " android.ril=ttyS%d", radio_serial);
-
-            if (opts->gps) {
-                p = bufprint(p, end, " android.gps=ttyS%d", gps_serial);
-            }
-        }
-        else
-        {
-            p = bufprint(p, end, " android.qemud=ttyS%d", qemud_serial);
-        }
-
-        if (opts->bootchart) {
-            p = bufprint(p, end, " androidboot.bootchart=%s", opts->bootchart);
-        }
-
-        if (p >= end) {
-            fprintf(stderr, "### ERROR: kernel parameters too long\n");
-            exit(1);
-        }
-
-        args[n++] = strdup(params);
-    }
-
-    if (opts->ports) {
-        args[n++] = "-android-ports";
-        args[n++] = opts->ports;
-    }
-
-    if (opts->port) {
-        args[n++] = "-android-port";
-        args[n++] = opts->port;
-    }
-
-    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) {
-        args[n++] = "-charmap";
-        args[n++] = opts->charmap;
-    }
-
-    if (opts->memcheck) {
-        args[n++] = "-android-memcheck";
-        args[n++] = opts->memcheck;
-    }
-
-    /* physical memory */
-    args[n++] = "-m";
-    args[n++] = opts->memory;
-
-    /* on Linux, the 'dynticks' clock sometimes doesn't work
-     * properly. this results in the UI freezing while emulation
-     * continues, for several seconds...
-     */
-#ifdef __linux__
-    args[n++] = "-clock";
-    args[n++] = "unix";
-#endif
-
-    args[n++] = "-android-avdname";
-    args[n++] = avdInfo_getName(avd);
-
-    /* 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";
-    }
-
-    while(argc-- > 0) {
-        args[n++] = *argv++;
-    }
-    args[n] = 0;
-
-    /* Generate a temporary hardware.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 temp file will group all definitions and will be used to
-     * launch the core with the -android-hw <file> option.
-     */
-    {
-        TempFile*  tempHw = tempfile_create();
-        if (tempHw == NULL) {
-            derror("Could not create temporary hardware.ini: %s", strerror(errno));
-            exit(2);
-        }
-
-        const char* tempHwPath = tempfile_path(tempHw);
-        IniFile*    hwIni      = iniFile_newFromMemory("", NULL);
-        androidHwConfig_write(hw, hwIni);
-        if (iniFile_saveToFile(hwIni, tempHwPath) < 0) {
-            derror("Could not write temporary hardware.ini: %s", tempHwPath);
-            exit(2);
-        }
-        args[n++] = "-android-hw";
-        args[n++] = strdup(tempHwPath);
-    }
-
-    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++) {
-            printf(" %s", args[i]);
-        }
-        printf("\n");
-    }
-
-    /* Setup SDL UI just before calling the code */
-    init_sdl_ui(skinConfig, skinPath, opts);
-
-    // Lets see if we're attaching to a running core process here.
-    if (opts->attach_core) {
-        if (attach_to_core(opts)) {
-            return -1;
-        }
-        // Connect to the core's UI control services.
-        if (coreCmdProxy_create(attachUiImpl_get_console_socket())) {
-            return -1;
-        }
-        // Connect to the core's user events service.
-        if (userEventsProxy_create(attachUiImpl_get_console_socket())) {
-            return -1;
-        }
-    }
-
-    return qemu_main(n, args);
-}
diff --git a/android/main.c b/android/main.c
index 51ef6d7..7b6ea03 100644
--- a/android/main.c
+++ b/android/main.c
@@ -38,7 +38,7 @@
 
 #include "android/user-config.h"
 #include "android/utils/bufprint.h"
-#include "android/utils/dirscanner.h"
+#include "android/utils/filelock.h"
 #include "android/utils/path.h"
 #include "android/utils/tempfile.h"
 
@@ -56,11 +56,6 @@
 #include "android/framebuffer.h"
 #include "iolooper.h"
 
-#ifdef TARGET_I386
-nand_threshold android_nand_read_threshold;
-nand_threshold android_nand_write_threshold;
-#endif
-
 AndroidRotation  android_framebuffer_rotation;
 
 #define  STRINGIFY(x)   _STRINGIFY(x)
@@ -82,10 +77,6 @@
  */
 #define  DEFAULT_DEVICE_DPI  165
 
-#if 0
-static int  opts->flashkeys;      /* forward */
-#endif
-
 #ifdef CONFIG_TRACE
 extern void  start_tracing(void);
 extern void  stop_tracing(void);
@@ -117,128 +108,21 @@
     exit(1);
 }
 
-/* this function is used to perform auto-detection of the
- * system directory in the case of a SDK installation.
- *
- * we want to deal with several historical usages, hence
- * the slightly complicated logic.
- *
- * NOTE: the function returns the path to the directory
- *       containing 'fileName'. this is *not* the full
- *       path to 'fileName'.
- */
+/* TODO: Put in shared source file */
 static char*
-_getSdkImagePath( const char*  fileName )
+_getFullFilePath( const char* rootPath, const char* fileName )
 {
-    char   temp[MAX_PATH];
-    char*  p   = temp;
-    char*  end = p + sizeof(temp);
-    char*  q;
-    char*  app;
+    if (path_is_absolute(fileName)) {
+        return ASTRDUP(fileName);
+    } else {
+        char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
 
-    static const char* const  searchPaths[] = {
-        "",                                  /* program's directory */
-        "/lib/images",                       /* this is for SDK 1.0 */
-        "/../platforms/android-1.1/images",  /* this is for SDK 1.1 */
-        NULL
-    };
-
-    app = bufprint_app_dir(temp, end);
-    if (app >= end)
-        return NULL;
-
-    do {
-        int  nn;
-
-        /* first search a few well-known paths */
-        for (nn = 0; searchPaths[nn] != NULL; nn++) {
-            p = bufprint(app, end, "%s", searchPaths[nn]);
-            q = bufprint(p, end, "/%s", fileName);
-            if (q < end && path_exists(temp)) {
-                *p = 0;
-                goto FOUND_IT;
-            }
+        p = bufprint(temp, end, "%s/%s", rootPath, fileName);
+        if (p >= end) {
+            return NULL;
         }
-
-        /* hmmm. let's assume that we are in a post-1.1 SDK
-         * scan ../platforms if it exists
-         */
-        p = bufprint(app, end, "/../platforms");
-        if (p < end) {
-            DirScanner*  scanner = dirScanner_new(temp);
-            if (scanner != NULL) {
-                int          found = 0;
-                const char*  subdir;
-
-                for (;;) {
-                    subdir = dirScanner_next(scanner);
-                    if (!subdir) break;
-
-                    q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
-                    if (q >= end || !path_exists(temp))
-                        continue;
-
-                    found = 1;
-                    p = bufprint(p, end, "/%s/images", subdir);
-                    break;
-                }
-                dirScanner_free(scanner);
-                if (found)
-                    break;
-            }
-        }
-
-        /* I'm out of ideas */
-        return NULL;
-
-    } while (0);
-
-FOUND_IT:
-    //D("image auto-detection: %s/%s", temp, fileName);
-    return android_strdup(temp);
-}
-
-static char*
-_getSdkImage( const char*  path, const char*  file )
-{
-    char  temp[MAX_PATH];
-    char  *p = temp, *end = p + sizeof(temp);
-
-    p = bufprint(temp, end, "%s/%s", path, file);
-    if (p >= end || !path_exists(temp))
-        return NULL;
-
-    return android_strdup(temp);
-}
-
-static char*
-_getSdkSystemImage( const char*  path, const char*  optionName, const char*  file )
-{
-    char*  image = _getSdkImage(path, file);
-
-    if (image == NULL) {
-        derror("Your system directory is missing the '%s' image file.\n"
-               "Please specify one with the '%s <filepath>' option",
-               file, optionName);
-        exit(2);
+        return ASTRDUP(temp);
     }
-    return image;
-}
-
-static void
-_forceAvdImagePath( AvdImageType  imageType,
-                   const char*   path,
-                   const char*   description,
-                   int           required )
-{
-    if (path == NULL)
-        return;
-
-    if (required && !path_exists(path)) {
-        derror("Cannot find %s image file: %s", description, path);
-        exit(1);
-    }
-    android_avdParams->forcePaths[imageType] = path;
 }
 
 static uint64_t
@@ -277,29 +161,21 @@
     char*  args[128];
     int    n;
     char*  opt;
-    int    use_sdcard_img = 0;
-    int    serial = 0;
-    int    gps_serial = 0;
-    int    radio_serial = 0;
-    int    qemud_serial = 0;
+    /* 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'
+     */
+    int    serial = 2;
     int    shell_serial = 0;
-    unsigned  cachePartitionSize = 0;
-    unsigned  systemPartitionSize = 0;
-    unsigned  dataPartitionSize = 0;
-    unsigned  defaultPartitionSize = convertMBToBytes(66);
 
     AndroidHwConfig*  hw;
     AvdInfo*          avd;
     AConfig*          skinConfig;
     char*             skinPath;
-
-    //const char *appdir = get_app_dir();
-    char*       android_build_root = NULL;
-    char*       android_build_out  = NULL;
+    int               inAndroidBuild;
+    uint64_t          defaultPartitionSize = convertMBToBytes(66);
 
     AndroidOptions  opts[1];
-    /* LCD density value to pass to the core. */
-    char lcd_density[16];
     /* net.shared_net_ip boot property value. */
     char boot_prop_ip[64];
     boot_prop_ip[0] = '\0';
@@ -310,6 +186,12 @@
         exit(1);
     }
 
+#ifdef _WIN32
+    socket_init();
+#endif
+
+    handle_ui_options(opts);
+
     while (argc-- > 1) {
         opt = (++argv)[0];
 
@@ -360,7 +242,7 @@
 
     if (opts->version) {
         printf("Android emulator version %s\n"
-               "Copyright (C) 2006-2008 The Android Open Source Project and many others.\n"
+               "Copyright (C) 2006-2011 The Android Open Source Project and many others.\n"
                "This program is a derivative of the QEMU CPU emulator (www.qemu.org).\n\n",
 #if defined ANDROID_BUILD_ID
                VERSION_STRING " (build_id " STRINGIFY(ANDROID_BUILD_ID) ")" );
@@ -378,249 +260,46 @@
         exit(0);
     }
 
+    if (opts->snapshot_list) {
+        snapshot_print_and_exit(opts->snapstorage);
+    }
+
+    sanitizeOptions(opts);
+
+    /* Initialization of UI started with -attach-core should work differently
+     * than initialization of UI that starts the core. In particular....
+     */
+
+    /* -charmap is incompatible with -attach-core, because particular
+     * charmap gets set up in the running core. */
     if (android_charmap_setup(opts->charmap)) {
         exit(1);
     }
 
-    /* legacy support: we used to use -system <dir> and -image <file>
-     * instead of -sysdir <dir> and -system <file>, so handle this by checking
-     * whether the options point to directories or files.
-     */
-    if (opts->image != NULL) {
-        if (opts->system != NULL) {
-            if (opts->sysdir != NULL) {
-                derror( "You can't use -sysdir, -system and -image at the same time.\n"
-                        "You should probably use '-sysdir <path> -system <file>'.\n" );
-                exit(2);
-            }
-        }
-        dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
-                  "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
-        opts->sysdir = opts->system;
-        opts->system = opts->image;
-        opts->image  = NULL;
-    }
-    else if (opts->system != NULL && path_is_dir(opts->system)) {
-        if (opts->sysdir != NULL) {
-            derror( "Option -system should now be followed by a file path, not a directory one.\n"
-                    "Please use '-sysdir <path>' to point to the system directory.\n" );
-            exit(1);
-        }
-        dwarning( "Please note that the -system option should now be used to point to the initial\n"
-                  "system image (like the obsolete -image option). To point to the system directory\n"
-                  "please now use '-sysdir <path>' instead.\n" );
-
-        opts->sysdir = opts->system;
-        opts->system = NULL;
-    }
-
-    if (opts->nojni)
-        opts->no_jni = opts->nojni;
-
-    if (opts->nocache)
-        opts->no_cache = opts->nocache;
-
-    if (opts->noaudio)
-        opts->no_audio = opts->noaudio;
-
-    if (opts->noskin)
-        opts->no_skin = opts->noskin;
-
-    /* If no AVD name was given, try to find the top of the
-     * Android build tree
-     */
-    if (opts->avd == NULL) {
-        do {
-            char*  out = getenv("ANDROID_PRODUCT_OUT");
-
-            if (out == NULL || out[0] == 0)
-                break;
-
-            if (!path_exists(out)) {
-                derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
-                    "You need to build the Android system before launching the emulator",
-                    out);
-                exit(2);
-            }
-
-            android_build_root = path_parent( out, 4 );
-            if (android_build_root == NULL || !path_exists(android_build_root)) {
-                derror("Can't find the Android build root from '%s'\n"
-                    "Please check the definition of the ANDROID_PRODUCT_OUT variable.\n"
-                    "It should point to your product-specific build output directory.\n",
-                    out );
-                exit(2);
-            }
-            android_build_out = out;
-            D( "found Android build root: %s", android_build_root );
-            D( "found Android build out:  %s", android_build_out );
-        } while (0);
-    }
-    /* if no virtual device name is given, and we're not in the
-     * Android build system, we'll need to perform some auto-detection
-     * magic :-)
-     */
-    if (opts->avd == NULL && !android_build_out)
-    {
-        char   dataDirIsSystem = 0;
-
-        if (!opts->sysdir) {
-            opts->sysdir = _getSdkImagePath("system.img");
-            if (!opts->sysdir) {
-                derror(
-                "You did not specify a virtual device name, and the system\n"
-                "directory could not be found.\n\n"
-                "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
-                "to start a given virtual device (see -help-avd for details).\n\n"
-
-                "Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
-                );
-                exit(2);
-            }
-            D("autoconfig: -sysdir %s", opts->sysdir);
-        }
-
-        if (!opts->system) {
-            opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
-            D("autoconfig: -image %s", opts->image);
-        }
-
-        if (!opts->kernel) {
-            opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
-            D("autoconfig: -kernel %s", opts->kernel);
-        }
-
-        if (!opts->ramdisk) {
-            opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
-            D("autoconfig: -ramdisk %s", opts->ramdisk);
-        }
-
-        /* if no data directory is specified, use the system directory */
-        if (!opts->datadir) {
-            opts->datadir   = android_strdup(opts->sysdir);
-            dataDirIsSystem = 1;
-            D("autoconfig: -datadir %s", opts->sysdir);
-        }
-
-        if (!opts->data) {
-            /* check for userdata-qemu.img in the data directory */
-            bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
-            if (!path_exists(tmp)) {
-                derror(
-                "You did not provide the name of an Android Virtual Device\n"
-                "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
-
-                "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
-                "to specify a data partition image file (I hope you know what you're doing).\n"
-                );
-                exit(2);
-            }
-
-            opts->data = android_strdup(tmp);
-            D("autoconfig: -data %s", opts->data);
-        }
-
-        if (!opts->sdcard && opts->datadir) {
-            bufprint(tmp, tmpend, "%s/sdcard.img", opts->datadir);
-            if (path_exists(tmp)) {
-                opts->sdcard = android_strdup(tmp);
-                D("autoconfig: -sdcard %s", opts->sdcard);
-            }
-        }
-
-#if CONFIG_ANDROID_SNAPSHOTS
-        if (!opts->snapstorage && opts->datadir) {
-            bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir);
-            if (path_exists(tmp)) {
-                opts->snapstorage = android_strdup(tmp);
-                D("autoconfig: -snapstorage %s", opts->snapstorage);
-            }
-        }
-#endif // CONFIG_ANDROID_SNAPSHOTS
-    }
-
-    /* setup the virtual device parameters from our options
-     */
-    if (opts->no_cache) {
-        android_avdParams->flags |= AVDINFO_NO_CACHE;
-    }
-    if (opts->wipe_data) {
-        android_avdParams->flags |= AVDINFO_WIPE_DATA | AVDINFO_WIPE_CACHE;
-    }
-#if CONFIG_ANDROID_SNAPSHOTS
-    if (opts->no_snapstorage) {
-        android_avdParams->flags |= AVDINFO_NO_SNAPSHOTS;
-    }
-#endif
-
-    /* if certain options are set, we can force the path of
-        * certain kernel/disk image files
-        */
-    _forceAvdImagePath(AVD_IMAGE_KERNEL,     opts->kernel,      "kernel", 1);
-    _forceAvdImagePath(AVD_IMAGE_INITSYSTEM, opts->system,      "system", 1);
-    _forceAvdImagePath(AVD_IMAGE_RAMDISK,    opts->ramdisk,     "ramdisk", 1);
-    _forceAvdImagePath(AVD_IMAGE_USERDATA,   opts->data,        "user data", 0);
-    _forceAvdImagePath(AVD_IMAGE_CACHE,      opts->cache,       "cache", 0);
-    _forceAvdImagePath(AVD_IMAGE_SDCARD,     opts->sdcard,      "SD Card", 0);
-#if CONFIG_ANDROID_SNAPSHOTS
-    _forceAvdImagePath(AVD_IMAGE_SNAPSHOTS,  opts->snapstorage, "snapshots", 0);
-#endif
-
-    /* we don't accept -skindir without -skin now
-     * to simplify the autoconfig stuff with virtual devices
-     */
-    if (opts->no_skin) {
-        opts->skin    = "320x480";
-        opts->skindir = NULL;
-    }
-
-    if (opts->skindir) {
-        if (!opts->skin) {
-            derror( "the -skindir <path> option requires a -skin <name> option");
-            exit(1);
-        }
-    }
-    android_avdParams->skinName     = opts->skin;
-    android_avdParams->skinRootPath = opts->skindir;
-
-    /* setup the virtual device differently depending on whether
-     * we are in the Android build system or not
-     */
-    if (opts->avd != NULL)
-    {
-        android_avdInfo = avdInfo_new( opts->avd, android_avdParams );
-        if (android_avdInfo == NULL) {
-            /* an error message has already been printed */
-            dprint("could not find virtual device named '%s'", opts->avd);
-            exit(1);
-        }
-    }
-    else
-    {
-        if (!android_build_out) {
-            android_build_out = android_build_root = opts->sysdir;
-        }
-        android_avdInfo = avdInfo_newForAndroidBuild(
-                            android_build_root,
-                            android_build_out,
-                            android_avdParams );
-
-        if(android_avdInfo == NULL) {
-            D("could not start virtual device\n");
-            exit(1);
-        }
-    }
-
-    avd = android_avdInfo;
+    /* Parses options and builds an appropriate AVD. */
+    avd = android_avdInfo = createAVD(opts, &inAndroidBuild);
 
     /* get the skin from the virtual device configuration */
-    opts->skin    = (char*) avdInfo_getSkinName( avd );
-    opts->skindir = (char*) avdInfo_getSkinDir( avd );
+    if (opts->skindir != NULL) {
+        if (opts->skin == NULL) {
+            /* NOTE: Normally handled by sanitizeOptions(), just be safe */
+            derror("The -skindir <path> option requires a -skin <name> option");
+            exit(2);
+        }
+    } else {
+        char* skinName;
+        char* skinDir;
 
-    if (opts->skin) {
-        D("autoconfig: -skin %s", opts->skin);
-    }
-    if (opts->skindir) {
+        avdInfo_getSkinInfo(avd, &skinName, &skinDir);
+
+        if (opts->skin == NULL) {
+            opts->skin = skinName;
+            D("autoconfig: -skin %s", opts->skin);
+        } else {
+            AFREE(skinName);
+        }
+
+        opts->skindir = skinDir;
         D("autoconfig: -skindir %s", opts->skindir);
     }
 
@@ -667,18 +346,20 @@
 
 
     user_config_init();
-    parse_skin_files(opts->skindir, opts->skin, opts,
+    parse_skin_files(opts->skindir, opts->skin, opts, hw,
                      &skinConfig, &skinPath);
 
-    if (!opts->netspeed) {
-        if (skin_network_speed)
-            D("skin network speed: '%s'", skin_network_speed);
-        opts->netspeed = (char*)skin_network_speed;
+    if (!opts->netspeed && skin_network_speed) {
+        D("skin network speed: '%s'", skin_network_speed);
+        if (strcmp(skin_network_speed, NETWORK_SPEED_DEFAULT) != 0) {
+            opts->netspeed = (char*)skin_network_speed;
+        }
     }
-    if (!opts->netdelay) {
-        if (skin_network_delay)
-            D("skin network delay: '%s'", skin_network_delay);
-        opts->netdelay = (char*)skin_network_delay;
+    if (!opts->netdelay && skin_network_delay) {
+        D("skin network delay: '%s'", skin_network_delay);
+        if (strcmp(skin_network_delay, NETWORK_DELAY_DEFAULT) != 0) {
+            opts->netdelay = (char*)skin_network_delay;
+        }
     }
 
     if (opts->trace) {
@@ -697,17 +378,26 @@
         opts->trace = tracePath;
     }
 
-    if (opts->no_cache)
-        opts->cache = 0;
-
     n = 1;
     /* generate arguments for the underlying qemu main() */
     {
-        const char*  kernelFile    = avdInfo_getImageFile(avd, AVD_IMAGE_KERNEL);
-        int          kernelFileLen = strlen(kernelFile);
+        char*  kernelFile    = opts->kernel;
+        int    kernelFileLen;
 
-        args[n++] = "-kernel";
-        args[n++] = (char*)kernelFile;
+        if (kernelFile == NULL) {
+            kernelFile = avdInfo_getKernelPath(avd);
+            if (kernelFile == NULL) {
+                derror( "This AVD's configuration is missing a kernel file!!" );
+                exit(2);
+            }
+            D("autoconfig: -kernel %s", kernelFile);
+        }
+        if (!path_exists(kernelFile)) {
+            derror( "Invalid or missing kernel image file: %s", kernelFile );
+            exit(2);
+        }
+
+        hw->kernel_path = kernelFile;
 
         /* If the kernel image name ends in "-armv7", then change the cpu
          * type automatically. This is a poor man's approach to configuration
@@ -722,6 +412,7 @@
          * some build system changes. I prefer not to do that for now for reasons
          * of simplicity.
          */
+         kernelFileLen = strlen(kernelFile);
          if (kernelFileLen > 6 && !memcmp(kernelFile + kernelFileLen - 6, "-armv7", 6)) {
             args[n++] = "-cpu";
             args[n++] = "cortex-a8";
@@ -762,11 +453,6 @@
         args[n++] = "-netfast";
     }
 
-    /* the purpose of -no-audio is to disable sound output from the emulator,
-     * not to disable Audio emulation. So simply force the 'none' backends */
-    if (opts->no_audio)
-        opts->audio = "none";
-
     if (opts->audio) {
         args[n++] = "-audio";
         args[n++] = opts->audio;
@@ -782,9 +468,12 @@
         args[n++] = opts->dns_server;
     }
 
-    args[n++] = "-initrd";
-    args[n++] = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_RAMDISK);
+    hw->disk_ramdisk_path = avdInfo_getRamdiskPath(avd);
+    D("autoconfig: -ramdisk %s", hw->disk_ramdisk_path);
 
+    /* -partition-size is used to specify the max size of both the system
+     * and data partition sizes.
+     */
     if (opts->partition_size) {
         char*  end;
         long   sizeMB = strtol(opts->partition_size, &end, 0);
@@ -800,105 +489,233 @@
                     sizeMB, minSizeMB, maxSizeMB );
             exit(1);
         }
-        defaultPartitionSize = sizeMB * ONE_MB;
+        defaultPartitionSize = (uint64_t) sizeMB * ONE_MB;
     }
 
-    /* Check the size of the system partition image.
-     * If we have an AVD, it must be smaller than
-     * the disk.systemPartition.size hardware property.
-     *
-     * Otherwise, we need to adjust the systemPartitionSize
-     * automatically, and print a warning.
-     *
-     */
-    {
-        uint64_t   systemBytes  = avdInfo_getImageFileSize(avd, AVD_IMAGE_INITSYSTEM);
-        uint64_t   defaultBytes = defaultPartitionSize;
 
-        if (defaultBytes == 0 || opts->partition_size)
-            defaultBytes = defaultPartitionSize;
+    /** SYSTEM PARTITION **/
 
-        systemPartitionSize = _adjustPartitionSize("system", systemBytes, defaultBytes,
-                                                   android_build_out != NULL);
+    if (opts->sysdir == NULL) {
+        if (avdInfo_inAndroidBuild(avd)) {
+            opts->sysdir = ASTRDUP(avdInfo_getContentPath(avd));
+            D("autoconfig: -sysdir %s", opts->sysdir);
+        }
     }
 
-    /* Check the size of the /data partition. The only interesting cases here are:
-     * - when the USERDATA image already exists and is larger than the default
-     * - when we're wiping data and the INITDATA is larger than the default.
-     */
+    if (opts->sysdir != NULL) {
+        if (!path_exists(opts->sysdir)) {
+            derror("Directory does not exist: %s", opts->sysdir);
+            exit(1);
+        }
+    }
 
     {
-        const char*  dataPath     = avdInfo_getImageFile(avd, AVD_IMAGE_USERDATA);
+        char*  rwImage   = NULL;
+        char*  initImage = NULL;
+
+        do {
+            if (opts->system == NULL) {
+                /* If -system is not used, try to find a runtime system image
+                * (i.e. system-qemu.img) in the content directory.
+                */
+                rwImage = avdInfo_getSystemImagePath(avd);
+                if (rwImage != NULL) {
+                    break;
+                }
+                /* Otherwise, try to find the initial system image */
+                initImage = avdInfo_getSystemInitImagePath(avd);
+                if (initImage == NULL) {
+                    derror("No initial system image for this configuration!");
+                    exit(1);
+                }
+                break;
+            }
+
+            /* If -system <name> is used, use it to find the initial image */
+            if (opts->sysdir != NULL) {
+                initImage = _getFullFilePath(opts->sysdir, opts->system);
+            } else {
+                initImage = ASTRDUP(opts->system);
+            }
+            if (!path_exists(initImage)) {
+                derror("System image file doesn't exist: %s", initImage);
+                exit(1);
+            }
+
+        } while (0);
+
+        if (rwImage != NULL) {
+            /* Use the read/write image file directly */
+            hw->disk_systemPartition_path     = rwImage;
+            hw->disk_systemPartition_initPath = NULL;
+            D("Using direct system image: %s", rwImage);
+        } else if (initImage != NULL) {
+            hw->disk_systemPartition_path = NULL;
+            hw->disk_systemPartition_initPath = initImage;
+            D("Using initial system image: %s", initImage);
+        }
+
+        /* Check the size of the system partition image.
+        * If we have an AVD, it must be smaller than
+        * the disk.systemPartition.size hardware property.
+        *
+        * Otherwise, we need to adjust the systemPartitionSize
+        * automatically, and print a warning.
+        *
+        */
+        const char* systemImage = hw->disk_systemPartition_path;
+        uint64_t    systemBytes;
+
+        if (systemImage == NULL)
+            systemImage = hw->disk_systemPartition_initPath;
+
+        if (path_get_size(systemImage, &systemBytes) < 0) {
+            derror("Missing system image: %s", systemImage);
+            exit(1);
+        }
+
+        hw->disk_systemPartition_size =
+            _adjustPartitionSize("system", systemBytes, defaultPartitionSize,
+                                 avdInfo_inAndroidBuild(avd));
+    }
+
+    /** DATA PARTITION **/
+
+    if (opts->datadir) {
+        if (!path_exists(opts->datadir)) {
+            derror("Invalid -datadir directory: %s", opts->datadir);
+        }
+    }
+
+    {
+        char*  dataImage = NULL;
+        char*  initImage = NULL;
+
+        do {
+            if (!opts->data) {
+                dataImage = avdInfo_getDataImagePath(avd);
+                if (dataImage != NULL) {
+                    D("autoconfig: -data %s", dataImage);
+                    break;
+                }
+                dataImage = avdInfo_getDefaultDataImagePath(avd);
+                if (dataImage == NULL) {
+                    derror("No data image path for this configuration!");
+                    exit (1);
+                }
+                opts->wipe_data = 1;
+                break;
+            }
+
+            if (opts->datadir) {
+                dataImage = _getFullFilePath(opts->datadir, opts->data);
+            } else {
+                dataImage = ASTRDUP(opts->data);
+            }
+        } while (0);
+
+        if (opts->initdata != NULL) {
+            initImage = ASTRDUP(opts->initdata);
+            if (!path_exists(initImage)) {
+                derror("Invalid initial data image path: %s", initImage);
+                exit(1);
+            }
+        } else {
+            initImage = avdInfo_getDataInitImagePath(avd);
+            D("autoconfig: -initdata %s", initImage);
+        }
+
+        hw->disk_dataPartition_path = dataImage;
+        if (opts->wipe_data) {
+            hw->disk_dataPartition_initPath = initImage;
+        } else {
+            hw->disk_dataPartition_initPath = NULL;
+        }
+
         uint64_t     defaultBytes = defaultPartitionSize;
+        uint64_t     dataBytes;
+        const char*  dataPath = hw->disk_dataPartition_initPath;
 
-        if (defaultBytes == 0 || opts->partition_size)
-            defaultBytes = defaultPartitionSize;
+        if (dataPath == NULL)
+            dataPath = hw->disk_dataPartition_path;
 
-        if (dataPath == NULL || !path_exists(dataPath) || opts->wipe_data) {
-            dataPath = avdInfo_getImageFile(avd, AVD_IMAGE_INITDATA);
-        }
-        if (dataPath == NULL || !path_exists(dataPath)) {
-            dataPartitionSize = defaultBytes;
-        }
-        else {
-            uint64_t  dataBytes;
-            path_get_size(dataPath, &dataBytes);
+        path_get_size(dataPath, &dataBytes);
 
-            dataPartitionSize = _adjustPartitionSize("data", dataBytes, defaultBytes,
-                                                     android_build_out != NULL);
-        }
+        hw->disk_dataPartition_size =
+            _adjustPartitionSize("data", dataBytes, defaultBytes,
+                                 avdInfo_inAndroidBuild(avd));
     }
 
+    /** CACHE PARTITION **/
+
+    if (opts->no_cache) {
+        /* No cache partition at all */
+        hw->disk_cachePartition = 0;
+    }
+    else if (!hw->disk_cachePartition) {
+        if (opts->cache) {
+            dwarning( "Emulated hardware doesn't support a cache partition. -cache option ignored!" );
+            opts->cache = NULL;
+        }
+    }
+    else
     {
-        const char*  filetype = "file";
+        if (!opts->cache) {
+            /* Find the current cache partition file */
+            opts->cache = avdInfo_getCachePath(avd);
+            if (opts->cache == NULL) {
+                /* The file does not exists, we will force its creation
+                 * if we are not in the Android build system. Otherwise,
+                 * a temporary file will be used.
+                 */
+                if (!avdInfo_inAndroidBuild(avd)) {
+                    opts->cache = avdInfo_getDefaultCachePath(avd);
+                }
+            }
+            if (opts->cache) {
+                D("autoconfig: -cache %s", opts->cache);
+            }
+        }
 
-        if (avdInfo_isImageReadOnly(avd, AVD_IMAGE_INITSYSTEM))
-            filetype = "initfile";
-
-        bufprint(tmp, tmpend,
-             "system,size=0x%x,%s=%s", systemPartitionSize, filetype,
-             avdInfo_getImageFile(avd, AVD_IMAGE_INITSYSTEM));
-
-        args[n++] = "-nand";
-        args[n++] = strdup(tmp);
+        if (opts->cache) {
+            hw->disk_cachePartition_path = ASTRDUP(opts->cache);
+        }
     }
 
-    bufprint(tmp, tmpend,
-             "userdata,size=0x%x,file=%s",
-             dataPartitionSize,
-             avdInfo_getImageFile(avd, AVD_IMAGE_USERDATA));
+    /** SD CARD PARTITION */
 
-    args[n++] = "-nand";
-    args[n++] = strdup(tmp);
+    if (!hw->hw_sdCard) {
+        /* No SD Card emulation, so -sdcard will be ignored */
+        if (opts->sdcard) {
+            dwarning( "Emulated hardware doesn't support SD Cards. -sdcard option ignored." );
+            opts->sdcard = NULL;
+        }
+    } else {
+        /* Auto-configure -sdcard if it is not available */
+        if (!opts->sdcard) {
+            do {
+                /* If -datadir <path> is used, look for a sdcard.img file here */
+                if (opts->datadir) {
+                    bufprint(tmp, tmpend, "%s/%s", opts->datadir, "system.img");
+                    if (path_exists(tmp)) {
+                        opts->sdcard = strdup(tmp);
+                        break;
+                    }
+                }
 
-    if (hw->disk_cachePartition) {
-        opts->cache = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_CACHE);
-        cachePartitionSize = hw->disk_cachePartition_size;
-    }
-    else if (opts->cache) {
-        dwarning( "Emulated hardware doesn't support a cache partition" );
-        opts->cache    = NULL;
-        opts->no_cache = 1;
-    }
+                /* Otherwise, look at the AVD's content */
+                opts->sdcard = avdInfo_getSdCardPath(avd);
+                if (opts->sdcard != NULL) {
+                    break;
+                }
 
-    if (opts->cache) {
-        /* use a specific cache file */
-        sprintf(tmp, "cache,size=0x%0x,file=%s", cachePartitionSize, opts->cache);
-        args[n++] = "-nand";
-        args[n++] = strdup(tmp);
-    }
-    else if (!opts->no_cache) {
-        /* create a temporary cache partition file */
-        sprintf(tmp, "cache,size=0x%0x", cachePartitionSize);
-        args[n++] = "-nand";
-        args[n++] = strdup(tmp);
-    }
+                /* Nothing */
+            } while (0);
 
-    if (hw->hw_sdCard != 0)
-        opts->sdcard = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_SDCARD);
-    else if (opts->sdcard) {
-        dwarning( "Emulated hardware doesn't support SD Cards" );
-        opts->sdcard = NULL;
+            if (opts->sdcard) {
+                D("autoconfig: -sdcard %s", opts->sdcard);
+            }
+        }
     }
 
     if(opts->sdcard) {
@@ -911,80 +728,102 @@
             if (size < 9*1024*1024ULL) {
                 fprintf(stderr, "### WARNING: SD Card files must be at least 9MB, ignoring '%s'\n", opts->sdcard);
             } else {
-                args[n++] = "-hda";
-                args[n++] = opts->sdcard;
-                use_sdcard_img = 1;
+                hw->hw_sdCard_path = ASTRDUP(opts->sdcard);
             }
         } else {
-            D("no SD Card image at '%s'", opts->sdcard);
+            dwarning("no SD Card image at '%s'", opts->sdcard);
         }
     }
 
-#if CONFIG_ANDROID_SNAPSHOTS
-    if (!opts->no_snapstorage) {
-        opts->snapstorage = (char*) avdInfo_getImageFile(avd, AVD_IMAGE_SNAPSHOTS);
-        if(opts->snapstorage) {
-            if (path_exists(opts->snapstorage)) {
-                args[n++] = "-hdb";
-                args[n++] = opts->snapstorage;
-            } else {
-                D("no image at '%s', state snapshots disabled", opts->snapstorage);
+
+    /** SNAPSHOT STORAGE HANDLING */
+
+    /* Determine snapstorage path. -no-snapstorage disables all snapshotting
+     * support. This means you can't resume a snapshot at load, save it at
+     * exit, or even load/save them dynamically at runtime with the console.
+     */
+    if (opts->no_snapstorage) {
+
+        if (opts->snapshot) {
+            dwarning("ignoring -snapshot option due to the use of -no-snapstorage");
+            opts->snapshot = NULL;
+        }
+
+        if (opts->snapstorage) {
+            dwarning("ignoring -snapstorage option due to the use of -no-snapstorage");
+            opts->snapstorage = NULL;
+        }
+    }
+    else
+    {
+        if (!opts->snapstorage) {
+            opts->snapstorage = avdInfo_getSnapStoragePath(avd);
+            if (opts->snapstorage != NULL) {
+                D("autoconfig: -snapstorage %s", opts->snapstorage);
             }
         }
 
-        if (!opts->no_snapshot) {
-            char* snapshot_name =
-                opts->snapshot ? opts->snapshot : "default-boot";
-            if (!opts->no_snapshot_load) {
-              args[n++] = "-loadvm";
-              args[n++] = snapshot_name;
-            }
-            if (!opts->no_snapshot_save) {
-              args[n++] = "-savevm-on-exit";
-              args[n++] = snapshot_name;
-            }
-        } else if (opts->snapshot) {
-            dwarning("option '-no-snapshot' overrides '-snapshot', continuing with boot sequence");
-        } else if (opts->no_snapshot_load || opts->no_snapshot_save) {
-            D("ignoring redundant option(s) '-no-snapshot-load' and/or '-no-snapshot-save' implied by '-no-snapshot'");
+        if (opts->snapstorage && !path_exists(opts->snapstorage)) {
+            D("no image at '%s', state snapshots disabled", opts->snapstorage);
+            opts->snapstorage = NULL;
         }
+    }
+
+    /* If we have a valid snapshot storage path */
+
+    if (opts->snapstorage) {
+
+        hw->disk_snapStorage_path = ASTRDUP(opts->snapstorage);
+
+        /* -no-snapshot is equivalent to using both -no-snapshot-load
+        * and -no-snapshot-save. You can still load/save snapshots dynamically
+        * from the console though.
+        */
+        if (opts->no_snapshot) {
+
+            opts->no_snapshot_load = 1;
+            opts->no_snapshot_save = 1;
+
+            if (opts->snapshot) {
+                dwarning("ignoring -snapshot option due to the use of -no-snapshot.");
+            }
+        }
+
+        if (!opts->no_snapshot_load || !opts->no_snapshot_save) {
+            if (opts->snapshot == NULL) {
+                opts->snapshot = "default-boot";
+                D("autoconfig: -snapshot %s", opts->snapshot);
+            }
+        }
+
+        /* 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) {
-            android_snapshot_update_time = 0;
+            args[n++] = "-snapshot-no-time-update";
         }
-    } else if (opts->snapshot || opts->snapstorage) {
-        dwarning("option '-no-snapstorage' overrides '-snapshot' and '-snapstorage', "
-                 "continuing with full boot, state snapshots are disabled");
-    } else if (opts->no_snapshot) {
-        D("ignoring redundant option '-no-snapshot' implied by '-no-snapstorage'");
     }
 
-    if (opts->snapshot_list) {
-        snapshot_print_and_exit(opts->snapstorage);
-    }
-#endif // CONFIG_ANDROID_SNAPSHOTS
-
     if (!opts->logcat || opts->logcat[0] == 0) {
         opts->logcat = getenv("ANDROID_LOG_TAGS");
         if (opts->logcat && opts->logcat[0] == 0)
             opts->logcat = NULL;
     }
 
-#if 0
-    if (opts->console) {
-        derror( "option -console is obsolete. please use -shell instead" );
-        exit(1);
-    }
-#endif
-
     /* we always send the kernel messages from ttyS0 to android_kmsg */
-    {
-        if (opts->show_kernel) {
-            args[n++] = "-show-kernel";
-        }
-
-        args[n++] = "-serial";
-        args[n++] = "android-kmsg";
-        serial++;
+    if (opts->show_kernel) {
+        args[n++] = "-show-kernel";
     }
 
     /* XXXX: TODO: implement -shell and -logcat through qemud instead */
@@ -1004,39 +843,14 @@
         shell_serial = serial++;
     }
 
-    if (opts->old_system)
-    {
-        if (opts->radio) {
-            args[n++] = "-serial";
-            args[n++] = opts->radio;
-            radio_serial = serial++;
-        }
-        else {
-            args[n++] = "-serial";
-            args[n++] = "android-modem";
-            radio_serial = serial++;
-        }
-        if (opts->gps) {
-            args[n++] = "-serial";
-            args[n++] = opts->gps;
-            gps_serial = serial++;
-        }
+    if (opts->radio) {
+        args[n++] = "-radio";
+        args[n++] = opts->radio;
     }
-    else /* !opts->old_system */
-    {
-        args[n++] = "-serial";
-        args[n++] = "android-qemud";
-        qemud_serial = serial++;
 
-        if (opts->radio) {
-            args[n++] = "-radio";
-            args[n++] = opts->radio;
-        }
-
-        if (opts->gps) {
-            args[n++] = "-gps";
-            args[n++] = opts->gps;
-        }
+    if (opts->gps) {
+        args[n++] = "-gps";
+        args[n++] = opts->gps;
     }
 
     if (opts->memory) {
@@ -1050,6 +864,7 @@
             derror( "physical memory size must be between 32 and 4096 MB" );
             exit(1);
         }
+        hw->hw_ramSize = ramSize;
     }
     if (!opts->memory) {
         int ramSize = hw->hw_ramSize;
@@ -1059,8 +874,7 @@
              * size through its hardware.ini (i.e. legacy ones) or when
              * in the full Android build system.
              */
-            int64_t pixels  = get_screen_pixels(skinConfig);
-
+            int64_t pixels  = hw->hw_lcd_width * hw->hw_lcd_height;
             /* The following thresholds are a bit liberal, but we
              * essentially want to ensure the following mappings:
              *
@@ -1078,8 +892,30 @@
             else
                 ramSize = 256;
         }
-        bufprint(tmp, tmpend, "%d", ramSize);
-        opts->memory = android_strdup(tmp);
+        hw->hw_ramSize = ramSize;
+    }
+
+    D("Physical RAM size: %dMB\n", hw->hw_ramSize);
+
+    if (hw->vm_heapSize == 0) {
+        /* Compute the default heap size based on the RAM size.
+         * Essentially, we want to ensure the following liberal mappings:
+         *
+         *   96MB RAM -> 16MB heap
+         *  128MB RAM -> 24MB heap
+         *  256MB RAM -> 48MB heap
+         */
+        int  ramSize = hw->hw_ramSize;
+        int  heapSize;
+
+        if (ramSize < 100)
+            heapSize = 16;
+        else if (ramSize < 192)
+            heapSize = 24;
+        else
+            heapSize = 48;
+
+        hw->vm_heapSize = heapSize;
     }
 
     if (opts->trace) {
@@ -1089,11 +925,6 @@
         args[n++] = "off";
     }
 
-    /* Pass LCD density value to the core. */
-    snprintf(lcd_density, sizeof(lcd_density), "%d", get_device_dpi(opts));
-    args[n++] = "-lcd-density";
-    args[n++] = lcd_density;
-
     /* Pass boot properties to the core. */
     if (opts->prop != NULL) {
         ParamList*  pl = opts->prop;
@@ -1103,27 +934,15 @@
         }
     }
 
-    args[n++] = "-append";
-
-    if (opts->bootchart) {
-        char*  end;
-        int    timeout = strtol(opts->bootchart, &end, 10);
-        if (timeout == 0)
-            opts->bootchart = NULL;
-        else if (timeout < 0 || timeout > 15*60) {
-            derror( "timeout specified for -bootchart option is invalid.\n"
-                    "please use integers between 1 and 900\n");
-            exit(1);
-        }
-    }
-
     /* Setup the kernel init options
      */
     {
         static char  params[1024];
         char        *p = params, *end = p + sizeof(params);
 
-        p = bufprint(p, end, "qemu=1 console=ttyS0" );
+        /* Don't worry about having a leading space here, this is handled
+         * by the core later. */
+
 #ifdef TARGET_I386
         p = bufprint(p, end, " androidboot.hardware=goldfish");
         p = bufprint(p, end, " clocksource=pit");
@@ -1161,19 +980,6 @@
             p = q;
         }
 
-        if (opts->old_system)
-        {
-            p = bufprint(p, end, " android.ril=ttyS%d", radio_serial);
-
-            if (opts->gps) {
-                p = bufprint(p, end, " android.gps=ttyS%d", gps_serial);
-            }
-        }
-        else
-        {
-            p = bufprint(p, end, " android.qemud=ttyS%d", qemud_serial);
-        }
-
         if (opts->bootchart) {
             p = bufprint(p, end, " androidboot.bootchart=%s", opts->bootchart);
         }
@@ -1183,7 +989,7 @@
             exit(1);
         }
 
-        args[n++] = strdup(params);
+        hw->kernel_parameters = strdup(params);
     }
 
     if (opts->ports) {
@@ -1216,21 +1022,9 @@
         args[n++] = opts->memcheck;
     }
 
-    /* physical memory */
-    args[n++] = "-m";
-    args[n++] = opts->memory;
+    /* physical memory is now in hw->hw_ramSize */
 
-    /* on Linux, the 'dynticks' clock sometimes doesn't work
-     * properly. this results in the UI freezing while emulation
-     * continues, for several seconds...
-     */
-#ifdef __linux__
-    args[n++] = "-clock";
-    args[n++] = "unix";
-#endif
-
-    args[n++] = "-android-avdname";
-    args[n++] = avdInfo_getName(avd);
+    hw->avd_name = ASTRDUP(avdInfo_getName(avd));
 
     /* Set up the interfaces for inter-emulator networking */
     if (opts->shared_net_id) {
@@ -1254,29 +1048,32 @@
     }
     args[n] = 0;
 
-    /* Generate a temporary hardware.ini for this AVD. The real hardware
+    /* 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 temp file will group all definitions and will be used to
+     * The new file will group all definitions and will be used to
      * launch the core with the -android-hw <file> option.
      */
     {
-        TempFile*  tempHw = tempfile_create();
-        if (tempHw == NULL) {
-            derror("Could not create temporary hardware.ini: %s", strerror(errno));
-            exit(2);
+        const char* coreHwIniPath = avdInfo_getCoreHwIniPath(avd);
+        IniFile*    hwIni         = iniFile_newFromMemory("", NULL);
+        androidHwConfig_write(hw, hwIni);
+
+        if (filelock_create(coreHwIniPath) == NULL) {
+            /* The AVD is already in use, we still support this as an
+             * experimental feature. Use a temporary hardware-qemu.ini
+             * file though to avoid overwriting the existing one. */
+             TempFile*  tempIni = tempfile_create();
+             coreHwIniPath = tempfile_path(tempIni);
         }
 
-        const char* tempHwPath = tempfile_path(tempHw);
-        IniFile*    hwIni      = iniFile_newFromMemory("", NULL);
-        androidHwConfig_write(hw, hwIni);
-        if (iniFile_saveToFile(hwIni, tempHwPath) < 0) {
-            derror("Could not write temporary hardware.ini: %s", tempHwPath);
+        if (iniFile_saveToFile(hwIni, coreHwIniPath) < 0) {
+            derror("Could not write hardware.ini to %s: %s", coreHwIniPath, strerror(errno));
             exit(2);
         }
         args[n++] = "-android-hw";
-        args[n++] = strdup(tempHwPath);
+        args[n++] = strdup(coreHwIniPath);
     }
 
     if(VERBOSE_CHECK(init)) {
@@ -1288,7 +1085,14 @@
         /* Dump final command-line option to make debugging the core easier */
         printf("Concatenated QEMU options:\n");
         for (i = 0; i < n; i++) {
-            printf(" %s", args[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");
     }
@@ -1296,5 +1100,10 @@
     /* Setup SDL UI just before calling the code */
     init_sdl_ui(skinConfig, skinPath, opts);
 
+    if (attach_ui_to_core(opts) < 0) {
+        derror("Can't attach to core!");
+        exit(1);
+    }
+
     return qemu_main(n, args);
 }
diff --git a/android/qemulator.c b/android/qemulator.c
index ee9ccbb..b15d751 100644
--- a/android/qemulator.c
+++ b/android/qemulator.c
@@ -258,7 +258,7 @@
  * Helper routines
  */
 
-int
+static int
 get_device_dpi( AndroidOptions*  opts )
 {
     int    dpi_device  = corecmd_get_hw_lcd_density();
diff --git a/android/qemulator.h b/android/qemulator.h
index 189cc53..bd77ae1 100644
--- a/android/qemulator.h
+++ b/android/qemulator.h
@@ -66,8 +66,4 @@
 QFrameBuffer*
 qemulator_get_first_framebuffer(QEmulator* emulator);
 
-/* A helper routine for getting device DPI. */
-int
-get_device_dpi( AndroidOptions*  opts );
-
 #endif  // QEMU_ANDROID_QEMULATOR_H
diff --git a/android/skin/file.c b/android/skin/file.c
index dddc279..252a7c4 100644
--- a/android/skin/file.c
+++ b/android/skin/file.c
@@ -128,6 +128,7 @@
     { "soft-left",    kKeyCodeSoftLeft },
     { "soft-right",   kKeyCodeSoftRight },
     { "search",       kKeyCodeSearch },
+    { "camera",       kKeyCodeCamera },
     { "volume-up",    kKeyCodeVolumeUp },
     { "volume-down",  kKeyCodeVolumeDown },
     { "power",        kKeyCodePower },
diff --git a/android/snapshot.c b/android/snapshot.c
index ca86700..047465f 100644
--- a/android/snapshot.c
+++ b/android/snapshot.c
@@ -33,12 +33,10 @@
 #include <time.h>
 #include <unistd.h>
 
+#include "bswap.h"
 #include "android/utils/debug.h"
 #include "android/utils/system.h"
-#include "bswap.h"
-#include "snapshot.h"
-
-#if CONFIG_ANDROID_SNAPSHOTS
+#include "android/snapshot.h"
 
 /* "Magic" sequence of four bytes required by spec to be the first four bytes
  * of any Qcow file.
@@ -333,4 +331,3 @@
     close(fd);
     exit(0);
 }
-#endif // CONFIG_ANDROID_SNAPSHOTS
diff --git a/android/snapshot.h b/android/snapshot.h
index c0d5965..b3d954f 100644
--- a/android/snapshot.h
+++ b/android/snapshot.h
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef SNAPSHOTS_H_
-#define SNAPSHOTS_H_
+#ifndef ANDROID_SNAPSHOT_H
+#define ANDROID_SNAPSHOT_H
 
 #include "config/config.h"
 
-#if CONFIG_ANDROID_SNAPSHOTS
-
 /* Prints a table with information on the snapshot stored in the file
  * 'snapstorage', then exit()s.
  */
@@ -30,6 +28,4 @@
 extern int android_snapshot_update_time;
 extern int android_snapshot_update_time_request;
 
-#endif
-
-#endif /* SNAPSHOTS_H_ */
+#endif /* ANDROID_SNAPSHOT_H */
diff --git a/android/utils/ini.c b/android/utils/ini.c
index a5914dd..ff4a8af 100644
--- a/android/utils/ini.c
+++ b/android/utils/ini.c
@@ -480,19 +480,22 @@
 {
     char     temp[32];
     int64_t  divisor = 0;
+    const int64_t  kilo = 1024;
+    const int64_t  mega = 1024*kilo;
+    const int64_t  giga = 1024*mega;
     char     suffix = '\0';
 
-    if (size >= 0) {
-        if (!(size % 1024)) {
-            suffix = 'k';
-            divisor = 1024;
-        } else if (!(size % 1024*1024)) {
-            divisor = 1024*1024;
-            suffix  = 'm';
-        } else if (!(size % 1024*1024*1024LL)) {
-            divisor = 1024*1024*1024;
-            suffix = 'g';
-        }
+    if (size >= giga && !(size % giga)) {
+        divisor = giga;
+        suffix = 'g';
+    }
+    else if (size >= mega && !(size % mega)) {
+        divisor = mega;
+        suffix  = 'm';
+    }
+    else if (size >= kilo && !(size % kilo)) {
+        divisor = kilo;
+        suffix = 'k';
     }
     if (divisor) {
         snprintf(temp, sizeof temp, "%" PRId64 "%c", size/divisor, suffix);
diff --git a/android/utils/stralloc.c b/android/utils/stralloc.c
index 2a924e4..ce5d800 100644
--- a/android/utils/stralloc.c
+++ b/android/utils/stralloc.c
@@ -19,7 +19,7 @@
 #include <limits.h>
 
 extern void
-stralloc_tabular( stralloc_t*  out, 
+stralloc_tabular( stralloc_t*  out,
                   const char** strings, int  count,
                   const char*  prefix,  int  width )
 {
@@ -138,6 +138,40 @@
     return s->s;
 }
 
+void
+stralloc_lstrip( stralloc_t*  s )
+{
+    int  count;
+
+    for (count = 0; count < s->n; count++) {
+        if (s->s[count] != ' ' && s->s[count] != '\t')
+            break;
+    }
+
+    if (count > 0) {
+        memmove(s->s, s->s + count, s->n - count);
+        s->n -= count;
+    }
+}
+
+void
+stralloc_rstrip( stralloc_t*  s )
+{
+    int  count = s->n;
+
+    while (count > 0 && (s->s[count-1] == ' ' || s->s[count-1] == '\t'))
+        count--;
+
+    s->n = count;
+}
+
+void
+stralloc_strip( stralloc_t* s )
+{
+    stralloc_rstrip(s);
+    stralloc_lstrip(s);
+}
+
 extern char*
 stralloc_to_tempstr( stralloc_t*  s )
 {
diff --git a/android/utils/stralloc.h b/android/utils/stralloc.h
index 4d17060..626a638 100644
--- a/android/utils/stralloc.h
+++ b/android/utils/stralloc.h
@@ -52,6 +52,11 @@
 extern void   stralloc_add_hex( stralloc_t*  s, unsigned  value, int  num_digits );
 extern void   stralloc_add_hexdump( stralloc_t*  s, void*  base, int  size, const char*  prefix );
 
+/* Remove leading, trailing or leading+trailing whitespace */
+extern void   stralloc_lstrip( stralloc_t*  s );
+extern void   stralloc_rstrip( stralloc_t*  s );
+extern void   stralloc_strip( stralloc_t*  s );
+
 extern void   stralloc_tabular( stralloc_t*  s, const char** strings, int  count,
                                                 const char*  prefix,  int  width );
 
diff --git a/android/utils/system.h b/android/utils/system.h
index c8163c6..464957d 100644
--- a/android/utils/system.h
+++ b/android/utils/system.h
@@ -173,6 +173,12 @@
 #ifndef PRIx64
 #  define PRIx64  "llx"
 #endif
+#ifndef PRUd64
+#  define PRUd64  "llu"
+#endif
+#ifndef PRUx64
+#  define PRUx64  "llx"
+#endif
 
 /* */
 
diff --git a/disas.c b/disas.c
index 79a98de..475aa86 100644
--- a/disas.c
+++ b/disas.c
@@ -8,6 +8,10 @@
 #include "exec-all.h"
 #include "disas.h"
 
+#ifdef TARGET_I386
+#include "kvm.h"
+#endif
+
 /* Filled in by elfload.c.  Simplistic, but will do for now. */
 struct syminfo *syminfos = NULL;
 
@@ -33,6 +37,10 @@
                     int length,
                     struct disassemble_info *info)
 {
+#ifdef TARGET_I386
+    if (kvm_enabled())
+        cpu_synchronize_state(cpu_single_env, 0);
+#endif
     cpu_memory_rw_debug(cpu_single_env, memaddr, myaddr, length, 0);
     return 0;
 }
diff --git a/distrib/build-kernel.sh b/distrib/build-kernel.sh
new file mode 100755
index 0000000..c7e9a8f
--- /dev/null
+++ b/distrib/build-kernel.sh
@@ -0,0 +1,214 @@
+#!/bin/sh
+#
+# A small script used to rebuild the Android goldfish kernel image
+# See docs/KERNEL.TXT for usage instructions.
+#
+MACHINE=goldfish
+VARIANT=goldfish
+OUTPUT=/tmp/kernel-qemu
+CROSSPREFIX=arm-eabi-
+CONFIG=goldfish
+
+# Determine the host architecture, and which default prebuilt tag we need.
+# For the toolchain auto-detection.
+#
+HOST_OS=`uname -s`
+case "$HOST_OS" in
+    Darwin)
+        HOST_OS=darwin
+        HOST_TAG=darwin-x86
+        BUILD_NUM_CPUS=$(sysctl -n hw.ncpu)
+        ;;
+    Linux)
+        # note that building  32-bit binaries on x86_64 is handled later
+        HOST_OS=linux
+        HOST_TAG=linux-x86
+        BUILD_NUM_CPUS=$(grep -c processor /proc/cpuinfo)
+        ;;
+    *)
+        echo "ERROR: Unsupported OS: $HOST_OS"
+        exit 1
+esac
+
+# Default number of parallel jobs during the build: cores * 2
+JOBS=$(( $BUILD_NUM_CPUS * 2 ))
+
+ARCH=arm
+
+OPTION_HELP=no
+OPTION_ARMV7=no
+OPTION_OUT=
+OPTION_CROSS=
+OPTION_ARCH=
+OPTION_CONFIG=
+OPTION_JOBS=
+
+for opt do
+    optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
+    case $opt in
+    --help|-h|-\?) OPTION_HELP=yes
+        ;;
+    --armv7)
+        OPTION_ARMV7=yes
+        ;;
+    --out=*)
+        OPTION_OUT=$optarg
+        ;;
+    --cross=*)
+        OPTION_CROSS=$optarg
+        ;;
+    --arch=*)
+        OPTION_ARCH=$optarg
+        ;;
+    --config=*)
+        OPTION_CONFIG=$optarg
+        ;;
+    -j*)
+        OPTION_JOBS=$optarg
+        ;;
+    *)
+        echo "unknown option '$opt', use --help"
+        exit 1
+    esac
+done
+
+if [ $OPTION_HELP = "yes" ] ; then
+    echo "Rebuild the prebuilt kernel binary for Android's emulator."
+    echo ""
+    echo "options (defaults are within brackets):"
+    echo ""
+    echo "  --help                   print this message"
+    echo "  --arch=<arch>            change target architecture [$ARCH]"
+    echo "  --armv7                  build ARMv7 binaries (see note below)"
+    echo "  --out=<directory>        output directory [$OUTPUT]"
+    echo "  --cross=<prefix>         cross-toolchain prefix [$CROSSPREFIX]"
+    echo "  --config=<name>          kernel config name [$CONFIG]"
+    echo "  -j<number>               launch <number> parallel build jobs [$JOBS]"
+    echo ""
+    echo "NOTE: --armv7 is equivalent to --config=goldfish_armv7. It is"
+    echo "      ignored if --config=<name> is used."
+    echo ""
+    exit 0
+fi
+
+if [ -n "$OPTION_ARCH" ]; then
+    ARCH=$OPTION_ARCH
+fi
+
+if [ -n "$OPTION_CONFIG" ]; then
+    CONFIG=$OPTION_CONFIG
+else
+    if [ "$OPTION_ARMV7" = "yes" ]; then
+        CONFIG=goldfish_armv7
+    fi
+    echo "Auto-config: --config=$CONFIG"
+fi
+
+# Check that we are in the kernel directory
+if [ ! -d arch/$ARCH/mach-$MACHINE ] ; then
+    echo "Cannot find arch/$ARCH/mach-$MACHINE. Please cd to the kernel source directory."
+    echo "Aborting."
+    #exit 1
+fi
+
+# Check output directory.
+if [ -n "$OPTION_OUT" ] ; then
+    if [ ! -d "$OPTION_OUT" ] ; then
+        echo "Output directory '$OPTION_OUT' does not exist ! Aborting."
+        exit 1
+    fi
+    OUTPUT=$OPTION_OUT
+else
+    mkdir -p $OUTPUT
+fi
+
+if [ -n "$OPTION_CROSS" ] ; then
+    CROSSPREFIX="$OPTION_CROSS"
+else
+    case $ARCH in
+        arm)
+            CROSSTOOLCHAIN=arm-eabi-4.4.3
+            CROSSPREFIX=arm-eabi-
+            ZIMAGE=zImage
+            ;;
+        x86)
+            CROSSTOOLCHAIN=i686-android-linux-4.4.3
+            CROSSPREFIX=i686-android-linux-
+            ZIMAGE=bzImage
+            ;;
+        *)
+            echo "ERROR: Unsupported architecture!"
+            exit 1
+            ;;
+    esac
+    echo "Auto-config: --cross=$CROSSPREFIX"
+fi
+
+# If the cross-compiler is not in the path, try to find it automatically
+CROSS_COMPILER="${CROSSPREFIX}gcc"
+CROSS_COMPILER_VERSION=$($CROSS_COMPILER --version 2>/dev/null)
+if [ $? != 0 ] ; then
+    BUILD_TOP=$ANDROID_BUILD_TOP
+    if [ -z "$BUILD_TOP" ]; then
+        # Assume this script is under external/qemu/distrib/ in the
+        # Android source tree.
+        BUILD_TOP=$(dirname $0)/../../..
+        if [ ! -d "$BUILD_TOP/prebuilt" ]; then
+            BUILD_TOP=
+        else
+            BUILD_TOP=$(cd $BUILD_TOP && pwd)
+        fi
+    fi
+    CROSSPREFIX=$BUILD_TOP/prebuilt/$HOST_TAG/toolchain/$CROSSTOOLCHAIN/bin/$CROSSPREFIX
+    if [ "$BUILD_TOP" -a -f ${CROSSPREFIX}gcc ]; then
+        echo "Auto-config: --cross=$CROSSPREFIX"
+    else
+        echo "It looks like $CROSS_COMPILER is not in your path ! Aborting."
+        exit 1
+    fi
+fi
+
+export CROSS_COMPILE="$CROSSPREFIX" ARCH SUBARCH=$ARCH
+
+if [ "$OPTION_JOBS" ]; then
+    JOBS=$OPTION_JOBS
+else
+    echo "Auto-config: -j$JOBS"
+fi
+
+# Do the build
+#
+rm -f include/asm &&
+make ${CONFIG}_defconfig &&    # configure the kernel
+make -j$JOBS                   # build it
+
+if [ $? != 0 ] ; then
+    echo "Could not build the kernel. Aborting !"
+    exit 1
+fi
+
+# Note: The exact names of the output files are important for the Android build,
+#       do not change the definitions lightly.
+case $CONFIG in
+    vbox*)
+        OUTPUT_KERNEL=kernel-vbox
+        OUTPUT_VMLINUX=vmlinux-vbox
+        ;;
+    goldfish)
+        OUTPUT_KERNEL=kernel-qemu
+        OUTPUT_VMLINUX=vmlinux-qemu
+        ;;
+    goldfish_armv7)
+        OUTPUT_KERNEL=kernel-qemu-armv7
+        OUTPUT_VMLINUX=vmlinux-qemu-armv7
+        ;;
+    *)
+        OUTPUT_KERNEL=kernel-$CONFIG
+        OUTPUT_VMLINUX=vmlinux-$CONFIG
+esac
+
+cp -f arch/$ARCH/boot/$ZIMAGE $OUTPUT/$OUTPUT_KERNEL
+cp -f vmlinux $OUTPUT/$OUTPUT_VMLINUX
+
+echo "Kernel $CONFIG prebuilt images ($OUTPUT_KERNEL and $OUTPUT_VMLINUX) copied to $OUTPUT successfully !"
+exit 0
diff --git a/distrib/sdl-1.2.12/Makefile.android b/distrib/sdl-1.2.12/Makefile.android
index 4e89fc7..2dfa7dd 100644
--- a/distrib/sdl-1.2.12/Makefile.android
+++ b/distrib/sdl-1.2.12/Makefile.android
@@ -85,8 +85,8 @@
 $(foreach target,$(INSTALL_TARGETS),\
   $(eval $(call install-target,objs/sdl-config,$(target)/bin/sdl-config)) \
   $(eval $(call install-target,objs/SDL_config.h,$(target)/include/SDL/SDL_config.h)) \
-  $(eval $(call install-target,objs/libSDL.a,$(target)/lib/libSDL.a)) \
-  $(eval $(call install-target,objs/libSDLmain.a,$(target)/lib/libSDLmain.a)) \
+  $(eval $(call install-target,objs/libs/libSDL.a,$(target)/libs/libSDL.a)) \
+  $(eval $(call install-target,objs/libs/libSDLmain.a,$(target)/libs/libSDLmain.a)) \
   $(foreach header,$(SDL_HEADERS), \
     $(eval $(call install-target,include/$(header),$(target)/include/SDL/$(header))) \
   ) \
diff --git a/distrib/sdl-1.2.12/android-configure.sh b/distrib/sdl-1.2.12/android-configure.sh
index 133daf4..95bb91f 100755
--- a/distrib/sdl-1.2.12/android-configure.sh
+++ b/distrib/sdl-1.2.12/android-configure.sh
@@ -479,7 +479,7 @@
     # replace @exec_prefix@ with "{prefix}", and @libdir@ with "{libdir}"
     cat > $TMPC <<EOF
 s!@exec_prefix@!\$\{prefix\}!g
-s!@libdir@!\$\{exec_prefix\}/lib!g
+s!@libdir@!\$\{exec_prefix\}/libs!g
 s!@includedir@!\$\{prefix\}/include!g
 EOF
 
diff --git a/docs/KERNEL.TXT b/docs/KERNEL.TXT
index e174fe5..35d1f1f 100644
--- a/docs/KERNEL.TXT
+++ b/docs/KERNEL.TXT
@@ -1,6 +1,37 @@
 HOW TO REBUILT THE ANDROID EMULATOR-SPECIFIC KERNEL:
 ====================================================
 
+I. Helper script:
+-----------------
+
+We now provide a helper script to rebuild the kernel,
+it is under distrib/rebuild-kernel.sh.
+
+You need the sources in android.git.kernel.org/kernel/common.git,
+in branch origin/archive/android-gldfish-2.6.29 (note the typo!)
+
+To rebuild the ARM kernel:
+
+  cd $KERNEL_SOURCES
+  /path/to/rebuild-kernel.sh --out=$ANDROID/prebuilt/android-arm/kernel
+
+To rebuild the x86 kernel:
+
+  cd $KERNEL_SOURCES
+  /path/to/rebuild-kernel.sh --arch=x86 --out=$ANDROID/prebuilt/android-x86/kernel
+
+Note that you will need to have your cross-toolchain in your path.
+If this is not the case, the script will complain and give you the
+expected name. Use --cross=<prefix> to specify a different toolchain.
+
+See rebuild-kernel.sh --help for more options and details.
+
+
+II. Rebuilding from scratch:
+----------------------------
+
+If you don't or can't use the script, here are manual instructions:
+
 You need to have the Android toolchain in your path
 (i.e. 'arm-eabi-gcc --version' must work)
 
@@ -8,7 +39,7 @@
 
 git clone git://android.git.kernel.org/kernel/common.git kernel-common
 cd kernel-common
-git checkout origin/android-goldfish-2.6.29
+git checkout origin/archive/android-gldfish-2.6.29
 
 export CROSS_COMPILE=arm-eabi-
 export ARCH=arm
diff --git a/hw/goldfish_device.c b/hw/goldfish_device.c
index 3ced4ce..e98161a 100644
--- a/hw/goldfish_device.c
+++ b/hw/goldfish_device.c
@@ -12,6 +12,9 @@
 #include "qemu_file.h"
 #include "arm_pic.h"
 #include "goldfish_device.h"
+#ifdef TARGET_I386
+#include "kvm.h"
+#endif
 
 #define PDEV_BUS_OP_DONE        (0x00)
 #define PDEV_BUS_OP_REMOVE_DEV  (0x04)
@@ -148,8 +151,13 @@
             };
             break;
         case PDEV_BUS_GET_NAME:
-            if(s->current)
+            if(s->current) {
+#ifdef TARGET_I386
+                if(kvm_enabled())
+                    cpu_synchronize_state(cpu_single_env, 0);
+#endif
                 cpu_memory_rw_debug(cpu_single_env, value, (void*)s->current->name, strlen(s->current->name), 1);
+            }
             break;
         default:
             cpu_abort (cpu_single_env, "goldfish_bus_write: Bad offset %x\n", offset);
diff --git a/hw/goldfish_nand.c b/hw/goldfish_nand.c
index 2aff835..eb0c355 100644
--- a/hw/goldfish_nand.c
+++ b/hw/goldfish_nand.c
@@ -16,6 +16,10 @@
 #include "qemu_debug.h"
 #include "android/android.h"
 
+#ifdef TARGET_I386
+#include "kvm.h"
+#endif
+
 #define  DEBUG  1
 #if DEBUG
 #  define  D(...)    VERBOSE_PRINT(init,__VA_ARGS__)
@@ -374,6 +378,10 @@
         if(!eof) {
             read_len = do_read(dev->fd, dev->data, read_len);
         }
+#ifdef TARGET_I386
+        if (kvm_enabled())
+            cpu_synchronize_state(cpu_single_env, 0);
+#endif
         cpu_memory_rw_debug(cpu_single_env, data, dev->data, read_len, 1);
         data += read_len;
         len -= read_len;
@@ -393,6 +401,10 @@
     while(len > 0) {
         if(len < write_len)
             write_len = len;
+#ifdef TARGET_I386
+        if (kvm_enabled())
+                cpu_synchronize_state(cpu_single_env, 0);
+#endif
         cpu_memory_rw_debug(cpu_single_env, data, dev->data, write_len, 0);
         ret = do_write(dev->fd, dev->data, write_len);
         if(ret < write_len) {
@@ -455,6 +467,10 @@
     case NAND_CMD_GET_DEV_NAME:
         if(size > dev->devname_len)
             size = dev->devname_len;
+#ifdef TARGET_I386
+        if (kvm_enabled())
+                cpu_synchronize_state(cpu_single_env, 0);
+#endif
         cpu_memory_rw_debug(cpu_single_env, s->data, (uint8_t*)dev->devname, size, 1);
         return size;
     case NAND_CMD_READ:
@@ -464,6 +480,10 @@
             size = dev->max_size - addr;
         if(dev->fd >= 0)
             return nand_dev_read_file(dev, s->data, addr, size);
+#ifdef TARGET_I386
+        if (kvm_enabled())
+                cpu_synchronize_state(cpu_single_env, 0);
+#endif
         cpu_memory_rw_debug(cpu_single_env,s->data, &dev->data[addr], size, 1);
         return size;
     case NAND_CMD_WRITE:
@@ -475,6 +495,10 @@
             size = dev->max_size - addr;
         if(dev->fd >= 0)
             return nand_dev_write_file(dev, s->data, addr, size);
+#ifdef TARGET_I386
+        if (kvm_enabled())
+                cpu_synchronize_state(cpu_single_env, 0);
+#endif
         cpu_memory_rw_debug(cpu_single_env,s->data, &dev->data[addr], size, 0);
         return size;
     case NAND_CMD_ERASE:
@@ -638,6 +662,8 @@
     uint32_t extra_size = 64;
     uint32_t erase_pages = 64;
 
+    VERBOSE_PRINT(init, "%s: %s", __FUNCTION__, arg);
+
     while(arg) {
         next_arg = strchr(arg, ',');
         value = strchr(arg, '=');
@@ -662,10 +688,11 @@
             if(value != NULL)
                 goto bad_arg_and_value;
             devname_len = arg_len;
-            devname = malloc(arg_len);
+            devname = malloc(arg_len+1);
             if(devname == NULL)
                 goto out_of_memory;
             memcpy(devname, arg, arg_len);
+            devname[arg_len] = 0;
         }
         else if(value == NULL) {
             if(arg_match("readonly", arg, arg_len)) {
@@ -739,7 +766,7 @@
 
     if(rwfilename) {
         rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR));
-        if(rwfd < 0 && read_only) {
+        if(rwfd < 0) {
             XLOG("could not open file %s, %s\n", rwfilename, strerror(errno));
             exit(1);
         }
@@ -792,7 +819,7 @@
                 exit(1);
             }
             if(do_write(rwfd, dev->data, read_size) != read_size) {
-                XLOG("could not write file %s, %s\n", initfilename, strerror(errno));
+                XLOG("could not write file %s, %s\n", rwfilename, strerror(errno));
                 exit(1);
             }
         } while(read_size == dev->erase_size);
diff --git a/hw/goldfish_tty.c b/hw/goldfish_tty.c
index 904a07b..fd8eca8 100644
--- a/hw/goldfish_tty.c
+++ b/hw/goldfish_tty.c
@@ -13,6 +13,10 @@
 #include "qemu-char.h"
 #include "goldfish_device.h"
 
+#ifdef TARGET_I386
+#include "kvm.h"
+#endif
+
 enum {
     TTY_PUT_CHAR       = 0x00,
     TTY_BYTES_READY    = 0x04,
@@ -126,6 +130,10 @@
                             if (to_write > len)
                                 to_write = len;
 
+#ifdef TARGET_I386
+                            if (kvm_enabled())
+                                cpu_synchronize_state(cpu_single_env, 0);
+#endif
                             cpu_memory_rw_debug(cpu_single_env, buf, (uint8_t*)temp, to_write, 0);
                             qemu_chr_write(s->cs, (const uint8_t*)temp, to_write);
                             buf += to_write;
@@ -138,6 +146,10 @@
                 case TTY_CMD_READ_BUFFER:
                     if(s->ptr_len > s->data_count)
                         cpu_abort (cpu_single_env, "goldfish_tty_write: reading more data than available %d %d\n", s->ptr_len, s->data_count);
+#ifdef TARGET_I386
+                    if (kvm_enabled())
+                        cpu_synchronize_state(cpu_single_env, 0);
+#endif
                     cpu_memory_rw_debug(cpu_single_env,s->ptr, s->data, s->ptr_len,1);
                     //printf("goldfish_tty_write: read %d bytes to %x\n", s->ptr_len, s->ptr);
                     if(s->data_count > s->ptr_len)
diff --git a/hw/hw.h b/hw/hw.h
index 4f9b650..efcbe1e 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -4,7 +4,10 @@
 
 #include "qemu-common.h"
 #include "irq.h"
+
+#if defined(TARGET_PHYS_ADDRESS_SPACE_BITS) && !defined(NEED_CPU_H)
 #include "cpu.h"
+#endif
 
 /* VM Load/Save */
 
diff --git a/hw/pc.c b/hw/pc.c
index 72b6813..ff7670e 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -788,6 +788,7 @@
 static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; */
 
 #ifdef HAS_AUDIO
+#ifndef CONFIG_ANDROID
 static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
 {
     struct soundhw *c;
@@ -805,6 +806,7 @@
     }
 }
 #endif
+#endif
 
 static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
 {
@@ -1184,7 +1186,11 @@
     events_dev_init(event0_device.base, i8259[event0_device.irq]);
 
 #ifdef HAS_AUDIO
+#ifndef CONFIG_ANDROID
     audio_init(pci_enabled ? pci_bus : NULL, i8259);
+#else
+    goldfish_audio_init(0xff004000, 0, audio_input_source);
+#endif
 #endif
 
 #ifndef CONFIG_ANDROID
diff --git a/kvm-all.c b/kvm-all.c
new file mode 100644
index 0000000..f620417
--- /dev/null
+++ b/kvm-all.c
@@ -0,0 +1,1039 @@
+/*
+ * QEMU KVM support
+ *
+ * Copyright IBM, Corp. 2008
+ *           Red Hat, Inc. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Glauber Costa     <gcosta@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdarg.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "hw/hw.h"
+#include "gdbstub.h"
+#include "kvm.h"
+
+/* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */
+#define PAGE_SIZE TARGET_PAGE_SIZE
+
+//#define DEBUG_KVM
+
+#ifdef DEBUG_KVM
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef struct KVMSlot
+{
+    target_phys_addr_t start_addr;
+    ram_addr_t memory_size;
+    ram_addr_t phys_offset;
+    int slot;
+    int flags;
+} KVMSlot;
+
+typedef struct kvm_dirty_log KVMDirtyLog;
+
+int kvm_allowed = 0;
+
+struct KVMState
+{
+    KVMSlot slots[32];
+    int fd;
+    int vmfd;
+    int coalesced_mmio;
+    int broken_set_mem_region;
+    int migration_log;
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
+#endif
+};
+
+static KVMState *kvm_state;
+
+static KVMSlot *kvm_alloc_slot(KVMState *s)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        /* KVM private memory slots */
+        if (i >= 8 && i < 12)
+            continue;
+        if (s->slots[i].memory_size == 0)
+            return &s->slots[i];
+    }
+
+    fprintf(stderr, "%s: no free slot available\n", __func__);
+    abort();
+}
+
+static KVMSlot *kvm_lookup_matching_slot(KVMState *s,
+                                         target_phys_addr_t start_addr,
+                                         target_phys_addr_t end_addr)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
+
+        if (start_addr == mem->start_addr &&
+            end_addr == mem->start_addr + mem->memory_size) {
+            return mem;
+        }
+    }
+
+    return NULL;
+}
+
+/*
+ * Find overlapping slot with lowest start address
+ */
+static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s,
+                                            target_phys_addr_t start_addr,
+                                            target_phys_addr_t end_addr)
+{
+    KVMSlot *found = NULL;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
+
+        if (mem->memory_size == 0 ||
+            (found && found->start_addr < mem->start_addr)) {
+            continue;
+        }
+
+        if (end_addr > mem->start_addr &&
+            start_addr < mem->start_addr + mem->memory_size) {
+            found = mem;
+        }
+    }
+
+    return found;
+}
+
+static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
+{
+    struct kvm_userspace_memory_region mem;
+
+    mem.slot = slot->slot;
+    mem.guest_phys_addr = slot->start_addr;
+    mem.memory_size = slot->memory_size;
+    mem.userspace_addr = (unsigned long)qemu_get_ram_ptr(slot->phys_offset);
+    mem.flags = slot->flags;
+    if (s->migration_log) {
+        mem.flags |= KVM_MEM_LOG_DIRTY_PAGES;
+    }
+    return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
+}
+
+
+int kvm_init_vcpu(CPUState *env)
+{
+    KVMState *s = kvm_state;
+    long mmap_size;
+    int ret;
+
+    dprintf("kvm_init_vcpu\n");
+
+    ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, env->cpu_index);
+    if (ret < 0) {
+        dprintf("kvm_create_vcpu failed\n");
+        goto err;
+    }
+
+    env->kvm_fd = ret;
+    env->kvm_state = s;
+
+    mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
+    if (mmap_size < 0) {
+        dprintf("KVM_GET_VCPU_MMAP_SIZE failed\n");
+        goto err;
+    }
+
+    env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                        env->kvm_fd, 0);
+    if (env->kvm_run == MAP_FAILED) {
+        ret = -errno;
+        dprintf("mmap'ing vcpu state failed\n");
+        goto err;
+    }
+
+    ret = kvm_arch_init_vcpu(env);
+
+err:
+    return ret;
+}
+
+int kvm_put_mp_state(CPUState *env)
+{
+    struct kvm_mp_state mp_state = { .mp_state = env->mp_state };
+
+    return kvm_vcpu_ioctl(env, KVM_SET_MP_STATE, &mp_state);
+}
+
+int kvm_get_mp_state(CPUState *env)
+{
+    struct kvm_mp_state mp_state;
+    int ret;
+
+    ret = kvm_vcpu_ioctl(env, KVM_GET_MP_STATE, &mp_state);
+    if (ret < 0) {
+        return ret;
+    }
+    env->mp_state = mp_state.mp_state;
+    return 0;
+}
+
+int kvm_sync_vcpus(void)
+{
+    CPUState *env;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        int ret;
+
+        ret = kvm_arch_put_registers(env);
+        if (ret)
+            return ret;
+    }
+
+    return 0;
+}
+
+/*
+ * dirty pages logging control
+ */
+static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
+                                      ram_addr_t size, int flags, int mask)
+{
+    KVMState *s = kvm_state;
+    KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size);
+    int old_flags;
+
+    if (mem == NULL)  {
+            fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
+                    TARGET_FMT_plx "\n", __func__, phys_addr,
+                    phys_addr + size - 1);
+            return -EINVAL;
+    }
+
+    old_flags = mem->flags;
+
+    flags = (mem->flags & ~mask) | flags;
+    mem->flags = flags;
+
+    /* If nothing changed effectively, no need to issue ioctl */
+    if (s->migration_log) {
+        flags |= KVM_MEM_LOG_DIRTY_PAGES;
+    }
+    if (flags == old_flags) {
+            return 0;
+    }
+
+    return kvm_set_user_memory_region(s, mem);
+}
+
+int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size)
+{
+        return kvm_dirty_pages_log_change(phys_addr, size,
+                                          KVM_MEM_LOG_DIRTY_PAGES,
+                                          KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size)
+{
+        return kvm_dirty_pages_log_change(phys_addr, size,
+                                          0,
+                                          KVM_MEM_LOG_DIRTY_PAGES);
+}
+
+int kvm_set_migration_log(int enable)
+{
+    KVMState *s = kvm_state;
+    KVMSlot *mem;
+    int i, err;
+
+    s->migration_log = enable;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        mem = &s->slots[i];
+
+        if (!!(mem->flags & KVM_MEM_LOG_DIRTY_PAGES) == enable) {
+            continue;
+        }
+        err = kvm_set_user_memory_region(s, mem);
+        if (err) {
+            return err;
+        }
+    }
+    return 0;
+}
+
+/**
+ * kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
+ * This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty().
+ * This means all bits are set to dirty.
+ *
+ * @start_add: start of logged region.
+ * @end_addr: end of logged region.
+ */
+int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+                                   target_phys_addr_t end_addr)
+{
+    KVMState *s = kvm_state;
+    unsigned long size, allocated_size = 0;
+    target_phys_addr_t phys_addr;
+    ram_addr_t addr;
+    KVMDirtyLog d;
+    KVMSlot *mem;
+    int ret = 0;
+
+    d.dirty_bitmap = NULL;
+    while (start_addr < end_addr) {
+        mem = kvm_lookup_overlapping_slot(s, start_addr, end_addr);
+        if (mem == NULL) {
+            break;
+        }
+
+        size = ((mem->memory_size >> TARGET_PAGE_BITS) + 7) / 8;
+        if (!d.dirty_bitmap) {
+            d.dirty_bitmap = qemu_malloc(size);
+        } else if (size > allocated_size) {
+            d.dirty_bitmap = qemu_realloc(d.dirty_bitmap, size);
+        }
+        allocated_size = size;
+        memset(d.dirty_bitmap, 0, allocated_size);
+
+        d.slot = mem->slot;
+
+        if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
+            dprintf("ioctl failed %d\n", errno);
+            ret = -1;
+            break;
+        }
+
+        for (phys_addr = mem->start_addr, addr = mem->phys_offset;
+             phys_addr < mem->start_addr + mem->memory_size;
+             phys_addr += TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
+            unsigned long *bitmap = (unsigned long *)d.dirty_bitmap;
+            unsigned nr = (phys_addr - mem->start_addr) >> TARGET_PAGE_BITS;
+            unsigned word = nr / (sizeof(*bitmap) * 8);
+            unsigned bit = nr % (sizeof(*bitmap) * 8);
+
+            if ((bitmap[word] >> bit) & 1) {
+                cpu_physical_memory_set_dirty(addr);
+            }
+        }
+        start_addr = phys_addr;
+    }
+    qemu_free(d.dirty_bitmap);
+
+    return ret;
+}
+
+int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
+{
+    int ret = -ENOSYS;
+#ifdef KVM_CAP_COALESCED_MMIO
+    KVMState *s = kvm_state;
+
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_zone zone;
+
+        zone.addr = start;
+        zone.size = size;
+
+        ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone);
+    }
+#endif
+
+    return ret;
+}
+
+int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
+{
+    int ret = -ENOSYS;
+#ifdef KVM_CAP_COALESCED_MMIO
+    KVMState *s = kvm_state;
+
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_zone zone;
+
+        zone.addr = start;
+        zone.size = size;
+
+        ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+    }
+#endif
+
+    return ret;
+}
+
+int kvm_check_extension(KVMState *s, unsigned int extension)
+{
+    int ret;
+
+    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, extension);
+    if (ret < 0) {
+        ret = 0;
+    }
+
+    return ret;
+}
+
+static void kvm_reset_vcpus(void *opaque)
+{
+    kvm_sync_vcpus();
+}
+
+int kvm_init(int smp_cpus)
+{
+    static const char upgrade_note[] =
+        "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
+        "(see http://sourceforge.net/projects/kvm).\n";
+    KVMState *s;
+    int ret;
+    int i;
+
+    if (smp_cpus > 1) {
+        fprintf(stderr, "No SMP KVM support, use '-smp 1'\n");
+        return -EINVAL;
+    }
+
+    s = qemu_mallocz(sizeof(KVMState));
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    QTAILQ_INIT(&s->kvm_sw_breakpoints);
+#endif
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++)
+        s->slots[i].slot = i;
+
+    s->vmfd = -1;
+    s->fd = open("/dev/kvm", O_RDWR);
+    if (s->fd == -1) {
+        fprintf(stderr, "Could not access KVM kernel module: %m\n");
+        ret = -errno;
+        goto err;
+    }
+
+    ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);
+    if (ret < KVM_API_VERSION) {
+        if (ret > 0)
+            ret = -EINVAL;
+        fprintf(stderr, "kvm version too old\n");
+        goto err;
+    }
+
+    if (ret > KVM_API_VERSION) {
+        ret = -EINVAL;
+        fprintf(stderr, "kvm version not supported\n");
+        goto err;
+    }
+
+    s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0);
+    if (s->vmfd < 0)
+        goto err;
+
+    /* initially, KVM allocated its own memory and we had to jump through
+     * hooks to make phys_ram_base point to this.  Modern versions of KVM
+     * just use a user allocated buffer so we can use regular pages
+     * unmodified.  Make sure we have a sufficiently modern version of KVM.
+     */
+    if (!kvm_check_extension(s, KVM_CAP_USER_MEMORY)) {
+        ret = -EINVAL;
+        fprintf(stderr, "kvm does not support KVM_CAP_USER_MEMORY\n%s",
+                upgrade_note);
+        goto err;
+    }
+
+    /* There was a nasty bug in < kvm-80 that prevents memory slots from being
+     * destroyed properly.  Since we rely on this capability, refuse to work
+     * with any kernel without this capability. */
+    if (!kvm_check_extension(s, KVM_CAP_DESTROY_MEMORY_REGION_WORKS)) {
+        ret = -EINVAL;
+
+        fprintf(stderr,
+                "KVM kernel module broken (DESTROY_MEMORY_REGION).\n%s",
+                upgrade_note);
+        goto err;
+    }
+
+#ifdef KVM_CAP_COALESCED_MMIO
+    s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO);
+#else
+    s->coalesced_mmio = 0;
+#endif
+
+    s->broken_set_mem_region = 1;
+#ifdef KVM_CAP_JOIN_MEMORY_REGIONS_WORKS
+    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS);
+    if (ret > 0) {
+        s->broken_set_mem_region = 0;
+    }
+#endif
+
+    ret = kvm_arch_init(s, smp_cpus);
+    if (ret < 0)
+        goto err;
+
+    qemu_register_reset(kvm_reset_vcpus, INT_MAX, NULL);
+
+    kvm_state = s;
+
+    return 0;
+
+err:
+    if (s) {
+        if (s->vmfd != -1)
+            close(s->vmfd);
+        if (s->fd != -1)
+            close(s->fd);
+    }
+    qemu_free(s);
+
+    return ret;
+}
+
+static int kvm_handle_io(CPUState *env, uint16_t port, void *data,
+                         int direction, int size, uint32_t count)
+{
+    int i;
+    uint8_t *ptr = data;
+
+    for (i = 0; i < count; i++) {
+        if (direction == KVM_EXIT_IO_IN) {
+            switch (size) {
+            case 1:
+                stb_p(ptr, cpu_inb(port));
+                break;
+            case 2:
+                stw_p(ptr, cpu_inw(port));
+                break;
+            case 4:
+                stl_p(ptr, cpu_inl(port));
+                break;
+            }
+        } else {
+            switch (size) {
+            case 1:
+                cpu_outb(port, ldub_p(ptr));
+                break;
+            case 2:
+                cpu_outw(port, lduw_p(ptr));
+                break;
+            case 4:
+                cpu_outl(port, ldl_p(ptr));
+                break;
+            }
+        }
+
+        ptr += size;
+    }
+
+    return 1;
+}
+
+static void kvm_run_coalesced_mmio(CPUState *env, struct kvm_run *run)
+{
+#ifdef KVM_CAP_COALESCED_MMIO
+    KVMState *s = kvm_state;
+    if (s->coalesced_mmio) {
+        struct kvm_coalesced_mmio_ring *ring;
+
+        ring = (void *)run + (s->coalesced_mmio * TARGET_PAGE_SIZE);
+        while (ring->first != ring->last) {
+            struct kvm_coalesced_mmio *ent;
+
+            ent = &ring->coalesced_mmio[ring->first];
+
+            cpu_physical_memory_write(ent->phys_addr, ent->data, ent->len);
+            /* FIXME smp_wmb() */
+            ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
+        }
+    }
+#endif
+}
+
+int kvm_cpu_exec(CPUState *env)
+{
+    struct kvm_run *run = env->kvm_run;
+    int ret;
+
+    dprintf("kvm_cpu_exec()\n");
+
+    do {
+        if (env->exit_request) {
+            dprintf("interrupt exit requested\n");
+            ret = 0;
+            break;
+        }
+
+        kvm_arch_pre_run(env, run);
+        ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
+        kvm_arch_post_run(env, run);
+
+        if (ret == -EINTR || ret == -EAGAIN) {
+            dprintf("io window exit\n");
+            ret = 0;
+            break;
+        }
+
+        if (ret < 0) {
+            dprintf("kvm run failed %s\n", strerror(-ret));
+            abort();
+        }
+
+        kvm_run_coalesced_mmio(env, run);
+
+        ret = 0; /* exit loop */
+        switch (run->exit_reason) {
+        case KVM_EXIT_IO:
+            dprintf("handle_io\n");
+            ret = kvm_handle_io(env, run->io.port,
+                                (uint8_t *)run + run->io.data_offset,
+                                run->io.direction,
+                                run->io.size,
+                                run->io.count);
+            break;
+        case KVM_EXIT_MMIO:
+            dprintf("handle_mmio\n");
+            cpu_physical_memory_rw(run->mmio.phys_addr,
+                                   run->mmio.data,
+                                   run->mmio.len,
+                                   run->mmio.is_write);
+            ret = 1;
+            break;
+        case KVM_EXIT_IRQ_WINDOW_OPEN:
+            dprintf("irq_window_open\n");
+            break;
+        case KVM_EXIT_SHUTDOWN:
+            dprintf("shutdown\n");
+            qemu_system_reset_request();
+            ret = 1;
+            break;
+        case KVM_EXIT_UNKNOWN:
+            dprintf("kvm_exit_unknown\n");
+            break;
+        case KVM_EXIT_FAIL_ENTRY:
+            dprintf("kvm_exit_fail_entry\n");
+            break;
+        case KVM_EXIT_EXCEPTION:
+            dprintf("kvm_exit_exception\n");
+            break;
+        case KVM_EXIT_DEBUG:
+            dprintf("kvm_exit_debug\n");
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+            if (kvm_arch_debug(&run->debug.arch)) {
+                gdb_set_stop_cpu(env);
+                vm_stop(EXCP_DEBUG);
+                env->exception_index = EXCP_DEBUG;
+                return 0;
+            }
+            /* re-enter, this exception was guest-internal */
+            ret = 1;
+#endif /* KVM_CAP_SET_GUEST_DEBUG */
+            break;
+        default:
+            dprintf("kvm_arch_handle_exit\n");
+            ret = kvm_arch_handle_exit(env, run);
+            break;
+        }
+    } while (ret > 0);
+
+    if (env->exit_request) {
+        env->exit_request = 0;
+        env->exception_index = EXCP_INTERRUPT;
+    }
+
+    return ret;
+}
+
+void kvm_set_phys_mem(target_phys_addr_t start_addr,
+                      ram_addr_t size,
+                      ram_addr_t phys_offset)
+{
+    KVMState *s = kvm_state;
+    ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
+    KVMSlot *mem, old;
+    int err;
+
+    if (start_addr & ~TARGET_PAGE_MASK) {
+        if (flags >= IO_MEM_UNASSIGNED) {
+            if (!kvm_lookup_overlapping_slot(s, start_addr,
+                                             start_addr + size)) {
+                return;
+            }
+            fprintf(stderr, "Unaligned split of a KVM memory slot\n");
+        } else {
+            fprintf(stderr, "Only page-aligned memory slots supported\n");
+        }
+        abort();
+    }
+
+    /* KVM does not support read-only slots */
+    phys_offset &= ~IO_MEM_ROM;
+
+    while (1) {
+        mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size);
+        if (!mem) {
+            break;
+        }
+
+        if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr &&
+            (start_addr + size <= mem->start_addr + mem->memory_size) &&
+            (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
+            /* The new slot fits into the existing one and comes with
+             * identical parameters - nothing to be done. */
+            return;
+        }
+
+        old = *mem;
+
+        /* unregister the overlapping slot */
+        mem->memory_size = 0;
+        err = kvm_set_user_memory_region(s, mem);
+        if (err) {
+            fprintf(stderr, "%s: error unregistering overlapping slot: %s\n",
+                    __func__, strerror(-err));
+            abort();
+        }
+
+        /* Workaround for older KVM versions: we can't join slots, even not by
+         * unregistering the previous ones and then registering the larger
+         * slot. We have to maintain the existing fragmentation. Sigh.
+         *
+         * This workaround assumes that the new slot starts at the same
+         * address as the first existing one. If not or if some overlapping
+         * slot comes around later, we will fail (not seen in practice so far)
+         * - and actually require a recent KVM version. */
+        if (s->broken_set_mem_region &&
+            old.start_addr == start_addr && old.memory_size < size &&
+            flags < IO_MEM_UNASSIGNED) {
+            mem = kvm_alloc_slot(s);
+            mem->memory_size = old.memory_size;
+            mem->start_addr = old.start_addr;
+            mem->phys_offset = old.phys_offset;
+            mem->flags = 0;
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error updating slot: %s\n", __func__,
+                        strerror(-err));
+                abort();
+            }
+
+            start_addr += old.memory_size;
+            phys_offset += old.memory_size;
+            size -= old.memory_size;
+            continue;
+        }
+
+        /* register prefix slot */
+        if (old.start_addr < start_addr) {
+            mem = kvm_alloc_slot(s);
+            mem->memory_size = start_addr - old.start_addr;
+            mem->start_addr = old.start_addr;
+            mem->phys_offset = old.phys_offset;
+            mem->flags = 0;
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error registering prefix slot: %s\n",
+                        __func__, strerror(-err));
+                abort();
+            }
+        }
+
+        /* register suffix slot */
+        if (old.start_addr + old.memory_size > start_addr + size) {
+            ram_addr_t size_delta;
+
+            mem = kvm_alloc_slot(s);
+            mem->start_addr = start_addr + size;
+            size_delta = mem->start_addr - old.start_addr;
+            mem->memory_size = old.memory_size - size_delta;
+            mem->phys_offset = old.phys_offset + size_delta;
+            mem->flags = 0;
+
+            err = kvm_set_user_memory_region(s, mem);
+            if (err) {
+                fprintf(stderr, "%s: error registering suffix slot: %s\n",
+                        __func__, strerror(-err));
+                abort();
+            }
+        }
+    }
+
+    /* in case the KVM bug workaround already "consumed" the new slot */
+    if (!size)
+        return;
+
+    /* KVM does not need to know about this memory */
+    if (flags >= IO_MEM_UNASSIGNED)
+        return;
+
+    mem = kvm_alloc_slot(s);
+    mem->memory_size = size;
+    mem->start_addr = start_addr;
+    mem->phys_offset = phys_offset;
+    mem->flags = 0;
+
+    err = kvm_set_user_memory_region(s, mem);
+    if (err) {
+        fprintf(stderr, "%s: error registering slot: %s\n", __func__,
+                strerror(-err));
+        abort();
+    }
+}
+
+int kvm_ioctl(KVMState *s, int type, ...)
+{
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(s->fd, type, arg);
+    if (ret == -1)
+        ret = -errno;
+
+    return ret;
+}
+
+int kvm_vm_ioctl(KVMState *s, int type, ...)
+{
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(s->vmfd, type, arg);
+    if (ret == -1)
+        ret = -errno;
+
+    return ret;
+}
+
+int kvm_vcpu_ioctl(CPUState *env, int type, ...)
+{
+    int ret;
+    void *arg;
+    va_list ap;
+
+    va_start(ap, type);
+    arg = va_arg(ap, void *);
+    va_end(ap);
+
+    ret = ioctl(env->kvm_fd, type, arg);
+    if (ret == -1)
+        ret = -errno;
+
+    return ret;
+}
+
+int kvm_has_sync_mmu(void)
+{
+#ifdef KVM_CAP_SYNC_MMU
+    KVMState *s = kvm_state;
+
+    return kvm_check_extension(s, KVM_CAP_SYNC_MMU);
+#else
+    return 0;
+#endif
+}
+
+void kvm_setup_guest_memory(void *start, size_t size)
+{
+    if (!kvm_has_sync_mmu()) {
+#ifdef MADV_DONTFORK
+        int ret = madvise(start, size, MADV_DONTFORK);
+
+        if (ret) {
+            perror("madvice");
+            exit(1);
+        }
+#else
+        fprintf(stderr,
+                "Need MADV_DONTFORK in absence of synchronous KVM MMU\n");
+        exit(1);
+#endif
+    }
+}
+
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
+                                                 target_ulong pc)
+{
+    struct kvm_sw_breakpoint *bp;
+
+    QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) {
+        if (bp->pc == pc)
+            return bp;
+    }
+    return NULL;
+}
+
+int kvm_sw_breakpoints_active(CPUState *env)
+{
+    return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints);
+}
+
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
+{
+    struct kvm_guest_debug dbg;
+
+    dbg.control = 0;
+    if (env->singlestep_enabled)
+        dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+
+    kvm_arch_update_guest_debug(env, &dbg);
+    dbg.control |= reinject_trap;
+
+    return kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg);
+}
+
+int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    struct kvm_sw_breakpoint *bp;
+    CPUState *env;
+    int err;
+
+    if (type == GDB_BREAKPOINT_SW) {
+        bp = kvm_find_sw_breakpoint(current_env, addr);
+        if (bp) {
+            bp->use_count++;
+            return 0;
+        }
+
+        bp = qemu_malloc(sizeof(struct kvm_sw_breakpoint));
+        if (!bp)
+            return -ENOMEM;
+
+        bp->pc = addr;
+        bp->use_count = 1;
+        err = kvm_arch_insert_sw_breakpoint(current_env, bp);
+        if (err) {
+            free(bp);
+            return err;
+        }
+
+        QTAILQ_INSERT_HEAD(&current_env->kvm_state->kvm_sw_breakpoints,
+                          bp, entry);
+    } else {
+        err = kvm_arch_insert_hw_breakpoint(addr, len, type);
+        if (err)
+            return err;
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        err = kvm_update_guest_debug(env, 0);
+        if (err)
+            return err;
+    }
+    return 0;
+}
+
+int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    struct kvm_sw_breakpoint *bp;
+    CPUState *env;
+    int err;
+
+    if (type == GDB_BREAKPOINT_SW) {
+        bp = kvm_find_sw_breakpoint(current_env, addr);
+        if (!bp)
+            return -ENOENT;
+
+        if (bp->use_count > 1) {
+            bp->use_count--;
+            return 0;
+        }
+
+        err = kvm_arch_remove_sw_breakpoint(current_env, bp);
+        if (err)
+            return err;
+
+        QTAILQ_REMOVE(&current_env->kvm_state->kvm_sw_breakpoints, bp, entry);
+        qemu_free(bp);
+    } else {
+        err = kvm_arch_remove_hw_breakpoint(addr, len, type);
+        if (err)
+            return err;
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        err = kvm_update_guest_debug(env, 0);
+        if (err)
+            return err;
+    }
+    return 0;
+}
+
+void kvm_remove_all_breakpoints(CPUState *current_env)
+{
+    struct kvm_sw_breakpoint *bp, *next;
+    KVMState *s = current_env->kvm_state;
+    CPUState *env;
+
+    QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) {
+        if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) {
+            /* Try harder to find a CPU that currently sees the breakpoint. */
+            for (env = first_cpu; env != NULL; env = env->next_cpu) {
+                if (kvm_arch_remove_sw_breakpoint(env, bp) == 0)
+                    break;
+            }
+        }
+    }
+    kvm_arch_remove_all_hw_breakpoints();
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu)
+        kvm_update_guest_debug(env, 0);
+}
+
+#else /* !KVM_CAP_SET_GUEST_DEBUG */
+
+int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap)
+{
+    return -EINVAL;
+}
+
+int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    return -EINVAL;
+}
+
+int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
+                          target_ulong len, int type)
+{
+    return -EINVAL;
+}
+
+void kvm_remove_all_breakpoints(CPUState *current_env)
+{
+}
+#endif /* !KVM_CAP_SET_GUEST_DEBUG */
diff --git a/kvm.h b/kvm.h
index f5f5a55..e1fc986 100644
--- a/kvm.h
+++ b/kvm.h
@@ -18,6 +18,8 @@
 #include "qemu-queue.h"
 
 #ifdef CONFIG_KVM
+
+#ifdef TARGET_I386
 extern int kvm_allowed;
 
 #define kvm_enabled() (kvm_allowed)
@@ -25,6 +27,10 @@
 #define kvm_enabled() (0)
 #endif
 
+#else
+#define kvm_enabled() (0)
+#endif
+
 struct kvm_run;
 
 /* external API */
diff --git a/memcheck/memcheck.c b/memcheck/memcheck.c
index 3c8194a..3ccb196 100644
--- a/memcheck/memcheck.c
+++ b/memcheck/memcheck.c
@@ -14,12 +14,6 @@
  * Contains implementation of memory checking framework in the emulator.
  */
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "qemu-queue.h"
 #include "qemu_file.h"
 #include "elff_api.h"
diff --git a/memcheck/memcheck.h b/memcheck/memcheck.h
index a9a6422..a7761a9 100644
--- a/memcheck/memcheck.h
+++ b/memcheck/memcheck.h
@@ -18,12 +18,6 @@
 #ifndef QEMU_MEMCHECK_MEMCHECK_H
 #define QEMU_MEMCHECK_MEMCHECK_H
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "memcheck_common.h"
 
 #ifdef __cplusplus
diff --git a/memcheck/memcheck_common.h b/memcheck/memcheck_common.h
index e6d12db..e753094 100644
--- a/memcheck/memcheck_common.h
+++ b/memcheck/memcheck_common.h
@@ -18,12 +18,6 @@
 #ifndef QEMU_MEMCHECK_MEMCHECK_COMMON_H
 #define QEMU_MEMCHECK_MEMCHECK_COMMON_H
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "qemu-common.h"
 #include "cpu.h"
 
diff --git a/memcheck/memcheck_logging.h b/memcheck/memcheck_logging.h
index c2ae6e9..94a3c09 100644
--- a/memcheck/memcheck_logging.h
+++ b/memcheck/memcheck_logging.h
@@ -17,12 +17,6 @@
 #ifndef QEMU_MEMCHECK_MEMCHECK_LOGGING_H
 #define QEMU_MEMCHECK_MEMCHECK_LOGGING_H
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "qemu-common.h"
 #include "android/utils/debug.h"
 
diff --git a/memcheck/memcheck_malloc_map.c b/memcheck/memcheck_malloc_map.c
index 07ae889..d7e8032 100644
--- a/memcheck/memcheck_malloc_map.c
+++ b/memcheck/memcheck_malloc_map.c
@@ -15,12 +15,6 @@
  * memory blocks allocated by the guest system.
  */
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "memcheck_malloc_map.h"
 #include "memcheck_util.h"
 #include "memcheck_logging.h"
diff --git a/memcheck/memcheck_malloc_map.h b/memcheck/memcheck_malloc_map.h
index b356180..1c25738 100644
--- a/memcheck/memcheck_malloc_map.h
+++ b/memcheck/memcheck_malloc_map.h
@@ -24,12 +24,6 @@
 #ifndef QEMU_MEMCHECK_MEMCHECK_MALLOC_MAP_H
 #define QEMU_MEMCHECK_MEMCHECK_MALLOC_MAP_H
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "sys-tree.h"
 #include "memcheck_common.h"
 
diff --git a/memcheck/memcheck_mmrange_map.c b/memcheck/memcheck_mmrange_map.c
index f2609df..d9a1211 100644
--- a/memcheck/memcheck_mmrange_map.c
+++ b/memcheck/memcheck_mmrange_map.c
@@ -15,12 +15,6 @@
  * memory mappings in the guest system.
  */
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "memcheck_mmrange_map.h"
 #include "memcheck_logging.h"
 
diff --git a/memcheck/memcheck_mmrange_map.h b/memcheck/memcheck_mmrange_map.h
index f2c9701..f291c95 100644
--- a/memcheck/memcheck_mmrange_map.h
+++ b/memcheck/memcheck_mmrange_map.h
@@ -22,12 +22,6 @@
 #ifndef QEMU_MEMCHECK_MEMCHECK_MMRANGE_MAP_H
 #define QEMU_MEMCHECK_MEMCHECK_MMRANGE_MAP_H
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "sys-tree.h"
 #include "memcheck_common.h"
 
diff --git a/memcheck/memcheck_proc_management.c b/memcheck/memcheck_proc_management.c
index 593ba32..45cf141 100644
--- a/memcheck/memcheck_proc_management.c
+++ b/memcheck/memcheck_proc_management.c
@@ -15,12 +15,6 @@
  * memchecker framework.
  */
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "elff/elff_api.h"
 #include "memcheck.h"
 #include "memcheck_proc_management.h"
diff --git a/memcheck/memcheck_proc_management.h b/memcheck/memcheck_proc_management.h
index 68b6181..7f489cf 100644
--- a/memcheck/memcheck_proc_management.h
+++ b/memcheck/memcheck_proc_management.h
@@ -18,12 +18,6 @@
 #ifndef QEMU_MEMCHECK_MEMCHECK_PROC_MANAGEMENT_H
 #define QEMU_MEMCHECK_MEMCHECK_PROC_MANAGEMENT_H
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "qemu-queue.h"
 #include "memcheck_common.h"
 #include "memcheck_malloc_map.h"
diff --git a/memcheck/memcheck_util.c b/memcheck/memcheck_util.c
index 5449488..8a59914 100644
--- a/memcheck/memcheck_util.c
+++ b/memcheck/memcheck_util.c
@@ -14,12 +14,6 @@
  * Contains implementation of utility routines for memchecker framework.
  */
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "stdio.h"
 #include "qemu-common.h"
 #include "android/utils/path.h"
diff --git a/memcheck/memcheck_util.h b/memcheck/memcheck_util.h
index b75ee53..2a9907e 100644
--- a/memcheck/memcheck_util.h
+++ b/memcheck/memcheck_util.h
@@ -17,12 +17,6 @@
 #ifndef QEMU_MEMCHECK_MEMCHECK_UTIL_H
 #define QEMU_MEMCHECK_MEMCHECK_UTIL_H
 
-/* This file should compile iff qemu is built with memory checking
- * configuration turned on. */
-#ifndef CONFIG_MEMCHECK
-#error CONFIG_MEMCHECK is not defined.
-#endif  // CONFIG_MEMCHECK
-
 #include "memcheck_common.h"
 #include "elff/elff_api.h"
 
diff --git a/net-android.c b/net-android.c
index 234235b..6459eff 100644
--- a/net-android.c
+++ b/net-android.c
@@ -126,7 +126,7 @@
 #include "libslirp.h"
 #endif
 
-#if defined(CONFIG_SHAPER)
+#if defined(CONFIG_ANDROID)
 #include "shaper.h"
 #endif
 
@@ -730,7 +730,7 @@
     return ( data[12] == 10 && data[16] == 10);
 }
 
-#ifdef CONFIG_SHAPER
+#ifdef CONFIG_ANDROID
 
 NetShaper  slirp_shaper_in;
 NetShaper  slirp_shaper_out;
@@ -773,12 +773,12 @@
     netshaper_set_rate( slirp_shaper_in,  qemu_net_upload_speed  );
 }
 
-#endif /* CONFIG_SHAPER */
+#endif /* CONFIG_ANDROID */
 
 
 int slirp_can_output(void)
 {
-#ifdef CONFIG_SHAPER
+#ifdef CONFIG_ANDROID
     return !slirp_vc ||
            ( netshaper_can_send(slirp_shaper_out) &&
              qemu_can_send_packet(slirp_vc) );
@@ -799,7 +799,7 @@
     if (!slirp_vc)
         return;
 
-#ifdef CONFIG_SHAPER
+#ifdef CONFIG_ANDROID
     netshaper_send(slirp_shaper_out, (void*)pkt, pkt_len);
 #else
     qemu_send_packet(slirp_vc, pkt, pkt_len);
@@ -820,7 +820,7 @@
     if (qemu_tcpdump_active)
         qemu_tcpdump_packet(buf, size);
 
-#ifdef CONFIG_SHAPER
+#ifdef CONFIG_ANDROID
     netshaper_send(slirp_shaper_in, (char*)buf, size);
 #else
     slirp_input(buf, size);
diff --git a/qemu-options.hx b/qemu-options.hx
index baae81b..f35b4d0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1440,6 +1440,95 @@
 @code{2006-06-17}. The default value is @code{now}.
 ETEXI
 
+/* Start user mode network stack restrictions */
+DEF("drop-udp", 0, QEMU_OPTION_drop_udp, \
+    "-drop-udp       starts filtering all UDP packets\n")
+STEXI
+
+@item -drop-udp
+Enable dropping of all UDP packets.
+ETEXI
+
+
+DEF("drop-tcp", 0, QEMU_OPTION_drop_tcp, \
+    "-drop-tcp       starts filtering all TCP packets\n")
+STEXI
+
+@item -drop-tcp
+Enable dropping of all TCP packets.
+ETEXI
+
+
+DEF("allow-tcp", HAS_ARG, QEMU_OPTION_allow_tcp, \
+    "-allow-tcp      Only allows TCP packets for host:port\n")
+STEXI
+
+@item -allow-tcp @var{host}:@var{port}
+Allows communication with the host named @code{host} and with
+the port @code{port}.
+ETEXI
+
+
+DEF("drop-log", 0, QEMU_OPTION_drop_log, \
+    "-drop-log       Creates a log for dropped connections\n")
+STEXI
+
+@item -drop-log @var{file}
+Creates a log for dropped connections in the file @code{file}.
+ETEXI
+
+/* Additional network restriction options */
+
+DEF("max-dns-conns", HAS_ARG, QEMU_OPTION_max_dns_conns, \
+    "-max-dns-conns limit \n"
+    "                Limits the maximum DNS connections\n")
+STEXI
+@item -max-dns-conns @var{limit}
+Limits the maximum DNS connections to @var{limit}.
+ETEXI
+
+DEF("allow-udp", HAS_ARG, QEMU_OPTION_allow_udp, \
+    "-allow-udp host:port \n"
+    "                Allows udp connections to go through to host:port\n")
+STEXI
+@item -allow-udp @var{host}:@var{port}
+Allows udp connections to go through to @var{host}:@var{port}.
+ETEXI
+
+DEF("dns-log", HAS_ARG, QEMU_OPTION_dns_log, \
+    "-dns-log file   Creates a log of DNS lookups\n")
+STEXI
+@item -dns-log @var{file}
+Creates a log of DNS lookups as @var{file}.
+ETEXI
+
+
+DEF("net-forward", HAS_ARG, QEMU_OPTION_net_forward, \
+"-net-forward dst_net:dst_mask:dst_port:redirect_ip:redirect_port:\n"
+"                Forwards guest network traffic sent to dst_net(dst_mask):dst_port\n"
+"                to redirect_ip:redirect_port\n")
+
+STEXI
+@item -net-forward @var{settings}
+Forwards network traffic using the settings @code{settings}.
+ETEXI
+
+
+DEF("net-forward-tcp2sink", HAS_ARG, QEMU_OPTION_net_forward_tcp2sink, \
+"-net-forward-tcp2sink sink_ip:sink_port\n"
+"                Forwards all dropped and non-forwarded guest network traffic\n"
+"                to specified ip:port. \n")
+
+STEXI
+@item -net-forward-tcp2sink @var{settings}
+Forwards all dropped and non-forwarded network traffic to sink ip:port.
+ETEXI
+
+
+
+/* End User mode network stack restrictions */
+
+
 DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
     "-icount [N|auto]\n" \
     "                enable virtual instruction counter with 2^N clock ticks per\n" \
@@ -1631,10 +1720,6 @@
     "-charmap <file>"
     " use specific key character map\n")
 
-DEF("android-gui", HAS_ARG, QEMU_OPTION_android_gui, \
-    "-android-gui width=<width>,height=<height>,bpp=<bits per pixel>"
-    " width, height, and bits per pixel for the graphic console\n")
-
 DEF("android-hw", HAS_ARG, QEMU_OPTION_android_hw, \
     "-android-hw <file> read hardware initialization from ini file\n")
 
@@ -1697,4 +1782,7 @@
 DEF("audio-test-out", 0, QEMU_OPTION_audio_test_out, \
    "-audio-test-out Test audio output\n")
 
+DEF("snapshot-no-time-update", 0, QEMU_OPTION_snapshot_no_time_update, \
+    "-snapshot-no-time-update Disable time update when restoring snapshots\n")
+
 #endif /* ANDROID */
diff --git a/qemu-timer.c b/qemu-timer.c
index 0ed5ba9..82a5de3 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -394,14 +394,20 @@
 static struct qemu_alarm_timer alarm_timers[] = {
 #ifndef _WIN32
 #ifdef __linux__
-    {"dynticks", dynticks_start_timer,
-     dynticks_stop_timer, dynticks_rearm_timer, NULL},
     /* HPET - if available - is preferred */
     {"hpet", hpet_start_timer, hpet_stop_timer, NULL, NULL},
     /* ...otherwise try RTC */
     {"rtc", rtc_start_timer, rtc_stop_timer, NULL, NULL},
 #endif
     {"unix", unix_start_timer, unix_stop_timer, NULL, NULL},
+#ifdef __linux__
+    /* on Linux, the 'dynticks' clock sometimes doesn't work
+     * properly. this results in the UI freezing while emulation
+     * continues, for several seconds... So move it to the end
+     * of the list. */
+    {"dynticks", dynticks_start_timer,
+     dynticks_stop_timer, dynticks_rearm_timer, NULL},
+#endif
 #else
     {"dynticks", win32_start_timer,
      win32_stop_timer, win32_rearm_timer, &alarm_win32_data},
diff --git a/slirp-android/libslirp.h b/slirp-android/libslirp.h
index 6086384..e8b63a8 100644
--- a/slirp-android/libslirp.h
+++ b/slirp-android/libslirp.h
@@ -2,7 +2,9 @@
 #define _LIBSLIRP_H
 
 #include <stdint.h>
+#include <stdio.h>
 #include "sockets.h"
+#include "slirp.h"
 #ifdef _WIN32
 #  define WIN32_LEAN_AND_MEAN
 #  define socket_close  winsock2_socket_close3
@@ -16,6 +18,8 @@
 extern "C" {
 #endif
 
+struct mbuf;
+
 int    inet_strtoip(const char*  str, uint32_t  *ip);
 char*  inet_iptostr(uint32_t  ip);
 
@@ -32,6 +36,64 @@
 int slirp_can_output(void);
 void slirp_output(const uint8_t *pkt, int pkt_len);
 
+/* ---------------------------------------------------*/
+/* User mode network stack restrictions */
+void slirp_drop_udp();
+void slirp_drop_tcp();
+void slirp_add_allow(unsigned long dst_addr, int dst_lport,
+                     int dst_hport, u_int8_t proto);
+void slirp_drop_log_fd(FILE* fd);
+
+/** Get the drop log fd */
+FILE* get_slirp_drop_log_fd(void);
+int slirp_should_drop(unsigned long dst_addr,
+                      int dst_port,
+                      u_int8_t proto);
+int slirp_drop_log(const char* format, ...);
+
+/* for network forwards */
+void slirp_add_net_forward(unsigned long dest_ip, unsigned long dest_mask,
+                           int dest_lport, int dest_hport,
+                           unsigned long redirect_ip, int redirect_port);
+
+int slirp_should_net_forward(unsigned long remote_ip, int remote_port,
+                             unsigned long *redirect_ip, int *redirect_port);
+/* ---------------------------------------------------*/
+
+/**
+ * Additional network stack modifications, aiming to detect and log
+ * any network activity initiated by any binary outisde the context of
+ * the running browser.
+ */
+
+void slirp_dns_log_fd(FILE* fd);
+/** Get the dns log fd */
+FILE* get_slirp_dns_log_fd(void);
+/** Logs the DNS name in DNS query issued by the VM. */
+int slirp_log_dns(struct mbuf* m, int dropped);
+/** IP packet dump of DNS queris and responses. */
+int slirp_dump_dns(struct mbuf* m);
+/** Sets an upper limit for the number of allowed DNS requests from
+ * the VM.
+ */
+void slirp_set_max_dns_conns(int max_dns_conns);
+/* Returns the max number of allowed DNS requests.*/
+int slirp_get_max_dns_conns();
+
+/**
+ * Modifications for implementing "-net-forward-tcp2sink' option.
+ */
+
+void slirp_forward_dropped_tcp2sink(unsigned long sink_ip,  int sink_port);
+int slirp_should_forward_dropped_tcp2sink();
+unsigned long slirp_get_tcp_sink_ip();
+int slirp_get_tcp_sink_port();
+
+
+
+
+/* ---------------------------------------------------*/
+
 void slirp_redir_loop(void (*func)(void *opaque, int is_udp,
                                    const SockAddress *laddr,
                                    const SockAddress *faddr),
diff --git a/slirp-android/slirp.c b/slirp-android/slirp.c
index dc94a99..6a62e4b 100644
--- a/slirp-android/slirp.c
+++ b/slirp-android/slirp.c
@@ -32,6 +32,12 @@
 #include "android/android.h"
 #include "sockets.h"
 
+#include "qemu-queue.h"
+
+/* proto types */
+static void slirp_net_forward_init(void);
+
+
 #define  D(...)   VERBOSE_PRINT(slirp,__VA_ARGS__)
 #define  DN(...)  do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0)
 
@@ -81,7 +87,7 @@
         return -1;
 
     dns_ip = sock_address_get_ip(new_dns_addr);
-    if (dns_ip < 0)
+    if (dns_ip == -1)
         return -1;
 
     dns_addr[dns_addr_count++] = dns_ip;
@@ -259,6 +265,8 @@
     alias_addr_ip = special_addr_ip | CTL_ALIAS;
     getouraddr();
     register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
+
+    slirp_net_forward_init();
 }
 
 #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
@@ -819,6 +827,306 @@
     }
 }
 
+
+/*---------------------------------------------------*/
+/* User mode network stack restrictions */
+struct fw_allow_entry {
+    struct fw_allow_entry* next;
+    unsigned long dst_addr;   /* host byte order */
+    /* Allowed port range. dst_lport should be the same as dst_hport for a
+     * single port. */
+    unsigned short dst_lport; /* host byte order */
+    unsigned short dst_hport; /* host byte order */
+};
+
+static int drop_udp = 0;
+static int drop_tcp = 0;
+static struct fw_allow_entry* allow_tcp_entries = NULL;
+static struct fw_allow_entry* allow_udp_entries = NULL;
+static FILE* drop_log_fd = NULL;
+static FILE* dns_log_fd = NULL;
+static int max_dns_conns = -1;   /* unlimited max DNS connections by default */
+static int slirp_net_forward_inited = 0;
+
+void slirp_drop_udp() {
+    drop_udp = 1;
+}
+
+void slirp_drop_tcp() {
+    drop_tcp = 1;
+}
+
+/* TCP traffic forwarding to a sink - If enabled, all TCP traffic to any
+ * ip/port that is not explicitly forwared using '-net-forward', and which would
+ * otherwise be dropped if '-drop-tcp' has been specified, is redirected to the
+ * specified ip:port
+ */
+int forward_dropped_tcp2sink = 0;
+static unsigned long tcp_sink_ip;
+int tcp_sink_port;
+
+void slirp_forward_dropped_tcp2sink(unsigned long sink_ip, int sink_port) {
+    tcp_sink_ip = sink_ip;
+    tcp_sink_port = sink_port;
+    forward_dropped_tcp2sink = 1;
+}
+
+int slirp_should_forward_dropped_tcp2sink() {
+    return forward_dropped_tcp2sink;
+}
+
+unsigned long slirp_get_tcp_sink_ip() {
+    return tcp_sink_ip;
+}
+int slirp_get_tcp_sink_port() {
+    return tcp_sink_port;
+}
+
+/* Fill in the firewall rules. dst_lport and dst_hport are in host byte order */
+void slirp_add_allow(unsigned long dst_addr,
+                     int dst_lport, int dst_hport,
+                     u_int8_t proto) {
+
+    struct fw_allow_entry** ate;
+    switch (proto) {
+      case IPPROTO_TCP:
+          ate = &allow_tcp_entries;
+          break;
+      case IPPROTO_UDP:
+          ate = &allow_udp_entries;
+          break;
+      default:
+          return; // unknown protocol for the FW
+    }
+
+    while(*ate != NULL)
+        ate = &(*ate)->next;
+
+    *ate = malloc(sizeof(**ate));
+    if (*ate == NULL) {
+        DEBUG_MISC((dfd,
+                    "Unable to create new firewall record, malloc failed\n"));
+        exit(-1);
+    }
+
+    (*ate)->next = NULL;
+    (*ate)->dst_addr = dst_addr;
+    (*ate)->dst_lport = dst_lport;
+    (*ate)->dst_hport = dst_hport;
+}
+
+void slirp_drop_log_fd(FILE* fd) {
+    drop_log_fd = fd;
+}
+
+void slirp_dns_log_fd(FILE* fd) {
+    dns_log_fd = fd;
+}
+
+FILE* get_slirp_drop_log_fd(void) {
+  return drop_log_fd;
+}
+
+FILE* get_slirp_dns_log_fd(void) {
+  return dns_log_fd;
+}
+
+/* Address and ports are in host byte order */
+int slirp_should_drop(unsigned long dst_addr,
+                      int dst_port,
+                      u_int8_t proto) {
+
+    struct fw_allow_entry* ate;
+
+    switch (proto) {
+        case IPPROTO_TCP:
+            if (drop_tcp != 0)
+                ate = allow_tcp_entries;
+            else
+                return 0;
+            break;
+        case IPPROTO_UDP:
+            if (drop_udp != 0)
+                ate = allow_udp_entries;
+            else
+                return 0;
+            break;
+        default:
+            return 1;  // unknown protocol for the FW
+    }
+
+    while(ate) {
+        if ((ate->dst_lport <= dst_port) && (dst_port <= ate->dst_hport)) {
+            // allow any destination if 0
+            if (ate->dst_addr == 0 || ate->dst_addr == dst_addr)
+                return 0;
+        }
+        ate = ate->next;
+    }
+
+    return 1;
+}
+
+/*
+ * log DNS requests in a separate log
+ */
+int
+slirp_log_dns(struct mbuf* m, int dropped) {
+    char dns_query[256];  // max allowable dns name size
+    int c = 0;
+    int i= 0;
+    int index = 0;
+    int offset = 40 + 1;  // udp/ip headers length + 1;
+    int trim_bytes = 4;
+
+    if (!dns_log_fd)
+        return -1;
+
+    /* We assume one DNS name per query: 300 = 255 (max dns name length)
+     * + 40 (udp/ip hdr) + 1 byte DNS peamble + 4 bytes DNS suffix
+     */
+    if (m->m_len < offset || m->m_len > 300) {
+        DEBUG_MISC((dfd,"Malformed DNS qeury, length %d \n", (int)m->m_len));
+        return -1;
+    }
+    for (i = offset; i < m->m_len - trim_bytes && index < sizeof(dns_query); i++, index++) {
+        c = m->m_data[i];
+        if (c < ' ' || c > '~')
+            c = '.';
+
+        dns_query[index] = (char)c;
+    }
+    dns_query[index] = '\0';
+    if (!dropped) {
+        fprintf(dns_log_fd, "Sent DNS query for, %s\n" , dns_query);
+    } else {
+        fprintf(dns_log_fd, "Dropped DNS query for, %s\n" , dns_query);
+    }
+    fflush(dns_log_fd);
+    return 1;
+}
+
+/*
+ * log DNS requests in a separate log
+ */
+int
+slirp_dump_dns(struct mbuf* m) {
+
+    if (!dns_log_fd)
+        return 0;
+    // first we write the length of the record then the record (IP packet)
+    if (!fwrite(&(m->m_len), sizeof(int), 1, dns_log_fd) ||
+        !fwrite(m->m_data, m->m_len, 1, dns_log_fd)) {
+        return 0;
+    }
+
+    fflush(dns_log_fd);
+    return 1;
+}
+
+/* Log dropped/accepted packet info */
+int slirp_drop_log(const char* format, ...) {
+    va_list args;
+
+    if (!drop_log_fd)
+        return 0;
+
+    va_start(args, format);
+    vfprintf(drop_log_fd, format, args);
+    va_end(args);
+
+    fflush(drop_log_fd);
+
+    return 1;
+}
+
+
+/* Set max DNS requests allowed to be issued from the VM */
+void slirp_set_max_dns_conns(int num_conns) {
+    max_dns_conns = num_conns;
+}
+
+int slirp_get_max_dns_conns() {
+    return max_dns_conns;
+}
+
+/* generic guest network redirection functionality for ipv4 */
+struct net_forward_entry {
+    QTAILQ_ENTRY(net_forward_entry) next;
+    /* ip addresses are also in host byte order */
+    unsigned long dest_ip;            /* the destination address they try to contact */
+    unsigned long dest_mask;          /* the mask to apply to the address for matching */
+    /* Range of ports they were trying to contact. In case of a single port,
+     * dest_lport should be the same as dest_hport */
+    int dest_lport; /* Host byte order */
+    int dest_hport; /* Host byte order */
+
+    unsigned long  redirect_ip;
+    int redirect_port; /* Host byte order */
+};
+
+static QTAILQ_HEAD(net_forwardq, net_forward_entry) net_forwards;
+
+static void slirp_net_forward_init(void)
+{
+    if (!slirp_net_forward_inited) {
+      QTAILQ_INIT(&net_forwards);
+      slirp_net_forward_inited = 1;
+    }
+}
+
+/* all addresses and ports ae in host byte order */
+void slirp_add_net_forward(unsigned long dest_ip, unsigned long dest_mask,
+                           int dest_lport, int dest_hport,
+                           unsigned long redirect_ip, int redirect_port)
+{
+    slirp_net_forward_init();
+
+    struct net_forward_entry *entry = malloc(sizeof(*entry));
+    if (entry == NULL) {
+        DEBUG_MISC((dfd, "Unable to create new forwarding entry, malloc failed\n"));
+        exit(-1);
+    }
+
+    entry->dest_ip = dest_ip;
+    entry->dest_mask = dest_mask;
+    entry->dest_lport = dest_lport;
+    entry->dest_hport = dest_hport;
+    entry->redirect_ip = redirect_ip;
+    entry->redirect_port = redirect_port;
+
+    QTAILQ_INSERT_TAIL(&net_forwards, entry, next);
+}
+
+/* remote_port and redir_port arguments
+ * are in network byte order (tcp_subr.c) */
+int slirp_should_net_forward(unsigned long remote_ip, int remote_port,
+                             unsigned long *redirect_ip, int *redirect_port)
+{
+    struct net_forward_entry *entry;
+
+    for (entry = net_forwards.tqh_first;
+         entry != NULL; entry = entry->next.tqe_next) {
+
+        if ((entry->dest_lport <= remote_port)
+            && (remote_port <= entry->dest_hport)) {
+            if ((entry->dest_ip & entry->dest_mask)
+                == (remote_ip & entry->dest_mask)) {
+              *redirect_ip = entry->redirect_ip;
+              *redirect_port = entry->redirect_port;
+              return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/*---------------------------------------------------*/
+
+
+
+
 static void _slirp_redir_loop(void (*func)(void *opaque, int is_udp,
                                            const SockAddress *laddr,
                                            const SockAddress *faddr),
diff --git a/slirp-android/socket.c b/slirp-android/socket.c
index 44640a8..439590a 100644
--- a/slirp-android/socket.c
+++ b/slirp-android/socket.c
@@ -570,6 +570,27 @@
 
 	addr_port = so->so_faddr_port;
 
+	/*
+	 * test for generic forwarding; this function replaces the arguments
+	 * only on success
+	 */
+	unsigned long faddr = addr_ip;
+        int fport = addr_port;
+
+	if (slirp_should_net_forward(faddr, fport, &faddr, &fport)) {
+      time_t timestamp = time(NULL);
+      slirp_drop_log(
+	       "Redirected UDP: src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x "
+	       "new dst: 0x%08lx:0x%04x %ld\n",
+	        so->so_laddr_ip, so->so_laddr_port,
+	        addr_ip, addr_port,
+	        faddr, fport, timestamp
+	    );
+	}
+	addr_ip = faddr;
+	addr_port = fport;
+
+
         sock_address_init_inet(&addr, addr_ip, addr_port);
 
 	DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%08x\n", addr_port, addr_ip));
@@ -779,4 +800,3 @@
 	else
 		sofcantsendmore(so);
 }
-
diff --git a/slirp-android/tcp_subr.c b/slirp-android/tcp_subr.c
index b8b680c..cfcc3cb 100644
--- a/slirp-android/tcp_subr.c
+++ b/slirp-android/tcp_subr.c
@@ -377,6 +377,29 @@
     tcp_input(NULL, sizeof(struct ip), so);
 }
 
+
+/* Tests if an IP address corresponds to a special Qemu service (eg, the DNS
+ * server or the gateway - see ctl.h) and if so, rewrites it with the real
+ * address of the service.
+ */
+int is_qemu_special_address(unsigned long dst_addr, unsigned long *redir_addr)
+{
+  if ((dst_addr & 0xffffff00) == special_addr_ip) {
+    /* It's an alias */
+
+    int  last_byte = dst_addr & 0xff;
+
+    if (CTL_IS_DNS(last_byte))
+      *redir_addr = dns_addr[last_byte - CTL_DNS];
+    else
+      *redir_addr = loopback_addr_ip;
+
+    return 1;
+  }
+  return 0;
+}
+
+
 /*
  * Connect to a host on the Internet
  * Called by tcp_input
@@ -390,41 +413,60 @@
 int tcp_fconnect(struct socket *so)
 {
   int ret=0;
-    int try_proxy = 1;
     SockAddress    sockaddr;
-    uint32_t       sock_ip;
-    uint16_t       sock_port;
+    unsigned long       sock_ip;
+    int                 sock_port;
+    int redirect_happened = 0; /* for logging new src ip/port after connect */
 
     DEBUG_CALL("tcp_fconnect");
     DEBUG_ARG("so = %lx", (long )so);
 
-    sock_ip   = so->so_faddr_ip;
-    sock_port = so->so_faddr_port;
+    /* when true, a connection that otherwise would be dropped will instead be
+     * redirected to the sink ('-net-forward-tcp2sink') */
+    int forward_dropped_to_sink = 0;
+    time_t timestamp = time(NULL);
 
-    if ((sock_ip & 0xffffff00) == special_addr_ip) {
-      /* It's an alias */
-      int  last_byte = sock_ip & 0xff;
+    /*-------------------------------------------------------------*/
+    /* User mode network stack restrictions */
+    if (slirp_should_drop(so->so_faddr_ip, so->so_faddr_port, IPPROTO_TCP)) {
 
-      if (CTL_IS_DNS(last_byte))
-        sock_ip = dns_addr[last_byte - CTL_DNS];
-      else
-        sock_ip = loopback_addr_ip;
-      try_proxy = 0;
+      /* If forwarding to sink is enabled, don't actually drop it */
+      if (slirp_should_forward_dropped_tcp2sink()) {
+        slirp_drop_log(
+            "About to be dropped TCP allowed to sink: "
+            "0x%08lx:0x%04x -> 0x%08lx:0x%04x %ld\n",
+              so->so_laddr_ip,
+              so->so_laddr_port,
+              so->so_faddr_ip,
+              so->so_faddr_port,
+              timestamp
+        );
+        forward_dropped_to_sink = 1;
+      }
+      else {
+        slirp_drop_log(
+            "Dropped TCP: 0x%08lx:0x%04x -> 0x%08lx:0x%04x %ld\n",
+            so->so_laddr_ip,
+            so->so_laddr_port,
+            so->so_faddr_ip,
+            so->so_faddr_port,
+            timestamp
+        );
+        //errno = ENETUNREACH;
+        errno = ECONNREFUSED;
+        return -1;
+      }
+    } else {
+      slirp_drop_log(
+          "Allowed TCP: 0x%08lx:0x%04x -> 0x%08lx:0x%04x %ld\n",
+          so->so_laddr_ip,
+          so->so_laddr_port,
+          so->so_faddr_ip,
+          so->so_faddr_port,
+          timestamp
+      );
     }
-
-    sock_address_init_inet( &sockaddr, sock_ip, sock_port );
-
-    DEBUG_MISC((dfd, " connect()ing, addr=%s, proxy=%d\n",
-                sock_address_to_string(&sockaddr), try_proxy));
-
-    if (try_proxy) {
-        if (!proxy_manager_add(&sockaddr, SOCKET_STREAM, (ProxyEventFunc) tcp_proxy_event, so)) {
-            soisfconnecting(so);
-            so->s         = -1;
-            so->so_state |= SS_PROXIFIED;
-            return 0;
-        }
-    }
+    /*-------------------------------------------------------------*/
 
     if ((ret=so->s=socket_create_inet(SOCKET_STREAM)) >= 0) 
     {
@@ -434,10 +476,87 @@
         socket_set_xreuseaddr(s);
         socket_set_oobinline(s);
 
+
+        if (forward_dropped_to_sink) {
+
+          /* This connection would normally be dropped, but since forwarding of
+           * dropped connections is enabled, redirect it to the sink */
+          sock_ip = slirp_get_tcp_sink_ip();
+          sock_port= slirp_get_tcp_sink_port();
+          redirect_happened = 1;
+        }
+        else {   /* An allowed connection */
+
+          unsigned long faddr;
+          int fport;
+
+          /* Determine if the connection should be redirected
+           * due to a -net-forward rule */
+          /* faddr and fport are modified only on success */
+          if (slirp_should_net_forward(so->so_faddr_ip, so->so_faddr_port,
+                                       &faddr, &fport)) {
+            redirect_happened = 1;
+            sock_ip = faddr;              /* forced dst addr */
+            sock_port= fport;                 /* forced dst port */
+          }
+          /* Determine if this is a connection to a special qemu service,
+           * and change the destination address accordingly.
+           * 'faddr' is modified only on success  */
+          else if (is_qemu_special_address(so->so_faddr_ip, &faddr)) {
+
+          /* We keep the original destination port. If a special service
+           * listens on a different port than the standard, then appropriate
+           * forwarding should be set up using -net-forward, e.g., as it is
+           * the case with Mawler's DNS traffic, which is redirected to the
+           * special DNS port:
+           * -net-forward 0.0.0.0:0.0.0.0:53:127.0.0.1:21737 */
+
+            sock_ip = faddr;         /* real DNS/gateway addr */
+            sock_port= so->so_faddr_port;/* original dst port */
+
+          }
+          /* A normal connection - keep the original destination addr/port */
+          else {
+
+            if (!proxy_manager_add(&sockaddr, SOCKET_STREAM,
+                                   (ProxyEventFunc) tcp_proxy_event, so)) {
+                soisfconnecting(so);
+                so->s         = -1;
+                so->so_state |= SS_PROXIFIED;
+                return 0;
+            }
+
+            sock_ip = so->so_faddr_ip;  /* original dst addr */
+            sock_port= so->so_faddr_port;   /* original dst port */
+          }
+        }
+
+        DEBUG_MISC((dfd, " connect()ing, addr=%s, proxy=%d\n",
+                    sock_address_to_string(&sockaddr), try_proxy));
+
+        sock_address_init_inet( &sockaddr, sock_ip, sock_port );
+
         /* We don't care what port we get */
         socket_connect(s, &sockaddr);
 
-        /*
+        if (redirect_happened) {
+          SockAddress local_addr;
+          if (socket_get_address(s, &local_addr)) {
+            fprintf (stderr,
+                     "Warning: tcp_fconnect: could not get socket name\n");
+          }
+          slirp_drop_log(
+              "Redirected TCP: orig 0x%08lx:0x%04x -> 0x%08lx:0x%04x "
+              "new 0x%08lx:0x%04x -> 0x%08lx:0x%04x %ld\n",
+              so->so_laddr_ip, so->so_laddr_port,
+              so->so_faddr_ip, so->so_laddr_port,
+              sock_address_get_ip(&local_addr),
+              sock_address_get_port(&local_addr),
+              sock_ip, sock_port, timestamp
+          );
+        }
+
+       /*
         * If it's not in progress, it failed, so we just return 0,
         * without clearing SS_NOFDREF
         */
diff --git a/slirp-android/udp.c b/slirp-android/udp.c
index 9091505..1de938a 100644
--- a/slirp-android/udp.c
+++ b/slirp-android/udp.c
@@ -47,6 +47,10 @@
 struct udpstat udpstat;
 #endif
 
+/* Keeps track of the number of DNS requests.  Used to implement the firewall
+ * option that restricts the number of DNS requests (-max_dns_conns). */
+u_int dns_num_conns;
+
 struct socket udb;
 
 static u_int8_t udp_tos(struct socket *so);
@@ -68,6 +72,7 @@
 udp_init(void)
 {
 	udb.so_next = udb.so_prev = &udb;
+	dns_num_conns = 0;
 }
 /* m->m_data  points at ip packet header
  * m->m_len   length ip packet
@@ -121,6 +126,37 @@
 		ip->ip_len = len;
 	}
 
+	/* ------------------------------------------------------*/
+	/* User mode network stack restrictions */
+	/* slirp_should_drop requires host byte ordering in arguments */
+	time_t timestamp = time(NULL);
+
+	if (slirp_should_drop(ntohl(ip->ip_dst.addr), ntohs(uh->uh_dport.port),
+	                      IPPROTO_UDP)) {
+	  slirp_drop_log(
+	    "Dropped UDP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x %ld\n",
+	    ntohl(ip->ip_src.addr),
+	    ntohs(uh->uh_sport.port),
+	    ntohl(ip->ip_dst.addr),
+	    ntohs(uh->uh_dport.port),
+	    timestamp
+	  );
+	  goto bad; /* drop the packet */
+	}
+	else {
+	  slirp_drop_log(
+	    "Allowed UDP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x %ld\n",
+	    ntohl(ip->ip_src.addr),
+	    ntohs(uh->uh_sport.port),
+	    ntohl(ip->ip_dst.addr),
+	    ntohs(uh->uh_dport.port),
+	    timestamp
+	  );
+	}
+  /* ------------------------------------------------------*/
+
+
+
 	/*
 	 * Save a copy of the IP header in case we want restore it
 	 * for sending an ICMP error message in response.
@@ -164,6 +200,18 @@
             goto bad;
         }
 
+        // DNS logging and FW rules
+        if (ntohs(uh->uh_dport.port) == 53) {
+            if (!slirp_dump_dns(m)) {
+                DEBUG_MISC((dfd,"Error logging DNS packet"));
+            }
+            dns_num_conns++;
+            if (slirp_get_max_dns_conns() != -1 &&
+                dns_num_conns > slirp_get_max_dns_conns())
+                goto bad;
+        }
+
+
 	/*
 	 * Locate pcb for datagram.
 	 */
@@ -309,6 +357,13 @@
 
 	STAT(udpstat.udps_opackets++);
 
+	//  DNS logging
+	if (so != NULL && so->so_faddr_port == 53) {  /*so has host byte order */
+	  if (!slirp_dump_dns(m)) {
+	    DEBUG_MISC((dfd,"Error logging DNS packet"));
+	  }
+	}
+
 	error = ip_output(so, m);
 
 	return (error);
diff --git a/slirp-android/udp.h b/slirp-android/udp.h
index 4350ec3..2224181 100644
--- a/slirp-android/udp.h
+++ b/slirp-android/udp.h
@@ -69,7 +69,6 @@
 #define ui_ulen         ui_u.uh_ulen
 #define ui_sum          ui_u.uh_sum
 
-#ifdef LOG_ENABLED
 struct udpstat {
 	                                /* input statistics: */
 	        u_long  udps_ipackets;          /* total input packets */
@@ -83,7 +82,6 @@
 	                                /* output statistics: */
 	        u_long  udps_opackets;          /* total output packets */
 };
-#endif
 
 /*
  * Names for UDP sysctl objects
@@ -91,9 +89,7 @@
 #define UDPCTL_CHECKSUM         1       /* checksum UDP packets */
 #define UDPCTL_MAXID            2
 
-#ifdef LOG_ENABLED
 extern struct udpstat udpstat;
-#endif
 
 extern struct socket udb;
 struct mbuf;
diff --git a/sockets.c b/sockets.c
index e1f7ad3..1063339 100644
--- a/sockets.c
+++ b/sockets.c
@@ -130,7 +130,7 @@
     const WinsockError*  werr = _winsock_errors;
     int                  unix = EINVAL;  /* generic error code */
 
-	winsock_error = WSAGetLastError();
+    winsock_error = WSAGetLastError();
 
     for ( ; werr->string != NULL; werr++ ) {
         if (werr->winsock == winsock_error) {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 258e2cb..f595b2c 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1214,7 +1214,7 @@
 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
                               int access_type, int mmu_idx, int is_softmmu)
 {
-    uint32_t phys_addr;
+    uint32_t phys_addr = 0;
     int prot;
     int ret, is_user;
 
@@ -1244,7 +1244,7 @@
 
 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
-    uint32_t phys_addr;
+    uint32_t phys_addr = 0;
     int prot;
     int ret;
 
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 4e7eb58..88547cb 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -181,7 +181,7 @@
 #define HF2_VINTR_SHIFT      3 /* value of V_INTR_MASKING bit */
 
 #define HF2_GIF_MASK          (1 << HF2_GIF_SHIFT)
-#define HF2_HIF_MASK          (1 << HF2_HIF_SHIFT) 
+#define HF2_HIF_MASK          (1 << HF2_HIF_SHIFT)
 #define HF2_NMI_MASK          (1 << HF2_NMI_SHIFT)
 #define HF2_VINTR_MASK        (1 << HF2_VINTR_SHIFT)
 
@@ -409,7 +409,7 @@
 #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
 
 #define CPUID_VENDOR_AMD_1   0x68747541 /* "Auth" */
-#define CPUID_VENDOR_AMD_2   0x69746e65 /* "enti" */ 
+#define CPUID_VENDOR_AMD_2   0x69746e65 /* "enti" */
 #define CPUID_VENDOR_AMD_3   0x444d4163 /* "cAMD" */
 
 #define CPUID_MWAIT_IBE     (1 << 1) /* Interrupts can exit capability */
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 5a81cb2..550b348 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -211,7 +211,7 @@
         .model = 3,
         .stepping = 3,
         .features = PPRO_FEATURES,
-        .ext_features = CPUID_EXT_SSE3,
+        .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_SSSE3,
         .xlevel = 0,
         .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
     },
diff --git a/telephony/android_modem.c b/telephony/android_modem.c
index 26276bb..437035d 100644
--- a/telephony/android_modem.c
+++ b/telephony/android_modem.c
@@ -2199,16 +2199,14 @@
     return NULL;
 }
 
-#if CONFIG_ANDROID_SNAPSHOTS
 int android_snapshot_update_time = 1;
 int android_snapshot_update_time_request = 0;
-#endif
 
 static const char*
 handleSignalStrength( const char*  cmd, AModem  modem )
 {
     amodem_begin_line( modem );
-#if CONFIG_ANDROID_SNAPSHOTS
+
     /* Sneak time updates into the SignalStrength request, because it's periodic.
      * Ideally, we'd be able to prod the guest into asking immediately on restore
      * from snapshot, but that'd require a driver.
@@ -2217,7 +2215,7 @@
       amodem_addTimeUpdate( modem );
       android_snapshot_update_time_request = 0;
     }
-#endif
+
     // rssi = 0 (<-113dBm) 1 (<-111) 2-30 (<-109--53) 31 (>=-51) 99 (?!)
     // ber (bit error rate) - always 99 (unknown), apparently.
     // TODO: return 99 if modem->radio_state==A_RADIO_STATE_OFF, once radio_state is in snapshot.
diff --git a/vl-android.c b/vl-android.c
index caef03d..e140cb2 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -56,8 +56,14 @@
 #include "android/charmap.h"
 #include "android/globals.h"
 #include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+#include "android/utils/filelock.h"
+#include "android/utils/path.h"
+#include "android/utils/stralloc.h"
+#include "android/utils/tempfile.h"
 #include "android/display-core.h"
 #include "android/utils/timezone.h"
+#include "android/snapshot.h"
 #include "targphys.h"
 #include "tcpdump.h"
 
@@ -278,6 +284,8 @@
 #endif
 int no_quit = 0;
 CharDriverState *serial_hds[MAX_SERIAL_PORTS];
+int              serial_hds_count;
+
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
 #ifdef TARGET_I386
@@ -338,9 +346,6 @@
 // Path to the file containing specific key character map.
 char* op_charmap_file = NULL;
 
-/* Framebuffer dimensions, passed with -android-gui option. */
-char* android_op_gui = NULL;
-
 /* Path to hardware initialization file passed with -android-hw option. */
 char* android_op_hwini = NULL;
 
@@ -401,9 +406,11 @@
 
 extern void  dprint( const char* format, ... );
 
-#if CONFIG_ANDROID_SNAPSHOTS
+const char* dns_log_filename = NULL;
+const char* drop_log_filename = NULL;
+static int rotate_logs_requested = 0;
+
 const char* savevm_on_exit = NULL;
-#endif
 
 #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
 
@@ -509,40 +516,50 @@
 #endif
 }
 
-/* Parses -android-gui command line option, extracting width, height and bits
- * per pixel parameters for the GUI console used in this session of the
- * emulator. -android-gui option contains exactly three comma-separated positive
- * integer numbers in strict order: width goes first, width goes next, and bits
- * per pixel goes third. This routine verifies that format and return 0 if all
- * three numbers were extracted, or -1 if string format was incorrect for that
- * option. Note that this routine does not verify that extracted values are
- * correct!
+/*
+ * Sets a flag (rotate_logs_requested) to clear both the DNS and the
+ * drop logs upon receiving a SIGUSR1 signal. We need to clear the logs
+ * between the tasks that do not require restarting Qemu.
  */
-static int
-parse_androig_gui_option(const char* op, int* width, int* height, int* bpp)
-{
-    char val[128];
+void rotate_qemu_logs_handler(int signum) {
+  rotate_logs_requested = 1;
+}
 
-    if (get_param_value(val, 128, "width", op)) {
-        *width = strtol(val, NULL, 0);
-    } else {
-        fprintf(stderr, "option -android-gui is missing width parameter\n");
-        return -1;
-    }
-    if (get_param_value(val, 128, "height", op)) {
-        *height = strtol(val, NULL, 0);
-    } else {
-        fprintf(stderr, "option -android-gui is missing height parameter\n");
-        return -1;
-    }
-    if (get_param_value(val, 128, "bpp", op)) {
-        *bpp = strtol(val, NULL, 0);
-    } else {
-        fprintf(stderr, "option -android-gui is missing bpp parameter\n");
-        return -1;
-    }
+/*
+ * Resets the rotate_log_requested_flag. Normally called after qemu
+ * logs has been rotated.
+ */
+void reset_rotate_qemu_logs_request(void) {
+  rotate_logs_requested = 0;
+}
 
-    return 0;
+/*
+ * Clears the passed qemu log when the rotate_logs_requested
+ * is set. We need to clear the logs between the tasks that do not
+ * require restarting Qemu.
+ */
+FILE* rotate_qemu_log(FILE* old_log_fd, const char* filename) {
+  FILE* new_log_fd = NULL;
+  if (old_log_fd) {
+    if (fclose(old_log_fd) == -1) {
+      fprintf(stderr, "Cannot close old_log fd\n");
+      exit(errno);
+    }
+  }
+
+  if (!filename) {
+    fprintf(stderr, "The log filename to be rotated is not provided");
+    exit(-1);
+  }
+
+  new_log_fd = fopen(filename , "wb+");
+  if (new_log_fd == NULL) {
+    fprintf(stderr, "Cannot open the log file: %s for write.\n",
+            filename);
+    exit(1);
+  }
+
+  return new_log_fd;
 }
 
 /***********************************************************/
@@ -3155,6 +3172,17 @@
 #ifdef CONFIG_PROFILER
             dev_time += profile_getclock() - ti;
 #endif
+
+            if (rotate_logs_requested) {
+                FILE* new_dns_log_fd = rotate_qemu_log(get_slirp_dns_log_fd(),
+                                                        dns_log_filename);
+                FILE* new_drop_log_fd = rotate_qemu_log(get_slirp_drop_log_fd(),
+                                                         drop_log_filename);
+                slirp_dns_log_fd(new_dns_log_fd);
+                slirp_drop_log_fd(new_drop_log_fd);
+                reset_rotate_qemu_logs_request();
+            }
+
         } while (vm_can_run());
 
         if (qemu_debug_requested())
@@ -3164,11 +3192,9 @@
                 vm_stop(0);
                 no_shutdown = 0;
             } else {
-#if CONFIG_ANDROID_SNAPSHOTS
                 if (savevm_on_exit != NULL) {
                   do_savevm(cur_mon, savevm_on_exit);
                 }
-#endif
                 break;
             }
         }
@@ -3521,9 +3547,11 @@
 
 /* Find a likely location for support files using the location of the binary.
    For installed binaries this will be "$bindir/../share/qemu".  When
-   running from the build tree this will be "$bindir/../pc-bios".  */
+   running from the build tree this will be "$bindir/../pc-bios".
+   The emulator running from the SDK will find the support files in $bindir/lib/pc-bios. */
 #define SHARE_SUFFIX "/share/qemu"
 #define BUILD_SUFFIX "/pc-bios"
+#define SDK_SUFFIX "/lib/pc-bios"
 static char *find_datadir(const char *argv0)
 {
     char *dir;
@@ -3564,19 +3592,25 @@
             return NULL;
         }
     }
-    dir = dirname(p);
-    dir = dirname(dir);
 
-    max_len = strlen(dir) +
-        MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
+#define STRLEN_CONST(str) (sizeof(str)-1)
+    dir = dirname(p);
+    max_len = strlen(dir) + 1 +
+        MAX(STRLEN_CONST(SDK_SUFFIX), MAX(STRLEN_CONST(SHARE_SUFFIX), STRLEN_CONST(BUILD_SUFFIX)));
     res = qemu_mallocz(max_len);
-    snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
+
+    snprintf(res, max_len, "%s%s", dir, SDK_SUFFIX);
     if (access(res, R_OK)) {
-        snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
-        if (access(res, R_OK)) {
-            qemu_free(res);
-            res = NULL;
-        }
+      dir = dirname(dir);
+
+      snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
+      if (access(res, R_OK)) {
+          snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
+          if (access(res, R_OK)) {
+              qemu_free(res);
+              res = NULL;
+          }
+      }
     }
 #ifndef PATH_MAX
     free(p);
@@ -3641,22 +3675,226 @@
     return 0;
 }
 
-/* Appends a parameter to a string of parameters separated with space.
+/* Parses an integer
  * Pararm:
- *  param_str String containing parameters separated with space.
- *  param Parameter to append to the string.
- *  size - Size (in characters) of the buffer addressed by param_str.
+ *  str      String containing a number to be parsed.
+ *  result   Passes the parsed integer in this argument
+ *  returns  0 if ok, -1 if failed
+ */
+int
+parse_int(const char *str, int *result)
+{
+    char* r;
+    *result = strtol(str, &r, 0);
+    if (r == NULL || *r != '\0')
+      return -1;
+
+    return 0;
+}
+
+#ifndef _WIN32
+/*
+ * Initializes the SIGUSR1 signal handler to clear Qemu logs.
+ */
+void init_qemu_clear_logs_sig() {
+  struct sigaction act;
+  sigfillset(&act.sa_mask);
+  act.sa_flags = 0;
+  act.sa_handler = rotate_qemu_logs_handler;
+  if (sigaction(SIGUSR1, &act, NULL) == -1) {
+    fprintf(stderr, "Failed to setup SIGUSR1 handler to clear Qemu logs\n");
+    exit(-1);
+  }
+}
+#endif
+
+
+
+/* parses a null-terminated string specifying a network port (e.g., "80") or
+ * port range (e.g., "[6666-7000]"). In case of a single port, lport and hport
+ * are the same. Returns 0 on success, -1 on error. */
+
+int parse_port_range(const char *str, unsigned short *lport,
+                     unsigned short *hport) {
+
+  unsigned int low = 0, high = 0;
+  char *p, *arg = strdup(str);
+
+  if ((*arg == '[') && ((p = strrchr(arg, ']')) != NULL)) {
+    p = arg + 1;   /* skip '[' */
+    low  = atoi(strtok(p, "-"));
+    high = atoi(strtok(NULL, "-"));
+    if ((low > 0) && (high > 0) && (low < high) && (high < 65535)) {
+      *lport = low;
+      *hport = high;
+    }
+  }
+  else {
+    low = atoi(arg);
+    if ((0 < low) && (low < 65535)) {
+      *lport = low;
+      *hport = low;
+    }
+  }
+  free(arg);
+  if (low != 0)
+    return 0;
+  return -1;
+}
+
+/*
+ * Implements the generic port forwarding option
+ */
+void
+net_slirp_forward(const char *optarg)
+{
+    /*
+     * we expect the following format:
+     * dst_net:dst_mask:dst_port:redirect_ip:redirect_port OR
+     * dst_net:dst_mask:[dp_range_start-dp_range_end]:redirect_ip:redirect_port
+     */
+    char *argument = strdup(optarg), *p = argument;
+    char *dst_net, *dst_mask, *dst_port;
+    char *redirect_ip, *redirect_port;
+    uint32_t dnet, dmask, rip;
+    unsigned short dlport, dhport, rport;
+
+
+    dst_net = strtok(p, ":");
+    dst_mask = strtok(NULL, ":");
+    dst_port = strtok(NULL, ":");
+    redirect_ip = strtok(NULL, ":");
+    redirect_port = strtok(NULL, ":");
+
+    if (dst_net == NULL || dst_mask == NULL || dst_port == NULL ||
+        redirect_ip == NULL || redirect_port == NULL) {
+        fprintf(stderr,
+                "Invalid argument for -net-forward, we expect "
+                "dst_net:dst_mask:dst_port:redirect_ip:redirect_port or "
+                "dst_net:dst_mask:[dp_range_start-dp_range_end]"
+                ":redirect_ip:redirect_port: %s\n",
+                optarg);
+        exit(1);
+    }
+
+    /* inet_strtoip converts dotted address to host byte order */
+    if (inet_strtoip(dst_net, &dnet) == -1) {
+        fprintf(stderr, "Invalid destination IP net: %s\n", dst_net);
+        exit(1);
+    }
+    if (inet_strtoip(dst_mask, &dmask) == -1) {
+        fprintf(stderr, "Invalid destination IP mask: %s\n", dst_mask);
+        exit(1);
+    }
+    if (inet_strtoip(redirect_ip, &rip) == -1) {
+        fprintf(stderr, "Invalid redirect IP address: %s\n", redirect_ip);
+        exit(1);
+    }
+
+    if (parse_port_range(dst_port, &dlport, &dhport) == -1) {
+        fprintf(stderr, "Invalid destination port or port range\n");
+        exit(1);
+    }
+
+    rport = atoi(redirect_port);
+    if (!rport) {
+        fprintf(stderr, "Invalid redirect port: %s\n", redirect_port);
+        exit(1);
+    }
+
+    dnet &= dmask;
+
+    slirp_add_net_forward(dnet, dmask, dlport, dhport,
+                          rip, rport);
+
+    free(argument);
+}
+
+
+/* Parses an -allow-tcp or -allow-udp argument and inserts a corresponding
+ * entry in the allows list */
+void
+slirp_allow(const char *optarg, u_int8_t proto)
+{
+  /*
+   * we expect the following format:
+   * dst_ip:dst_port OR dst_ip:[dst_lport-dst_hport]
+   */
+  char *argument = strdup(optarg), *p = argument;
+  char *dst_ip_str, *dst_port_str;
+  uint32_t dst_ip;
+  unsigned short dst_lport, dst_hport;
+
+  dst_ip_str = strtok(p, ":");
+  dst_port_str = strtok(NULL, ":");
+
+  if (dst_ip_str == NULL || dst_port_str == NULL) {
+    fprintf(stderr,
+            "Invalid argument %s for -allow. We expect "
+            "dst_ip:dst_port or dst_ip:[dst_lport-dst_hport]\n",
+            optarg);
+    exit(1);
+  }
+
+  if (inet_strtoip(dst_ip_str, &dst_ip) == -1) {
+    fprintf(stderr, "Invalid destination IP address: %s\n", dst_ip_str);
+    exit(1);
+  }
+  if (parse_port_range(dst_port_str, &dst_lport, &dst_hport) == -1) {
+    fprintf(stderr, "Invalid destination port or port range\n");
+    exit(1);
+  }
+
+  slirp_add_allow(dst_ip, dst_lport, dst_hport, proto);
+
+  free(argument);
+}
+
+/* Add a serial device at a given location in the emulated hardware table.
+ * On failure, this function aborts the program with an error message.
  */
 static void
-append_param(char* param_str, const char* arg, int size)
+serial_hds_add_at(int  index, const char* devname)
 {
-    if (*param_str) {
-        strncat(param_str, " ", size);
-        strncat(param_str, arg, size);
-    } else {
-        strncpy(param_str, arg, size);
-        param_str[size - 1] = '\0';
+    char label[32];
+
+    if (!devname || !strcmp(devname,"none"))
+        return;
+
+    if (index >= MAX_SERIAL_PORTS) {
+        PANIC("qemu: invalid serial index for %s (%d >= %d)",
+              devname, index, MAX_SERIAL_PORTS);
     }
+    if (serial_hds[index] != NULL) {
+        PANIC("qemu: invalid serial index for %s (%d: already taken!)",
+              devname, index);
+    }
+    snprintf(label, sizeof(label), "serial%d", index);
+    serial_hds[index] = qemu_chr_open(label, devname, NULL);
+    if (!serial_hds[index]) {
+        PANIC("qemu: could not open serial device '%s'", devname);
+    }
+}
+
+
+/* Find a free slot in the emulated serial device table, and register
+ * it. Return the allocated table index.
+ */
+static int
+serial_hds_add(const char* devname)
+{
+    int  index;
+
+    /* Find first free slot */
+    for (index = 0; index < MAX_SERIAL_PORTS; index++) {
+        if (serial_hds[index] == NULL) {
+            serial_hds_add_at(index, devname);
+            return index;
+        }
+    }
+
+    PANIC("qemu: too many serial devices registered (%d)", index);
+    return -1;  /* shouldn't happen */
 }
 
 int main(int argc, char **argv, char **envp)
@@ -3673,6 +3911,7 @@
     DisplayChangeListener *dcl;
     int cyls, heads, secs, translation;
     QemuOpts *hda_opts = NULL;
+    QemuOpts *hdb_opts = NULL;
     const char *net_clients[MAX_NET_CLIENTS];
     int nb_net_clients;
     const char *bt_opts[MAX_BT_CMDLINE];
@@ -3706,16 +3945,9 @@
 #endif
     CPUState *env;
     int show_vnc_port = 0;
-#ifdef CONFIG_STANDALONE_CORE
     IniFile*  hw_ini = NULL;
-#endif  // CONFIG_STANDALONE_CORE
-    /* Container for the kernel initialization parameters collected in this
-     * routine. */
-    char kernel_cmdline_append[1024];
-    /* Combines kernel initialization parameters passed from the UI with
-     * the parameters collected in this routine. */
-    char kernel_cmdline_full[1024];
-    char tmp_str[1024];
+    STRALLOC_DEFINE(kernel_params);
+    STRALLOC_DEFINE(kernel_config);
     int    dns_count = 0;
 
     /* Initialize sockets before anything else, so we can properly report
@@ -3767,8 +3999,7 @@
     snapshot = 0;
     kernel_filename = NULL;
     kernel_cmdline = "";
-    kernel_cmdline_append[0] = '\0';
-    kernel_cmdline_full[0] = '\0';
+
     cyls = heads = secs = 0;
     translation = BIOS_ATA_TRANSLATION_AUTO;
     monitor_device = "vc:80Cx24C";
@@ -3893,6 +4124,9 @@
                                  ",trans=none" : "");
                  break;
             case QEMU_OPTION_hdb:
+                hdb_opts = drive_add(optarg, HD_ALIAS, 1);
+                break;
+
             case QEMU_OPTION_hdc:
             case QEMU_OPTION_hdd:
                 drive_add(optarg, HD_ALIAS, popt->index - QEMU_OPTION_hda);
@@ -4235,11 +4469,9 @@
             case QEMU_OPTION_loadvm:
                 loadvm = optarg;
                 break;
-#if CONFIG_ANDROID_SNAPSHOTS
             case QEMU_OPTION_savevm_on_exit:
                 savevm_on_exit = optarg;
                 break;
-#endif
             case QEMU_OPTION_full_screen:
                 full_screen = 1;
                 break;
@@ -4288,6 +4520,7 @@
                 kqemu_allowed = 2;
                 break;
 #endif
+#ifdef TARGET_I386
 #ifdef CONFIG_KVM
             case QEMU_OPTION_enable_kvm:
                 kvm_allowed = 1;
@@ -4296,6 +4529,7 @@
 #endif
                 break;
 #endif
+#endif  /* TARGET_I386 */
             case QEMU_OPTION_usb:
                 usb_enabled = 1;
                 break;
@@ -4416,6 +4650,91 @@
                     }
                 }
                 break;
+
+            /* -------------------------------------------------------*/
+            /* User mode network stack restrictions */
+            case QEMU_OPTION_drop_udp:
+                slirp_drop_udp();
+                break;
+            case QEMU_OPTION_drop_tcp:
+                slirp_drop_tcp();
+                break;
+            case QEMU_OPTION_allow_tcp:
+                slirp_allow(optarg, IPPROTO_TCP);
+                break;
+            case QEMU_OPTION_allow_udp:
+                slirp_allow(optarg, IPPROTO_UDP);
+                break;
+             case QEMU_OPTION_drop_log:
+                {
+                    FILE* drop_log_fd;
+                    drop_log_filename = optarg;
+                    drop_log_fd = fopen(optarg, "w+");
+
+                    if (!drop_log_fd) {
+                        fprintf(stderr, "Cannot open drop log: %s\n", optarg);
+                        exit(1);
+                    }
+
+                    slirp_drop_log_fd(drop_log_fd);
+                }
+                break;
+
+            case QEMU_OPTION_dns_log:
+                {
+                    FILE* dns_log_fd;
+                    dns_log_filename = optarg;
+                    dns_log_fd = fopen(optarg, "wb+");
+
+                    if (dns_log_fd == NULL) {
+                        fprintf(stderr, "Cannot open dns log: %s\n", optarg);
+                        exit(1);
+                    }
+
+                    slirp_dns_log_fd(dns_log_fd);
+                }
+                break;
+
+
+            case QEMU_OPTION_max_dns_conns:
+                {
+                    int max_dns_conns = 0;
+                    if (parse_int(optarg, &max_dns_conns)) {
+                      fprintf(stderr,
+                              "qemu: syntax: -max-dns-conns max_connections\n");
+                      exit(1);
+                    }
+                    if (max_dns_conns <= 0 ||  max_dns_conns == LONG_MAX) {
+                      fprintf(stderr,
+                              "Invalid arg for max dns connections: %s\n",
+                              optarg);
+                      exit(1);
+                    }
+                    slirp_set_max_dns_conns(max_dns_conns);
+                }
+                break;
+
+            case QEMU_OPTION_net_forward:
+                net_slirp_forward(optarg);
+                break;
+            case QEMU_OPTION_net_forward_tcp2sink:
+                {
+                    SockAddress saddr;
+
+                    if (parse_host_port(&saddr, optarg)) {
+                        fprintf(stderr,
+                                "Invalid ip/port %s for "
+                                "-forward-dropped-tcp2sink. "
+                                "We expect 'sink_ip:sink_port'\n",
+                                optarg);
+                        exit(1);
+                    }
+                    slirp_forward_dropped_tcp2sink(saddr.u.inet.address,
+                                                   saddr.u.inet.port);
+                }
+                break;
+            /* -------------------------------------------------------*/
+
             case QEMU_OPTION_tb_size:
                 tb_size = strtol(optarg, NULL, 0);
                 if (tb_size < 0)
@@ -4508,10 +4827,6 @@
                 op_charmap_file = (char*)optarg;
                 break;
 
-            case QEMU_OPTION_android_gui:
-                android_op_gui = (char*)optarg;
-                break;
-
             case QEMU_OPTION_android_hw:
                 android_op_hwini = (char*)optarg;
                 break;
@@ -4596,26 +4911,16 @@
 #ifdef CONFIG_MEMCHECK
             case QEMU_OPTION_android_memcheck:
                 android_op_memcheck = (char*)optarg;
-                snprintf(tmp_str, sizeof(tmp_str), "memcheck=%s",
-                         android_op_memcheck);
-                tmp_str[sizeof(tmp_str) - 1] = '\0';
                 /* This will set ro.kernel.memcheck system property
                  * to memcheck's tracing flags. */
-                append_param(kernel_cmdline_append, tmp_str, sizeof(kernel_cmdline_append));
+                stralloc_add_format(kernel_config, " memcheck=%s", android_op_memcheck);
                 break;
 #endif // CONFIG_MEMCHECK
-            }
-        }
-    }
 
-    /* Parse GUI option early, so when we init framebuffer in goldfish we have
-     * saved display parameters. */
-    if (android_op_gui) {
-        if (parse_androig_gui_option(android_op_gui,
-                                     &android_display_width,
-                                     &android_display_height,
-                                     &android_display_bpp)) {
-            PANIC("Unable to parse -android-gui parameter: %s", android_op_gui);
+            case QEMU_OPTION_snapshot_no_time_update:
+                android_snapshot_update_time = 0;
+                break;
+            }
         }
     }
 
@@ -4641,20 +4946,33 @@
         data_dir = CONFIG_QEMU_SHAREDIR;
     }
 
-#ifdef CONFIG_STANDALONE_CORE
-    /* Initialize hardware configuration. */
-    if (android_op_hwini) {
-      hw_ini = iniFile_newFromFile(android_op_hwini);
-      if (hw_ini == NULL) {
-        PANIC("Could not find %s file.", android_op_hwini);
-      }
-    } else {
-      hw_ini = iniFile_newFromMemory("", 0);
+    if (!android_op_hwini) {
+        PANIC("Missing -android-hw <file> option!");
     }
-
+    hw_ini = iniFile_newFromFile(android_op_hwini);
+    if (hw_ini == NULL) {
+        PANIC("Could not find %s file.", android_op_hwini);
+    }
     androidHwConfig_read(android_hw, hw_ini);
     iniFile_free(hw_ini);
-#endif  // CONFIG_STANDALONE_CORE
+
+    {
+        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|height) & 3) != 0)  )
+        {
+            PANIC("Invalid display configuration (%d,%d,%d)",
+                  width, height, depth);
+        }
+        android_display_width  = width;
+        android_display_height = height;
+        android_display_bpp    = depth;
+    }
 
 #ifdef CONFIG_NAND_LIMITS
     /* Init nand stuff. */
@@ -4663,6 +4981,114 @@
     }
 #endif  // CONFIG_NAND_LIMITS
 
+    /* Initialize AVD name from hardware configuration if needed */
+    if (!android_op_avd_name) {
+        if (android_hw->avd_name && *android_hw->avd_name) {
+            android_op_avd_name = android_hw->avd_name;
+            VERBOSE_PRINT(init,"AVD Name: %s", android_op_avd_name);
+        }
+    }
+
+    /* Initialize system partition image */
+    {
+        char        tmp[PATH_MAX+32];
+        const char* sysImage = android_hw->disk_systemPartition_path;
+        const char* initImage = android_hw->disk_systemPartition_initPath;
+        uint64_t    sysBytes = android_hw->disk_systemPartition_size;
+
+        if (sysBytes == 0) {
+            PANIC("Invalid system partition size: %" PRUd64, sysBytes);
+        }
+
+        snprintf(tmp,sizeof(tmp),"system,size=0x%" PRUx64, sysBytes);
+
+        if (sysImage && *sysImage) {
+            if (filelock_create(sysImage) == NULL) {
+                fprintf(stderr,"WARNING: System image already in use, changes will not persist!\n");
+                /* If there is no file= parameters, nand_add_dev will create
+                 * a temporary file to back the partition image. */
+            } else {
+                pstrcat(tmp,sizeof(tmp),",file=");
+                pstrcat(tmp,sizeof(tmp),sysImage);
+            }
+        }
+        if (initImage && *initImage) {
+            if (!path_exists(initImage)) {
+                PANIC("Invalid initial system image path: %s", initImage);
+            }
+            pstrcat(tmp,sizeof(tmp),",initfile=");
+            pstrcat(tmp,sizeof(tmp),initImage);
+        } else {
+            PANIC("Missing initial system image path!");
+        }
+        nand_add_dev(tmp);
+    }
+
+    /* Initialize data partition image */
+    {
+        char        tmp[PATH_MAX+32];
+        const char* dataImage = android_hw->disk_dataPartition_path;
+        const char* initImage = android_hw->disk_dataPartition_initPath;
+        uint64_t    dataBytes = android_hw->disk_dataPartition_size;
+
+        if (dataBytes == 0) {
+            PANIC("Invalid data partition size: %" PRUd64, dataBytes);
+        }
+
+        snprintf(tmp,sizeof(tmp),"userdata,size=0x%" PRUx64, dataBytes);
+
+        if (dataImage && *dataImage) {
+            if (filelock_create(dataImage) == NULL) {
+                fprintf(stderr, "WARNING: Data partition already in use. Changes will not persist!\n");
+                /* Note: if there is no file= parameters, nand_add_dev() will
+                 *       create a temporary file to back the partition image. */
+            } else {
+                /* Create the file if needed */
+                if (!path_exists(dataImage)) {
+                    if (path_empty_file(dataImage) < 0) {
+                        PANIC("Could not create data image file %s: %s", dataImage, strerror(errno));
+                    }
+                }
+                pstrcat(tmp, sizeof(tmp), ",file=");
+                pstrcat(tmp, sizeof(tmp), dataImage);
+            }
+        }
+        if (initImage && *initImage) {
+            pstrcat(tmp, sizeof(tmp), ",initfile=");
+            pstrcat(tmp, sizeof(tmp), initImage);
+        }
+        nand_add_dev(tmp);
+    }
+
+    /* Init SD-Card stuff. For Android, it is always hda */
+    /* If the -hda option was used, ignore the Android-provided one */
+    if (hda_opts == NULL) {
+        const char* sdPath = android_hw->hw_sdCard_path;
+        if (sdPath && *sdPath) {
+            if (!path_exists(sdPath)) {
+                fprintf(stderr, "WARNING: SD Card image is missing: %s\n", sdPath);
+            } else if (filelock_create(sdPath) == NULL) {
+                fprintf(stderr, "WARNING: SD Card image already in use: %s\n", sdPath);
+            } else {
+                /* Successful locking */
+                hda_opts = drive_add(sdPath, HD_ALIAS, 0);
+            }
+        }
+    }
+
+    if (hdb_opts == NULL) {
+        const char* spath = android_hw->disk_snapStorage_path;
+        if (spath && *spath) {
+            if (!path_exists(spath)) {
+                PANIC("Snapshot storage file does not exist: %s", spath);
+            }
+            if (filelock_create(spath) == NULL) {
+                PANIC("Snapshot storag already in use: %s", spath);
+            }
+            hdb_opts = drive_add(spath, HD_ALIAS, 1);
+        }
+    }
+
     /* Set the VM's max heap size, passed as a boot property */
     if (android_hw->vm_heapSize > 0) {
         char  tmp[64];
@@ -4689,11 +5115,10 @@
     }
 
     /* Initialize LCD density */
-    if (android_op_lcd_density) {
-        char*   end;
-        long density = strtol(android_op_lcd_density, &end, 0);
-        if (end == NULL || *end || density < 0) {
-            PANIC("option -lcd-density must be a positive integer");
+    if (android_hw->hw_lcd_density) {
+        long density = android_hw->hw_lcd_density;
+        if (density <= 0) {
+            PANIC("Invalid hw.lcd.density value: %ld", density);
         }
         hwLcd_setBootProperty(density);
     }
@@ -4789,8 +5214,7 @@
     if (dns_count == 0)
         dns_count = slirp_get_system_dns_servers();
     if (dns_count) {
-        snprintf(tmp_str, sizeof(tmp_str), "ndns=%d", dns_count);
-        append_param(kernel_cmdline_append, tmp_str, sizeof(kernel_cmdline_append));
+        stralloc_add_format(kernel_config, " ndns=%d", dns_count);
     }
 
 #ifdef CONFIG_MEMCHECK
@@ -4799,6 +5223,46 @@
     }
 #endif  // CONFIG_MEMCHECK
 
+    /* Initialize cache partition, if any */
+    if (android_hw->disk_cachePartition != 0) {
+        char        tmp[PATH_MAX+32];
+        const char* partPath = android_hw->disk_cachePartition_path;
+        uint64_t    partSize = android_hw->disk_cachePartition_size;
+
+        snprintf(tmp,sizeof(tmp),"cache,size=0x%" PRUx64, partSize);
+
+        if (partPath && *partPath && strcmp(partPath, "<temp>") != 0) {
+            if (filelock_create(partPath) == NULL) {
+                fprintf(stderr, "WARNING: Cache partition already in use. Changes will not persist!\n");
+                /* Note: if there is no file= parameters, nand_add_dev() will
+                 *       create a temporary file to back the partition image. */
+            } else {
+                /* Create the file if needed */
+                if (!path_exists(partPath)) {
+                    if (path_empty_file(partPath) < 0) {
+                        PANIC("Could not create cache image file %s: %s", partPath, strerror(errno));
+                    }
+                }
+                pstrcat(tmp, sizeof(tmp), ",file=");
+                pstrcat(tmp, sizeof(tmp), partPath);
+            }
+        }
+        nand_add_dev(tmp);
+    }
+
+    /* We always force qemu=1 when running inside QEMU */
+    stralloc_add_str(kernel_params, " qemu=1");
+
+    /* We always initialize the first serial port for the android-kmsg
+     * character device (used to send kernel messages) */
+    serial_hds_add_at(0, "android-kmsg");
+    stralloc_add_str(kernel_params, " console=ttyS0");
+
+    /* We always initialize the second serial port for the android-qemud
+     * character device as well */
+    serial_hds_add_at(1, "android-qemud");
+    stralloc_add_str(kernel_params, " android.qemud=ttyS1");
+
 #if defined(CONFIG_KVM) && defined(CONFIG_KQEMU)
     if (kvm_allowed && kqemu_allowed) {
         PANIC(
@@ -4891,6 +5355,14 @@
     if (qemu_init_main_loop()) {
         PANIC("qemu_init_main_loop failed");
     }
+
+    if (kernel_filename == NULL) {
+        kernel_filename = android_hw->kernel_path;
+    }
+    if (initrd_filename == NULL) {
+        initrd_filename = android_hw->disk_ramdisk_path;
+    }
+
     linux_boot = (kernel_filename != NULL);
     net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
 
@@ -4968,8 +5440,12 @@
         }
 
     /* init the memory */
-    if (ram_size == 0)
-        ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
+    if (ram_size == 0) {
+        ram_size = android_hw->hw_ramSize * 1024LL * 1024;
+        if (ram_size == 0) {
+            ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
+        }
+    }
 
 #ifdef CONFIG_KQEMU
     /* FIXME: This is a nasty hack because kqemu can't cope with dynamic
@@ -4983,6 +5459,10 @@
     }
 #endif
 
+#ifndef _WIN32
+    init_qemu_clear_logs_sig();
+#endif
+
     /* init the dynamic translator */
     cpu_exec_init_all(tb_size * 1024 * 1024);
 
@@ -5093,16 +5573,7 @@
     }
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
-        const char *devname = serial_devices[i];
-        if (devname && strcmp(devname, "none")) {
-            char label[32];
-            snprintf(label, sizeof(label), "serial%d", i);
-            serial_hds[i] = qemu_chr_open(label, devname, NULL);
-            if (!serial_hds[i]) {
-                PANIC("qemu: could not open serial device '%s'",
-                        devname);
-            }
-        }
+        serial_hds_add(serial_devices[i]);
     }
 
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
@@ -5149,21 +5620,45 @@
 #endif
 
     /* Combine kernel command line passed from the UI with parameters
-     * collected during initialization. */
-    if (*kernel_cmdline) {
-        if (kernel_cmdline_append[0]) {
-            snprintf(kernel_cmdline_full, sizeof(kernel_cmdline_full), "%s %s",
-                     kernel_cmdline, kernel_cmdline_append);
-        } else {
-            strncpy(kernel_cmdline_full, kernel_cmdline, sizeof(kernel_cmdline_full));
-            kernel_cmdline_full[sizeof(kernel_cmdline_full) - 1] = '\0';
-        }
-    } else if (kernel_cmdline_append[0]) {
-        strncpy(kernel_cmdline_full, kernel_cmdline_append, sizeof(kernel_cmdline_full));
-    }
+     * collected during initialization.
+     *
+     * The order is the following:
+     * - parameters from the hw configuration (kernel.parameters)
+     * - additionnal parameters from options (e.g. -memcheck)
+     * - the -append parameters.
+     */
+    {
+        const char* kernel_parameters;
 
-    machine->init(ram_size, boot_devices,
-                  kernel_filename, kernel_cmdline_full, initrd_filename, cpu_model);
+        if (android_hw->kernel_parameters) {
+            stralloc_add_c(kernel_params, ' ');
+            stralloc_add_str(kernel_params, android_hw->kernel_parameters);
+        }
+
+        /* If not empty, kernel_config always contains a leading space */
+        stralloc_append(kernel_params, kernel_config);
+
+        if (*kernel_cmdline) {
+            stralloc_add_c(kernel_params, ' ');
+            stralloc_add_str(kernel_params, kernel_cmdline);
+        }
+
+        /* Remove any leading/trailing spaces */
+        stralloc_strip(kernel_params);
+
+        kernel_parameters = stralloc_cstr(kernel_params);
+        VERBOSE_PRINT(init, "Kernel parameters: %s", kernel_parameters);
+
+        machine->init(ram_size,
+                      boot_devices,
+                      kernel_filename,
+                      kernel_parameters,
+                      initrd_filename,
+                      cpu_model);
+
+        stralloc_reset(kernel_params);
+        stralloc_reset(kernel_config);
+    }
 
 
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
@@ -5199,16 +5694,11 @@
     /* just use the first displaystate for the moment */
     ds = get_displaystate();
 
-    if (android_op_gui) {
-        /* Initialize display from the command line parameters. */
-        android_display_reset(ds,
-                              android_display_width,
-                              android_display_height,
-                              android_display_bpp);
-    } else {
-        /* By default, use 320x480x16 */
-        android_display_reset(ds, 320, 480, 16);
-    }
+    /* Initialize display from the command line parameters. */
+    android_display_reset(ds,
+                          android_display_width,
+                          android_display_height,
+                          android_display_bpp);
 
     if (display_type == DT_DEFAULT) {
 #if defined(CONFIG_SDL) || defined(CONFIG_COCOA)