aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.android11
-rw-r--r--Makefile.common59
-rw-r--r--Makefile.target4
-rw-r--r--android/avd/hw-config-defs.h305
-rw-r--r--android/avd/info.c25
-rw-r--r--android/avd/info.h7
-rw-r--r--android/avd/util.c18
-rw-r--r--android/avd/util.h10
-rw-r--r--android/build/binary.make5
-rw-r--r--android/build/common.sh4
-rw-r--r--android/build/definitions.make13
-rw-r--r--android/hw-pipe-net.c76
-rw-r--r--android/hw-qemud.c470
-rw-r--r--android/main-common.c2
-rw-r--r--android/main.c26
-rw-r--r--android/skin/window.c6
-rw-r--r--android/utils/setenv.c18
-rw-r--r--docs/ANDROID-QEMUD.TXT17
-rw-r--r--images/android_icon.icobin300318 -> 56119 bytes
-rw-r--r--images/android_icon_16.pngbin460 -> 1760 bytes
-rw-r--r--images/android_icon_256.pngbin13369 -> 39249 bytes
-rw-r--r--images/android_icon_32.pngbin1321 -> 2965 bytes
-rw-r--r--vl-android.c4
23 files changed, 652 insertions, 428 deletions
diff --git a/Makefile.android b/Makefile.android
index 4139226..01cb35b 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -55,7 +55,7 @@ ifeq ($(HOST_OS),freebsd)
endif
ifeq ($(HOST_OS),windows)
- MY_CFLAGS += -D_WIN32 -mno-cygwin
+ MY_CFLAGS += -D_WIN32
# we need Win32 features that are available since Windows 2000 Professional/Server (NT 5.0)
MY_CFLAGS += -DWINVER=0x501
endif
@@ -149,17 +149,17 @@ start-emulator-library = \
$(eval LOCAL_LDLIBS := $(MY_LDLIBS)) \
$(eval LOCAL_MODULE_TAGS := debug) \
$(eval LOCAL_MODULE := $1) \
+ $(eval LOCAL_MODULE_CLASS := STATIC_LIBRARIES)
# Used with start-emulator-library
end-emulator-library = \
- $(eval include $(BUILD_HOST_STATIC_LIBRARY)) \
- $(eval EMULATOR_MODULE_TYPE := STATIC_LIBRARY)
+ $(eval include $(BUILD_HOST_STATIC_LIBRARY))
# 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) \
- $(eval EMULATOR_MODULE_TYPE := EXECUTABLES)
+ $(eval LOCAL_MODULE_CLASS := EXECUTABLES)
# A varient of end-emulator-library for host programs instead
end-emulator-program = \
@@ -242,6 +242,7 @@ LOCAL_SRC_FILES := \
android/snapshot.c \
android/main-common.c \
android/main.c \
+ android/utils/setenv.c \
vl-android-ui.c \
android/protocol/core-connection.c \
android/protocol/attach-ui-impl.c \
@@ -250,6 +251,8 @@ LOCAL_SRC_FILES := \
android/protocol/core-commands-proxy.c \
android/protocol/user-events-proxy.c \
+$(call gen-hw-config-defs,android/main-common.c)
+
LOCAL_SRC_FILES += $(SDLMAIN_SOURCES)
LOCAL_STATIC_LIBRARIES += $(SDL_STATIC_LIBRARIES)
diff --git a/Makefile.common b/Makefile.common
index 222a1ae..93f15be 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -13,6 +13,42 @@
##############################################################################
##############################################################################
###
+### gen-hw-config-defs: Generate hardware configuration definitions header
+###
+### The 'gen-hw-config.py' script is used to generate the hw-config-defs.h
+### header from the an .ini file like android/avd/hardware-properties.ini
+###
+### 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-hw-config-defs)
+###
+
+# First, define a rule to generate a dummy "emulator_hw_config_defs" module
+# which purpose is simply to host the generated header in its output directory.
+intermediates := $(call intermediates-dir-for,SHARED_LIBRARIES,emulator_hw_config_defs,true)
+
+QEMU_HARDWARE_PROPERTIES_INI := $(LOCAL_PATH)/android/avd/hardware-properties.ini
+QEMU_HW_CONFIG_DEFS_H := $(intermediates)/android/avd/hw-config-defs.h
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_PATH := $(LOCAL_PATH)
+$(QEMU_HW_CONFIG_DEFS_H): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/android/tools/gen-hw-config.py $< $@
+$(QEMU_HW_CONFIG_DEFS_H): $(QEMU_HARDWARE_PROPERTIES_INI) $(LOCAL_PATH)/android/tools/gen-hw-config.py
+ $(hide) rm -f $@
+ $(transform-generated-source)
+
+QEMU_HW_CONFIG_DEFS_INCLUDES := $(intermediates)
+
+# Second, define a function that needs to be called inside each module that contains
+# a source file that includes the generated header file.
+gen-hw-config-defs = \
+ $(eval LOCAL_GENERATED_SOURCES += $(QEMU_HW_CONFIG_DEFS_H))\
+ $(eval LOCAL_C_INCLUDES += $(QEMU_HW_CONFIG_DEFS_INCLUDES))
+
+##############################################################################
+##############################################################################
+###
### emulator-common: LIBRARY OF COMMON FUNCTIONS
###
### THESE ARE POTENTIALLY USED BY ALL COMPONENTS
@@ -90,6 +126,8 @@ LOCAL_SRC_FILES += \
android/utils/tempfile.c \
android/utils/vector.c \
+$(call gen-hw-config-defs)
+
LOCAL_CFLAGS += $(EMULATOR_COMMON_CFLAGS)
$(call end-emulator-library)
@@ -215,6 +253,8 @@ LOCAL_SRC_FILES += \
android/qemulator.c \
android/keycode.c \
+$(call gen-hw-config-defs)
+
# enable MMX code for our skin scaler
ifeq ($(HOST_ARCH),x86)
LOCAL_CFLAGS += -DUSE_MMX=1 -mmmx
@@ -383,6 +423,8 @@ CORE_MISC_SOURCES = \
android/snapshot.c \
android/utils/timezone.c \
+$(call gen-hw-config-defs)
+
ifeq ($(HOST_ARCH),x86)
CORE_MISC_SOURCES += i386-dis.c
endif
@@ -475,19 +517,6 @@ LOCAL_SRC_FILES += \
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.
#
@@ -603,7 +632,7 @@ $(call end-emulator-library)
gen-hx-header = $(eval $(call gen-hx-header-ev,$1,$2,$3))
define gen-hx-header-ev
-intermediates := $$(call intermediates-dir-for,$$(EMULATOR_MODULE_TYPE),$$(LOCAL_MODULE),true)
+intermediates := $$(call intermediates-dir-for,$$(LOCAL_MODULE_CLASS),$$(LOCAL_MODULE),true)
QEMU_HEADER_H := $$(intermediates)/$$2
$$(QEMU_HEADER_H): PRIVATE_PATH := $$(LOCAL_PATH)
@@ -613,7 +642,5 @@ $$(QEMU_HEADER_H): $$(LOCAL_PATH)/$$1 $$(LOCAL_PATH)/hxtool
LOCAL_GENERATED_SOURCES += $$(QEMU_HEADER_H)
LOCAL_C_INCLUDES += $$(intermediates)
-_objects := $$(patsubst %,$$(intermediates)/%,$$(3:.c=.o))
-$$(_objects): $$(QEMU_HEADER_H)
endef
diff --git a/Makefile.target b/Makefile.target
index 5f7a8b2..ccc86b4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -86,6 +86,8 @@ HW_SOURCES := \
usb.c \
watchdog.c
+$(call gen-hw-config-defs)
+
ifeq ($(EMULATOR_TARGET_ARCH),arm)
HW_SOURCES += android_arm.c \
arm_pic.c \
@@ -277,6 +279,7 @@ LOCAL_SRC_FILES := \
$(call gen-hx-header,qemu-monitor.hx,qemu-monitor.h,monitor.c)
$(call gen-hx-header,qemu-options.hx,qemu-options.def,vl-android.c qemu-options.h)
+$(call gen-hw-config-defs)
ifeq ($(HOST_OS),darwin)
FRAMEWORKS := OpenGL Cocoa QuickTime ApplicationServices Carbon IOKit
@@ -356,6 +359,7 @@ LOCAL_SRC_FILES := \
$(call gen-hx-header,qemu-monitor.hx,qemu-monitor.h,monitor.c)
$(call gen-hx-header,qemu-options.hx,qemu-options.def,vl-android.c qemu-options.h)
+$(call gen-hw-config-defs)
# The following files cannot be in static libraries because they contain
# constructor functions that are otherwise stripped by the final linker
diff --git a/android/avd/hw-config-defs.h b/android/avd/hw-config-defs.h
deleted file mode 100644
index bb523d5..0000000
--- a/android/avd/hw-config-defs.h
+++ /dev/null
@@ -1,305 +0,0 @@
-/* this file is automatically generated from 'hardware-properties.ini'
- * DO NOT EDIT IT. To re-generate it, use android/tools/gen-hw-config.py'
- */
-#ifndef HWCFG_INT
-#error HWCFG_INT not defined
-#endif
-#ifndef HWCFG_BOOL
-#error HWCFG_BOOL not defined
-#endif
-#ifndef HWCFG_DISKSIZE
-#error HWCFG_DISKSIZE not defined
-#endif
-#ifndef HWCFG_STRING
-#error HWCFG_STRING not defined
-#endif
-#ifndef HWCFG_DOUBLE
-#error HWCFG_DOUBLE not defined
-#endif
-
-HWCFG_STRING(
- hw_cpu_arch,
- "hw.cpu.arch",
- "arm",
- "CPU Architecture",
- "The CPU Architecture to emulator")
-
-HWCFG_STRING(
- hw_cpu_model,
- "hw.cpu.model",
- "",
- "CPU model",
- "The CPU model (QEMU-specific string)")
-
-HWCFG_INT(
- hw_ramSize,
- "hw.ramSize",
- 0,
- "Device ram size",
- "The amount of physical RAM on the device, in megabytes.")
-
-HWCFG_BOOL(
- hw_touchScreen,
- "hw.touchScreen",
- "yes",
- "Touch-screen support",
- "Whether there is a touch screen or not on the device.")
-
-HWCFG_BOOL(
- hw_trackBall,
- "hw.trackBall",
- "yes",
- "Track-ball support",
- "Whether there is a trackball on the device.")
-
-HWCFG_BOOL(
- hw_keyboard,
- "hw.keyboard",
- "yes",
- "Keyboard support",
- "Whether the device has a QWERTY keyboard.")
-
-HWCFG_BOOL(
- hw_keyboard_lid,
- "hw.keyboard.lid",
- "yes",
- "Keyboard lid support",
- "Whether the QWERTY keyboard can be opened/closed.")
-
-HWCFG_BOOL(
- hw_dPad,
- "hw.dPad",
- "yes",
- "DPad support",
- "Whether the device has DPad keys")
-
-HWCFG_BOOL(
- hw_gsmModem,
- "hw.gsmModem",
- "yes",
- "GSM modem support",
- "Whether there is a GSM modem in the device.")
-
-HWCFG_BOOL(
- hw_camera,
- "hw.camera",
- "no",
- "Camera support",
- "Whether the device has a camera.")
-
-HWCFG_INT(
- hw_camera_maxHorizontalPixels,
- "hw.camera.maxHorizontalPixels",
- 640,
- "Maximum horizontal camera pixels",
- "")
-
-HWCFG_INT(
- hw_camera_maxVerticalPixels,
- "hw.camera.maxVerticalPixels",
- 480,
- "Maximum vertical camera pixels",
- "")
-
-HWCFG_BOOL(
- hw_gps,
- "hw.gps",
- "yes",
- "GPS support",
- "Whether there is a GPS in the device.")
-
-HWCFG_BOOL(
- hw_battery,
- "hw.battery",
- "yes",
- "Battery support",
- "Whether the device can run on a battery.")
-
-HWCFG_BOOL(
- hw_accelerometer,
- "hw.accelerometer",
- "yes",
- "Accelerometer",
- "Whether there is an accelerometer in the device.")
-
-HWCFG_BOOL(
- hw_audioInput,
- "hw.audioInput",
- "yes",
- "Audio recording support",
- "Whether the device can record audio")
-
-HWCFG_BOOL(
- hw_audioOutput,
- "hw.audioOutput",
- "yes",
- "Audio playback support",
- "Whether the device can play audio")
-
-HWCFG_BOOL(
- hw_sdCard,
- "hw.sdCard",
- "yes",
- "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",
- "yes",
- "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",
- "66MB",
- "Cache partition size",
- "")
-
-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,
- "Abstracted LCD density",
- "Must be one of 120, 160 or 240. A value used to roughly describe the density of the LCD screen for automatic resource/asset selection.")
-
-HWCFG_BOOL(
- hw_lcd_backlight,
- "hw.lcd.backlight",
- "yes",
- "LCD backlight",
- "Enable/Disable LCD backlight simulation,yes-enabled,no-disabled.")
-
-HWCFG_INT(
- vm_heapSize,
- "vm.heapSize",
- 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.")
-
-HWCFG_BOOL(
- hw_sensors_proximity,
- "hw.sensors.proximity",
- "yes",
- "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
-#undef HWCFG_STRING
-#undef HWCFG_DOUBLE
-/* end of auto-generated file */
diff --git a/android/avd/info.c b/android/avd/info.c
index 1ab066c..f1514f2 100644
--- a/android/avd/info.c
+++ b/android/avd/info.c
@@ -886,9 +886,20 @@ avdInfo_getKernelPath( AvdInfo* i )
* for our target architecture.
*/
char temp[PATH_MAX], *p = temp, *end = p + sizeof(temp);
+ const char* suffix = "";
+ char* abi;
+
+ /* If the target ABI is armeabi-v7a, then look for
+ * kernel-qemu-armv7 instead of kernel-qemu in the prebuilt
+ * directory. */
+ abi = path_getBuildTargetAbi(i->androidOut);
+ if (!strcmp(abi,"armeabi-v7a")) {
+ suffix = "-armv7";
+ }
+ AFREE(abi);
- p = bufprint(temp, end, "%s/prebuilt/android-%s/kernel/kernel-qemu",
- i->androidBuildRoot, i->targetArch);
+ p = bufprint(temp, end, "%s/prebuilt/android-%s/kernel/kernel-qemu%s",
+ i->androidBuildRoot, i->targetArch, suffix);
if (p >= end || !path_exists(temp)) {
derror("bad workspace: cannot find prebuilt kernel in: %s", temp);
exit(1);
@@ -1024,6 +1035,16 @@ avdInfo_inAndroidBuild( AvdInfo* i )
}
char*
+avdInfo_getTargetAbi( AvdInfo* i )
+{
+ /* For now, we can't get the ABI from SDK AVDs */
+ if (!i->inAndroidBuild)
+ return NULL;
+
+ return path_getBuildTargetAbi(i->androidOut);
+}
+
+char*
avdInfo_getTracePath( AvdInfo* i, const char* traceName )
{
char tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
diff --git a/android/avd/info.h b/android/avd/info.h
index 2469f68..5192bb9 100644
--- a/android/avd/info.h
+++ b/android/avd/info.h
@@ -218,6 +218,13 @@ void avdInfo_getSkinInfo( AvdInfo* i, char** pSkinName, char** pSkinDir
/* Returns TRUE iff in the Android build system */
int avdInfo_inAndroidBuild( AvdInfo* i );
+/* Returns the target ABI for the corresponding platform image.
+ * This may return NULL if it cannot be determined. Otherwise this is
+ * a string like "armeabi", "armeabi-v7a" or "x86" that must be freed
+ * by the caller.
+ */
+char* avdInfo_getTargetAbi( AvdInfo* i );
+
/* Reads the AVD's hardware configuration into 'hw'. returns -1 on error, 0 otherwise */
int avdInfo_initHwConfig( AvdInfo* i, AndroidHwConfig* hw );
diff --git a/android/avd/util.c b/android/avd/util.c
index 2ba4117..304b98f 100644
--- a/android/avd/util.c
+++ b/android/avd/util.c
@@ -264,6 +264,24 @@ path_getBuildTargetArch( const char* androidOut )
return result;
}
+char*
+path_getBuildTargetAbi( const char* androidOut )
+{
+ const char* defaultAbi = "armeabi";
+ char* result = NULL;
+ char* cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi");
+
+ if (cpuAbi == NULL) {
+ D("Coult not find CPU ABI in build properties!");
+ D("Default target ABI: %s", defaultAbi);
+ result = ASTRDUP(defaultAbi);
+ } else {
+ D("Found target ABI=%s", cpuAbi);
+ result = cpuAbi;
+ }
+ return result;
+}
+
int
path_getBuildTargetApiLevel( const char* androidOut )
diff --git a/android/avd/util.h b/android/avd/util.h
index 27f8f28..877d5aa 100644
--- a/android/avd/util.h
+++ b/android/avd/util.h
@@ -48,6 +48,16 @@ char* path_getAvdTargetArch( const char* avdName );
*/
char* path_getBuildTargetArch( const char* androidOut );
+/* Retrieves a string corresponding to the target CPU ABI
+ * when in the Android platform tree. The only way to do that
+ * properly for now is to look at $OUT/system/build.prop:
+ *
+ * ro.product.cpu-abi=<abi>
+ *
+ * Where <abi> can be 'armeabi', 'armeabi-v7a' or 'x86'.
+ */
+char* path_getBuildTargetAbi( const char* androidOut );
+
/* Retrieve the target API level when in the Android platform tree.
* This can be a very large number like 1000 if the value cannot
* be extracted from the appropriate file
diff --git a/android/build/binary.make b/android/build/binary.make
index f6542dc..3bc4fe9 100644
--- a/android/build/binary.make
+++ b/android/build/binary.make
@@ -25,6 +25,8 @@ LOCAL_GENERATED_C_SOURCES := $(filter %.c,$(LOCAL_GENERATED_SOURCES))
LOCAL_CXX_SOURCES := $(filter %$(LOCAL_CPP_EXTENSION),$(LOCAL_SRC_FILES) $(LOCAL_GENERATED_SOURCES))
LOCAL_OBJC_SOURCES := $(filter %.m,$(LOCAL_SRC_FILES) $(LOCAL_GENERATED_SOURCES))
+LOCAL_CFLAGS := $(strip $(patsubst %,-I%,$(LOCAL_C_INCLUDES)) $(LOCAL_CFLAGS))
+
$(foreach src,$(LOCAL_C_SOURCES), \
$(eval $(call compile-c-source,$(src))) \
)
@@ -41,4 +43,7 @@ $(foreach src,$(LOCAL_OBJC_SOURCES), \
$(eval $(call compile-objc-source,$(src))) \
)
+# Ensure that we build all generated sources before the objects
+$(LOCAL_OBJECTS): | $(LOCAL_GENERATED_SOURCES)
+
CLEAN_OBJS_DIRS += $(LOCAL_OBJS_DIR)
diff --git a/android/build/common.sh b/android/build/common.sh
index 050fd90..de4e3c1 100644
--- a/android/build/common.sh
+++ b/android/build/common.sh
@@ -457,11 +457,11 @@ check_android_build ()
unset ANDROID_TOP
IN_ANDROID_BUILD=no
- if [ -z "$ANDROID_PRODUCT_OUT" ] ; then
+ if [ -z "$ANDROID_BUILD_TOP" ] ; then
return ;
fi
- ANDROID_TOP=`cd $ANDROID_PRODUCT_OUT/../../../.. && pwd`
+ ANDROID_TOP=$ANDROID_BUILD_TOP
log "ANDROID_TOP found at $ANDROID_TOP"
# $ANDROID_TOP/config/envsetup.make is for the old tree layout
# $ANDROID_TOP/build/envsetup.sh is for the new one
diff --git a/android/build/definitions.make b/android/build/definitions.make
index e31131b..ddf9150 100644
--- a/android/build/definitions.make
+++ b/android/build/definitions.make
@@ -13,6 +13,19 @@
# limitations under the License.
#
+# this turns off the suffix rules built into make
+.SUFFIXES:
+
+# this turns off the RCS / SCCS implicit rules of GNU Make
+% : RCS/%,v
+% : RCS/%
+% : %,v
+% : s.%
+% : SCCS/s.%
+
+# If a rule fails, delete $@.
+.DELETE_ON_ERROR:
+
# shared definitions
ifeq ($(strip $(SHOW)),)
define pretty
diff --git a/android/hw-pipe-net.c b/android/hw-pipe-net.c
index d83d8b1..dade446 100644
--- a/android/hw-pipe-net.c
+++ b/android/hw-pipe-net.c
@@ -68,7 +68,7 @@ typedef struct {
int wakeWanted;
LoopIo io[1];
AsyncConnector connector[1];
-
+ int shouldSetSocketOpt;
} NetPipe;
static void
@@ -192,6 +192,7 @@ netPipe_initFromAddress( void* hwpipe, const SockAddress* address, Looper* loop
pipe->hwpipe = hwpipe;
pipe->state = STATE_INIT;
+ pipe->shouldSetSocketOpt = 0;
{
AsyncStatus status;
@@ -245,13 +246,26 @@ netPipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuf
const GoldfishPipeBuffer* buff = buffers;
const GoldfishPipeBuffer* buffEnd = buff + numBuffers;
+#ifdef _WIN32
+ if (pipe->shouldSetSocketOpt == 1) {
+ int sndbuf = 128 * 1024;
+ int len = sizeof(sndbuf);
+ if (setsockopt(pipe->io->fd, SOL_SOCKET, SO_SNDBUF,
+ (char*)&sndbuf, len) == SOCKET_ERROR) {
+ D("Failed to set SO_SNDBUF to %d error=0x%x\n",
+ sndbuf, WSAGetLastError());
+ }
+ pipe->shouldSetSocketOpt = 0;
+ }
+#endif
+
for (; buff < buffEnd; buff++)
count += buff->size;
buff = buffers;
while (count > 0) {
int avail = buff->size - buffStart;
- int len = write(pipe->io->fd, buff->data + buffStart, avail);
+ int len = socket_send(pipe->io->fd, buff->data + buffStart, avail);
/* the write succeeded */
if (len > 0) {
@@ -272,10 +286,6 @@ netPipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuf
break;
}
- /* loop on EINTR */
- if (errno == EINTR)
- continue;
-
/* if we already wrote some stuff, simply return */
if (ret > 0) {
break;
@@ -309,7 +319,7 @@ netPipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers
buff = buffers;
while (count > 0) {
int avail = buff->size - buffStart;
- int len = read(pipe->io->fd, buff->data + buffStart, avail);
+ int len = socket_recv(pipe->io->fd, buff->data + buffStart, avail);
/* the read succeeded */
if (len > 0) {
@@ -330,10 +340,6 @@ netPipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers
break;
}
- /* loop on EINTR */
- if (errno == EINTR)
- continue;
-
/* if we already read some stuff, simply return */
if (ret > 0) {
break;
@@ -381,40 +387,17 @@ void*
netPipe_initTcp( void* hwpipe, void* _looper, const char* args )
{
/* Build SockAddress from arguments. Acceptable formats are:
- *
* <port>
- * <host>:<port>
*/
SockAddress address;
+ uint16_t port;
void* ret;
if (args == NULL) {
D("%s: Missing address!", __FUNCTION__);
return NULL;
}
- D("%s: Address is '%s'", __FUNCTION__, args);
-
- char host[256]; /* max size of regular FDQN+1 */
- int hostlen = 0;
- int port;
- const char* p;
-
- /* Assume that anything after the last ':' is a port number
- * And that what is before it is a port number. Should handle IPv6
- * notation. */
- p = strrchr(args, ':');
- if (p != NULL) {
- hostlen = p - args;
- if (hostlen >= sizeof(host)) {
- D("%s: Address too long!", __FUNCTION__);
- return NULL;
- }
- memcpy(host, args, hostlen);
- host[hostlen] = '\0';
- args = p + 1;
- } else {
- snprintf(host, sizeof host, "127.0.0.1");
- }
+ D("%s: Port is '%s'", __FUNCTION__, args);
/* Now, look at the port number */
{
@@ -423,12 +406,9 @@ netPipe_initTcp( void* hwpipe, void* _looper, const char* args )
if (end == NULL || *end != '\0' || val <= 0 || val > 65535) {
D("%s: Invalid port number: '%s'", __FUNCTION__, args);
}
- port = (int)val;
- }
- if (sock_address_init_resolve(&address, host, port, 0) < 0) {
- D("%s: Could not resolve address", __FUNCTION__);
- return NULL;
+ port = (uint16_t)val;
}
+ sock_address_init_inet(&address, SOCK_ADDRESS_INET_LOOPBACK, port);
ret = netPipe_initFromAddress(hwpipe, &address, _looper);
@@ -436,6 +416,7 @@ netPipe_initTcp( void* hwpipe, void* _looper, const char* args )
return ret;
}
+#ifndef _WIN32
void*
netPipe_initUnix( void* hwpipe, void* _looper, const char* args )
{
@@ -459,7 +440,7 @@ netPipe_initUnix( void* hwpipe, void* _looper, const char* args )
sock_address_done(&address);
return ret;
}
-
+#endif
/**********************************************************************
**********************************************************************
@@ -477,6 +458,7 @@ static const GoldfishPipeFuncs netPipeTcp_funcs = {
netPipe_wakeOn,
};
+#ifndef _WIN32
static const GoldfishPipeFuncs netPipeUnix_funcs = {
netPipe_initUnix,
netPipe_closeFromGuest,
@@ -485,7 +467,7 @@ static const GoldfishPipeFuncs netPipeUnix_funcs = {
netPipe_poll,
netPipe_wakeOn,
};
-
+#endif
#define DEFAULT_OPENGLES_PORT 22468
@@ -493,10 +475,14 @@ static void*
openglesPipe_init( void* hwpipe, void* _looper, const char* args )
{
char temp[32];
+ NetPipe *pipe;
/* For now, simply connect through tcp */
snprintf(temp, sizeof temp, "%d", DEFAULT_OPENGLES_PORT);
- return netPipe_initTcp(hwpipe, _looper, temp);
+ pipe = (NetPipe *)netPipe_initTcp(hwpipe, _looper, temp);
+ pipe->shouldSetSocketOpt = 1;
+
+ return pipe;
}
static const GoldfishPipeFuncs openglesPipe_funcs = {
@@ -515,6 +501,8 @@ android_net_pipes_init(void)
Looper* looper = looper_newCore();
goldfish_pipe_add_type( "tcp", looper, &netPipeTcp_funcs );
+#ifndef _WIN32
goldfish_pipe_add_type( "unix", looper, &netPipeUnix_funcs );
+#endif
goldfish_pipe_add_type( "opengles", looper, &openglesPipe_funcs );
}
diff --git a/android/hw-qemud.c b/android/hw-qemud.c
index e91ec78..9bfeaff 100644
--- a/android/hw-qemud.c
+++ b/android/hw-qemud.c
@@ -14,7 +14,9 @@
#include "android/utils/misc.h"
#include "android/utils/system.h"
#include "android/utils/bufprint.h"
+#include "android/looper.h"
#include "hw/hw.h"
+#include "hw/goldfish_pipe.h"
#include "qemu-char.h"
#include "charpipe.h"
#include "cbuffer.h"
@@ -575,18 +577,54 @@ qemud_serial_send( QemudSerial* s,
/** CLIENTS
**/
+/* Descriptor for a data buffer pending to be sent to a qemud pipe client.
+ *
+ * When a service decides to send data to the client, there could be cases when
+ * client is not ready to read them. In this case there is no GoldfishPipeBuffer
+ * available to write service's data to, So, we need to cache that data into the
+ * client descriptor, and "send" them over to the client in _qemudPipe_recvBuffers
+ * callback. Pending service data is stored in the client descriptor as a list
+ * of QemudPipeMessage instances.
+ */
+typedef struct QemudPipeMessage QemudPipeMessage;
+struct QemudPipeMessage {
+ /* Message to send. */
+ uint8_t* message;
+ /* Message size. */
+ size_t size;
+ /* Offset in the message buffer of the chunk, that has not been sent
+ * to the pipe yet. */
+ size_t offset;
+ /* Links next message in the client. */
+ QemudPipeMessage* next;
+};
+
+
/* A QemudClient models a single client as seen by the emulator.
- * Each client has its own channel id, and belongs to a given
- * QemudService (see below).
+ * Each client has its own channel id (for the serial qemud), or pipe descriptor
+ * (for the pipe based qemud), and belongs to a given QemudService (see below).
*
- * There is a global list of clients used to multiplex incoming
- * messages from the channel id (see qemud_multiplexer_serial_recv()).
+ * There is a global list of serial clients used to multiplex incoming
+ * messages from the channel id (see qemud_multiplexer_serial_recv()). Pipe
+ * clients don't need multiplexing, because they are communicated via qemud pipes
+ * that are unique for each client.
*
*/
+/* Defines type of the client: pipe, or serial.
+ */
+typedef enum QemudProtocol {
+ /* Client is communicating via pipe. */
+ QEMUD_PROTOCOL_PIPE,
+ /* Client is communicating via serial port. */
+ QEMUD_PROTOCOL_SERIAL
+} QemudProtocol;
+
struct QemudClient {
- int channel;
- QemudSerial* serial;
+ /* Defines protocol, used by the client. */
+ QemudProtocol protocol;
+
+ /* Fields that are common for all protocols. */
void* clie_opaque;
QemudClientRecv clie_recv;
QemudClientClose clie_close;
@@ -604,8 +642,28 @@ struct QemudClient {
QemudSink header[1];
uint8_t header0[FRAME_HEADER_SIZE];
QemudSink payload[1];
+
+ /* Fields that are protocol-specific. */
+ union {
+ /* Serial-specific fields. */
+ struct {
+ int channel;
+ QemudSerial* serial;
+ } Serial;
+ /* Pipe-specific fields. */
+ struct {
+ void* hwpipe;
+ QemudPipeMessage* messages;
+ } Pipe;
+ } ProtocolSelector;
};
+static ABool
+_is_pipe_client(QemudClient* client)
+{
+ return (client-> protocol == QEMUD_PROTOCOL_PIPE) ? true : false;
+}
+
static void qemud_service_remove_client( QemudService* service,
QemudClient* client );
@@ -716,6 +774,11 @@ qemud_client_recv( void* opaque, uint8_t* msg, int msglen )
}
}
+/* Sends data to a pipe-based client.
+ */
+static void
+_qemud_pipe_send(QemudClient* client, const uint8_t* msg, int msglen);
+
/* disconnect a client. this automatically frees the QemudClient.
* note that this also removes the client from the global list
* and from its service's list, if any.
@@ -734,10 +797,15 @@ qemud_client_disconnect( void* opaque )
qemud_client_remove(c);
/* send a disconnect command to the daemon */
- if (c->channel > 0) {
+ if (_is_pipe_client(c)) {
char tmp[128], *p=tmp, *end=p+sizeof(tmp);
- p = bufprint(tmp, end, "disconnect:%02x", c->channel);
- qemud_serial_send(c->serial, 0, 0, (uint8_t*)tmp, p-tmp);
+ p = bufprint(tmp, end, "disconnect:00");
+ _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
+ } else if (c->ProtocolSelector.Serial.channel > 0) {
+ char tmp[128], *p=tmp, *end=p+sizeof(tmp);
+ p = bufprint(tmp, end, "disconnect:%02x",
+ c->ProtocolSelector.Serial.channel);
+ qemud_serial_send(c->ProtocolSelector.Serial.serial, 0, 0, (uint8_t*)tmp, p-tmp);
}
/* call the client close callback */
@@ -756,7 +824,10 @@ qemud_client_disconnect( void* opaque )
AFREE(c);
}
-/* allocate a new QemudClient object */
+/* allocate a new QemudClient object
+ * NOTE: channel_id valie is used as a selector between serial and pipe clients.
+ * Since channel_id < 0 is an invalid value for a serial client, it would
+ * indicate that creating client is a pipe client. */
static QemudClient*
qemud_client_alloc( int channel_id,
void* clie_opaque,
@@ -771,14 +842,25 @@ qemud_client_alloc( int channel_id,
ANEW0(c);
- c->serial = serial;
- c->channel = channel_id;
+ if (channel_id < 0) {
+ /* Allocating a pipe client. */
+ c->protocol = QEMUD_PROTOCOL_PIPE;
+ c->ProtocolSelector.Pipe.messages = NULL;
+ c->ProtocolSelector.Pipe.hwpipe = NULL;
+ } else {
+ /* Allocating a serial client. */
+ c->protocol = QEMUD_PROTOCOL_SERIAL;
+ c->ProtocolSelector.Serial.serial = serial;
+ c->ProtocolSelector.Serial.channel = channel_id;
+ }
c->clie_opaque = clie_opaque;
c->clie_recv = clie_recv;
c->clie_close = clie_close;
c->clie_save = clie_save;
c->clie_load = clie_load;
-
+ c->service = NULL;
+ c->next_serv = NULL;
+ c->next = NULL;
c->framing = 0;
c->need_header = 1;
qemud_sink_reset(c->header, FRAME_HEADER_SIZE, c->header0);
@@ -794,7 +876,7 @@ static char* qemud_service_load_name( QEMUFile* f );
static QemudService* qemud_service_find( QemudService* service_list,
const char* service_name );
static QemudClient* qemud_service_connect_client( QemudService *sv,
- int channel_id );
+ int channel_id);
/* Saves the client state needed to re-establish connections on load.
*/
@@ -803,7 +885,10 @@ qemud_client_save(QEMUFile* f, QemudClient* c)
{
/* save generic information */
qemud_service_save_name(f, c->service);
- qemu_put_be32(f, c->channel);
+ qemu_put_be32(f, c->protocol);
+ if (_is_pipe_client(c)) {
+ qemu_put_be32(f, c->ProtocolSelector.Serial.channel);
+ }
/* save client-specific state */
if (c->clie_save)
@@ -840,8 +925,13 @@ qemud_client_load(QEMUFile* f, QemudService* current_services )
return -EIO;
}
+ /* get protocol. */
+ QemudProtocol protocol = qemu_get_be32(f);
/* get channel id */
- int channel = qemu_get_be32(f);
+ int channel = -1;
+ if (protocol == QEMUD_PROTOCOL_SERIAL) {
+ qemu_get_be32(f);
+ }
if (channel == 0) {
D("%s: illegal snapshot: client for control channel must no be saved\n",
__FUNCTION__);
@@ -976,8 +1066,8 @@ qemud_service_remove_client( QemudService* s, QemudClient* c )
for (;;) {
node = *pnode;
if (node == NULL) {
- D("%s: could not find client %d for service '%s'",
- __FUNCTION__, c->channel, s->name);
+ D("%s: could not find client for service '%s'",
+ __FUNCTION__, s->name);
return;
}
if (node == c)
@@ -1004,7 +1094,6 @@ qemud_service_connect_client(QemudService *sv, int channel_id)
__FUNCTION__, sv->name);
return NULL;
}
-
D("%s: registered client channel %d for '%s' service",
__FUNCTION__, channel_id, sv->name);
return client;
@@ -1153,7 +1242,7 @@ qemud_multiplexer_serial_recv( void* opaque,
* QemudClient that is setup in qemud_multiplexer_init()
*/
for ( ; c != NULL; c = c->next ) {
- if (c->channel == channel) {
+ if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
qemud_client_recv(c, msg, msglen);
return;
}
@@ -1203,13 +1292,13 @@ qemud_multiplexer_disconnect( QemudMultiplexer* m,
/* find the client by its channel id, then disconnect it */
for (c = m->clients; c; c = c->next) {
- if (c->channel == channel) {
+ if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
D("%s: disconnecting client %d",
__FUNCTION__, channel);
/* note thatt this removes the client from
* m->clients automatically.
*/
- c->channel = -1; /* no need to send disconnect:<id> */
+ c->ProtocolSelector.Serial.channel = -1; /* no need to send disconnect:<id> */
qemud_client_disconnect(c);
return;
}
@@ -1233,12 +1322,13 @@ qemud_multiplexer_disconnect_noncontrol( QemudMultiplexer* m )
c = next;
next = c->next; /* disconnect frees c, remember next in advance */
- if (c->channel > 0) { /* skip control channel */
+ if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0) {
+ /* skip control channel */
D("%s: disconnecting client %d",
- __FUNCTION__, c->channel);
+ __FUNCTION__, c->ProtocolSelector.Serial.channel);
D("%s: disconnecting client %d\n",
- __FUNCTION__, c->channel);
- c->channel = -1; /* do not send disconnect:<id> */
+ __FUNCTION__, c->ProtocolSelector.Serial.channel);
+ c->ProtocolSelector.Serial.channel = -1; /* do not send disconnect:<id> */
qemud_client_disconnect(c);
}
}
@@ -1442,13 +1532,91 @@ qemud_client_new( QemudService* service,
return c;
}
+/* Caches a service message into the client's descriptor.
+ *
+ * See comments on QemudPipeMessage structure for more info.
+ */
+static void
+_qemud_pipe_cache_buffer(QemudClient* client, const uint8_t* msg, int msglen)
+{
+ QemudPipeMessage* buf;
+ QemudPipeMessage** ins_at = &client->ProtocolSelector.Pipe.messages;
+
+ /* Allocate descriptor big enough to contain message as well. */
+ buf = (QemudPipeMessage*)malloc(msglen + sizeof(QemudPipeMessage));
+ if (buf != NULL) {
+ /* Message starts right after the descriptor. */
+ buf->message = (uint8_t*)buf + sizeof(QemudPipeMessage);
+ buf->size = msglen;
+ memcpy(buf->message, msg, msglen);
+ buf->offset = 0;
+ buf->next = NULL;
+ while (*ins_at != NULL) {
+ ins_at = &(*ins_at)->next;
+ }
+ *ins_at = buf;
+ /* Notify the pipe that there is data to read. */
+ goldfish_pipe_wake(client->ProtocolSelector.Pipe.hwpipe, PIPE_WAKE_READ);
+ }
+}
+
+/* Sends service message to the client.
+ */
+static void
+_qemud_pipe_send(QemudClient* client, const uint8_t* msg, int msglen)
+{
+ uint8_t frame[FRAME_HEADER_SIZE];
+ int avail, len = msglen;
+ int framing = client->framing;
+
+ if (msglen <= 0)
+ return;
+
+ D("%s: len=%3d '%s'",
+ __FUNCTION__, msglen, quote_bytes((const void*)msg, msglen));
+
+ if (framing) {
+ len += FRAME_HEADER_SIZE;
+ }
+
+ /* packetize the payload for the serial MTU */
+ while (len > 0)
+ {
+ avail = len;
+ if (avail > MAX_SERIAL_PAYLOAD)
+ avail = MAX_SERIAL_PAYLOAD;
+
+ /* insert frame header when needed */
+ if (framing) {
+ int2hex(frame, FRAME_HEADER_SIZE, msglen);
+ T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
+ _qemud_pipe_cache_buffer(client, frame, FRAME_HEADER_SIZE);
+ avail -= FRAME_HEADER_SIZE;
+ len -= FRAME_HEADER_SIZE;
+ framing = 0;
+ }
+
+ /* write message content */
+ T("%s: '%.*s'", __FUNCTION__, avail, msg);
+ _qemud_pipe_cache_buffer(client, msg, avail);
+ msg += avail;
+ len -= avail;
+ }
+}
+
/* this can be used by a service implementation to send an answer
* or message to a specific client.
*/
void
qemud_client_send ( QemudClient* client, const uint8_t* msg, int msglen )
{
- qemud_serial_send(client->serial, client->channel, client->framing != 0, msg, msglen);
+ if (_is_pipe_client(client)) {
+ _qemud_pipe_send(client, msg, msglen);
+ } else {
+ qemud_serial_send(client->ProtocolSelector.Serial.serial,
+ client->ProtocolSelector.Serial.channel,
+ client->framing != 0, msg, msglen);
+ }
}
/* enable framing for this client. When TRUE, this will
@@ -1488,7 +1656,8 @@ qemud_client_save_count(QEMUFile* f, QemudClient* c)
{
unsigned int client_count = 0;
for( ; c; c = c->next) // walk over linked list
- if (c->channel > 0) // skip control channel, which is not saved
+ // skip control channel, which is not saved
+ if (_is_pipe_client(c) || c->ProtocolSelector.Serial.channel > 0)
client_count++;
qemu_put_be32(f, client_count);
@@ -1530,7 +1699,8 @@ qemud_save(QEMUFile* f, void* opaque)
qemud_client_save_count(f, m->clients);
QemudClient *c;
for (c = m->clients; c; c = c->next) {
- if (c->channel > 0) { /* skip control channel client */
+ /* skip control channel client */
+ if (_is_pipe_client(c) || c->ProtocolSelector.Serial.channel > 0) {
qemud_client_save(f, c);
}
}
@@ -1604,6 +1774,211 @@ qemud_load(QEMUFile *f, void* opaque, int version)
return 0;
}
+/*------------------------------------------------------------------------------
+ *
+ * QEMUD PIPE service callbacks
+ *
+ * ----------------------------------------------------------------------------*/
+
+/* Descriptor for a QEMUD pipe connection.
+ *
+ * Every time a client connects to the QEMUD via pipe, an instance of this
+ * structure is created to represent a connection used by new pipe client.
+ */
+typedef struct QemudPipe {
+ /* Pipe descriptor. */
+ void* hwpipe;
+ /* Looper used for I/O */
+ void* looper;
+ /* Service for this pipe. */
+ QemudService* service;
+ /* Client for this pipe. */
+ QemudClient* client;
+} QemudPipe;
+
+/* This is a callback that gets invoked when guest is connecting to the service.
+ *
+ * Here we will create a new client as well as pipe descriptor representing new
+ * connection.
+ */
+static void*
+_qemudPipe_init(void* hwpipe, void* _looper, const char* args)
+{
+ QemudMultiplexer *m = _multiplexer;
+ QemudService* sv = m->services;
+ QemudClient* client;
+ QemudPipe* pipe = NULL;
+
+ /* 'args' passed in this callback represents name of the service the guest is
+ * connecting to. It can't be NULL. */
+ if (args == NULL) {
+ D("%s: Missing address!", __FUNCTION__);
+ return NULL;
+ }
+
+ /* Lookup registered service by its name. */
+ while (sv != NULL && strcmp(sv->name, args)) {
+ sv = sv->next;
+ }
+ if (sv == NULL) {
+ D("%s: Service '%s' has not been registered!", __FUNCTION__, args);
+ return NULL;
+ }
+
+ /* Create a client for this connection. -1 as a channel ID signals that this
+ * is a pipe client. */
+ client = qemud_service_connect_client(sv, -1);
+ if (client != NULL) {
+ ANEW0(pipe);
+ pipe->hwpipe = hwpipe;
+ pipe->looper = _looper;
+ pipe->service = sv;
+ pipe->client = client;
+ client->ProtocolSelector.Pipe.hwpipe = hwpipe;
+ }
+
+ return pipe;
+}
+
+/* Called when the guest wants to close the channel.
+*/
+static void
+_qemudPipe_closeFromGuest( void* opaque )
+{
+ QemudPipe* pipe = opaque;
+ QemudClient* client = pipe->client;
+ D("%s", __FUNCTION__);
+ qemud_client_disconnect(client);
+}
+
+/* Called when the guest has sent some data to the client.
+ */
+static int
+_qemudPipe_sendBuffers(void* opaque,
+ const GoldfishPipeBuffer* buffers,
+ int numBuffers)
+{
+ QemudPipe* pipe = opaque;
+ QemudClient* client = pipe->client;
+ size_t transferred = 0;
+
+ if (numBuffers == 1) {
+ /* Simple case: all data are in one buffer. */
+ D("%s: %s", __FUNCTION__, quote_bytes((char*)buffers->data, buffers->size));
+ qemud_client_recv(client, buffers->data, buffers->size);
+ transferred = buffers->size;
+ } else {
+ /* If there are multiple buffers involved, collect all data in one buffer
+ * before calling the high level client. */
+ uint8_t* msg, *wrk;
+ int n;
+ for (n = 0; n < numBuffers; n++) {
+ transferred += buffers[n].size;
+ }
+ msg = malloc(transferred);
+ wrk = msg;
+ for (n = 0; n < numBuffers; n++) {
+ memcpy(wrk, buffers[n].data, buffers[n].size);
+ wrk += buffers[n].size;
+ }
+ D("%s: %s", __FUNCTION__, quote_bytes((char*)msg, transferred));
+ qemud_client_recv(client, msg, transferred);
+ free(msg);
+ }
+
+ return transferred;
+}
+
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+/* Called when the guest is reading data from the client.
+ */
+static int
+_qemudPipe_recvBuffers(void* opaque, GoldfishPipeBuffer* buffers, int numBuffers)
+{
+ QemudPipe* pipe = opaque;
+ QemudClient* client = pipe->client;
+ QemudPipeMessage** msg_list = &client->ProtocolSelector.Pipe.messages;
+ GoldfishPipeBuffer* buff = buffers;
+ GoldfishPipeBuffer* endbuff = buffers + numBuffers;
+ size_t sent_bytes = 0;
+ size_t off_in_buff = 0;
+
+ if (*msg_list == NULL) {
+ /* No data to send. Let it block until we wake it up with
+ * PIPE_WAKE_READ when service sends data to the client. */
+ return PIPE_ERROR_AGAIN;
+ }
+
+ /* Fill in goldfish buffers while they are still available, and there are
+ * messages in the client's message list. */
+ while (buff != endbuff && *msg_list != NULL) {
+ QemudPipeMessage* msg = *msg_list;
+ /* Message data fiting the current pipe's buffer. */
+ size_t to_copy = min(msg->size - msg->offset, buff->size);
+ memcpy(buff->data + off_in_buff, msg->message + msg->offset, to_copy);
+ /* Update offsets. */
+ off_in_buff += to_copy;
+ msg->offset += to_copy;
+ sent_bytes += to_copy;
+ if (msg->size == msg->offset) {
+ /* We're done with the current message. Go to the next one. */
+ *msg_list = msg->next;
+ free(msg);
+ }
+ if (off_in_buff == buff->size) {
+ /* Current pipe buffer is full. Continue with the next one. */
+ buff++;
+ }
+ }
+
+ D("%s: -> %u (of %u)", __FUNCTION__, sent_bytes, buffers->size);
+
+ return sent_bytes;
+}
+
+static unsigned
+_qemudPipe_poll(void* opaque)
+{
+ QemudPipe* pipe = opaque;
+ QemudClient* client = pipe->client;
+ unsigned ret = PIPE_WAKE_WRITE;
+ if (client->ProtocolSelector.Pipe.messages != NULL) {
+ ret |= PIPE_WAKE_READ;
+ }
+
+ return ret;
+}
+
+static void
+_qemudPipe_wakeOn(void* opaque, int flags)
+{
+ D("%s: -> %X", __FUNCTION__, flags);
+}
+
+/* QEMUD pipe functions.
+ */
+static const GoldfishPipeFuncs _qemudPipe_funcs = {
+ _qemudPipe_init,
+ _qemudPipe_closeFromGuest,
+ _qemudPipe_sendBuffers,
+ _qemudPipe_recvBuffers,
+ _qemudPipe_poll,
+ _qemudPipe_wakeOn,
+};
+
+/* Initializes QEMUD pipe interface.
+ */
+static void
+_android_qemud_pipe_init(void)
+{
+ static ABool _qemud_pipe_initialized = false;
+
+ if (!_qemud_pipe_initialized) {
+ goldfish_pipe_add_type( "qemud", looper_newCore(), &_qemudPipe_funcs );
+ _qemud_pipe_initialized = true;
+ }
+}
/* this is the end of the serial charpipe that must be passed
* to the emulated tty implementation. The other end of the
@@ -1611,8 +1986,10 @@ qemud_load(QEMUFile *f, void* opaque, int version)
*/
static CharDriverState* android_qemud_cs;
-extern void
-android_qemud_init( void )
+/* Initializes QEMUD serial interface.
+ */
+static void
+_android_qemud_serial_init(void)
{
CharDriverState* cs;
@@ -1631,6 +2008,18 @@ android_qemud_init( void )
qemud_save, qemud_load, _multiplexer);
}
+extern void
+android_qemud_init( void )
+{
+ D("%s", __FUNCTION__);
+ /* We don't know in advance whether the guest system supports qemud pipes,
+ * so we will initialize both qemud machineries, the legacy (over serial
+ * port), and the new one (over qemu pipe). Then we let the guest to connect
+ * via one, or the other. */
+ _android_qemud_serial_init();
+ _android_qemud_pipe_init();
+}
+
/* return the serial charpipe endpoint that must be used
* by the emulated tty implementation.
*/
@@ -1663,20 +2052,19 @@ qemud_service_register( const char* service_name,
QemudServiceSave serv_save,
QemudServiceLoad serv_load )
{
- QemudMultiplexer* m = _multiplexer;
QemudService* sv;
+ QemudMultiplexer* m = _multiplexer;
- if (android_qemud_cs == NULL)
- android_qemud_init();
+ android_qemud_init();
sv = qemud_service_new(service_name,
- max_clients,
- serv_opaque,
- serv_connect,
- serv_save,
- serv_load,
- &m->services);
-
+ max_clients,
+ serv_opaque,
+ serv_connect,
+ serv_save,
+ serv_load,
+ &m->services);
+ D("Registered QEMUD service %s", service_name);
return sv;
}
diff --git a/android/main-common.c b/android/main-common.c
index 94accf7..a0e5f56 100644
--- a/android/main-common.c
+++ b/android/main-common.c
@@ -524,7 +524,7 @@ init_sdl_ui(AConfig* skinConfig,
#endif
/* we're not a game, so allow the screensaver to run */
- putenv("SDL_VIDEO_ALLOW_SCREENSAVER=1");
+ setenv("SDL_VIDEO_ALLOW_SCREENSAVER","1",1);
flags = SDL_INIT_NOPARACHUTE;
if (!opts->no_window)
diff --git a/android/main.c b/android/main.c
index ec7ea61..814d2ec 100644
--- a/android/main.c
+++ b/android/main.c
@@ -169,6 +169,8 @@ int main(int argc, char **argv)
int serial = 2;
int shell_serial = 0;
+ int forceArmv7 = 0;
+
AndroidHwConfig* hw;
AvdInfo* avd;
AConfig* skinConfig;
@@ -430,8 +432,7 @@ int main(int argc, char **argv)
*/
kernelFileLen = strlen(kernelFile);
if (kernelFileLen > 6 && !memcmp(kernelFile + kernelFileLen - 6, "-armv7", 6)) {
- args[n++] = "-cpu";
- args[n++] = "cortex-a8";
+ forceArmv7 = 1;
}
}
@@ -1067,6 +1068,27 @@ int main(int argc, char **argv)
}
args[n] = 0;
+ /* If the target ABI is armeabi-v7a, we can auto-detect the cpu model
+ * as a cortex-a8, instead of the default (arm926) which only emulates
+ * an ARMv5TE CPU.
+ */
+ if (!forceArmv7 && hw->hw_cpu_model[0] == '\0')
+ {
+ char* abi = avdInfo_getTargetAbi(avd);
+ if (abi != NULL) {
+ if (!strcmp(abi, "armeabi-v7a")) {
+ forceArmv7 = 1;
+ }
+ AFREE(abi);
+ }
+ }
+
+ if (forceArmv7 != 0) {
+ AFREE(hw->hw_cpu_model);
+ hw->hw_cpu_model = ASTRDUP("cortex-a8");
+ D("Auto-config: -qemu -cpu %s", hw->hw_cpu_model);
+ }
+
/* 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.
diff --git a/android/skin/window.c b/android/skin/window.c
index 0d8788e..9a72db5 100644
--- a/android/skin/window.c
+++ b/android/skin/window.c
@@ -1315,15 +1315,9 @@ skin_window_resize( SkinWindow* window )
{
char temp[32];
-#ifdef HAVE_SETENV
sprintf(temp, "%d,%d", window_x, window_y);
setenv("SDL_VIDEO_WINDOW_POS", temp, 1);
setenv("SDL_VIDEO_WINDOW_FORCE_VISIBLE", "1", 1);
-#else
- sprintf(temp,"SDL_VIDEO_WINDOW_POS=%d,%d",window_x,window_y);
- putenv(temp);
- putenv("SDL_VIDEO_WINDOW_FORCE_VISIBLE=1");
-#endif
}
flags = SDL_SWSURFACE;
diff --git a/android/utils/setenv.c b/android/utils/setenv.c
new file mode 100644
index 0000000..916c5f3
--- /dev/null
+++ b/android/utils/setenv.c
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+int setenv(const char *name, const char *value, int overwrite)
+{
+ int result = 0;
+ if (overwrite || !getenv(name)) {
+ size_t length = strlen(name) + strlen(value) + 2;
+ char *string = malloc(length);
+ snprintf(string, length, "%s=%s", name, value);
+ result = putenv(string);
+ }
+ return result;
+}
+
+#endif
diff --git a/docs/ANDROID-QEMUD.TXT b/docs/ANDROID-QEMUD.TXT
index 7841399..8b4f8d6 100644
--- a/docs/ANDROID-QEMUD.TXT
+++ b/docs/ANDROID-QEMUD.TXT
@@ -6,7 +6,9 @@ I. Overview:
The Android system image includes a small daemon program named "qemud"
which is started at boot time. Its purpose is to provide a multiplexing
communication channel between the emulated system and the emulator program
-itself.
+itself. Another way to support communication between the emulated system and
+the emulator program is using qemu pipes (see ANDROID-QEMU-PIPE.TXT for details
+on qemu pipes).
Its goal is to allow certain parts of the system to talk directly to the
emulator without requiring special kernel support; this simplifies a lot of
@@ -169,6 +171,17 @@ Since the "cupcake" platform, this works as follows:
Certain services do not need it at all (GSM, GPS) so it is optional and
must be used depending on which service you talk to by clients.
+- QEMU pipe communication model works similarly to the serial port multiplexing,
+ but also has some differences as far as connecting client with the service is
+ concerned:
+
+ emulator <-+--> /dev/qemu_pipe/qemud:srv1 <---> client1
+ |
+ +--> /dev/qemu_pipe/qemud:srv2 <---> client2
+
+ In the pipe model each client gets connected to the emulator through a unique
+ handle to /dev/qemu_pipe (a "pipe"), so there is no need for multiplexing the
+ channels.
III. Legacy 'qemud':
--------------------
@@ -254,7 +267,7 @@ only uses a single socket and allows concurrent clients for a all services.
IV. State snapshots:
--------------------
-Support for snapshots relies on the symmetric qemud_*_save and qemud_*_load
+Support for snapshots relies on the symmetric qemud_*_save and qemud_*_load
functions which save the state of the various Qemud* structs defined in
android/hw-qemud.c. The high-level process is as follows.
diff --git a/images/android_icon.ico b/images/android_icon.ico
index bd25179..798d96b 100644
--- a/images/android_icon.ico
+++ b/images/android_icon.ico
Binary files differ
diff --git a/images/android_icon_16.png b/images/android_icon_16.png
index 0b0744b..5df26d4 100644
--- a/images/android_icon_16.png
+++ b/images/android_icon_16.png
Binary files differ
diff --git a/images/android_icon_256.png b/images/android_icon_256.png
index 2d1dc05..0fcac26 100644
--- a/images/android_icon_256.png
+++ b/images/android_icon_256.png
Binary files differ
diff --git a/images/android_icon_32.png b/images/android_icon_32.png
index 72aa861..4ba97a5 100644
--- a/images/android_icon_32.png
+++ b/images/android_icon_32.png
Binary files differ
diff --git a/vl-android.c b/vl-android.c
index 8436d68..32b5eac 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -3721,13 +3721,11 @@ int main(int argc, char **argv, char **envp)
/* Initialize audio. */
if (android_op_audio) {
- char temp[128];
if ( !audio_check_backend_name( 0, android_op_audio ) ) {
PANIC("'%s' is not a valid audio output backend. see -help-audio-out",
android_op_audio);
}
- snprintf(temp, sizeof temp, "QEMU_AUDIO_DRV=%s", android_op_audio);
- putenv(temp);
+ setenv("QEMU_AUDIO_DRV", android_op_audio, 1);
}
/* Initialize OpenGLES emulation */