aboutsummaryrefslogtreecommitdiffstats
path: root/android
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:04:49 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:04:49 -0800
commitdf7881f07f53b041dc0568be8528e9dbb74994cc (patch)
tree1b3e036f7df4241bf0c2d527b73198c50e1d7891 /android
parent55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (diff)
downloadexternal_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.zip
external_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.tar.gz
external_qemu-df7881f07f53b041dc0568be8528e9dbb74994cc.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'android')
-rw-r--r--android/build/binary.make29
-rw-r--r--android/build/clear_vars.make30
-rw-r--r--android/build/definitions.make88
-rw-r--r--android/build/getdir.make19
-rw-r--r--android/build/host_executable.make36
-rw-r--r--android/build/host_static_library.make35
-rwxr-xr-xandroid/build/mkdeps.sh48
-rw-r--r--android/config/check-alsa.c107
-rw-r--r--android/config/check-esd.c67
-rw-r--r--android/globals.h33
-rwxr-xr-xandroid/tools/gen-hw-config.py141
-rw-r--r--android/utils/debug.h18
-rw-r--r--android/utils/dirscanner.c203
-rw-r--r--android/utils/dirscanner.h25
-rw-r--r--android/utils/ini.c366
-rw-r--r--android/utils/ini.h121
-rw-r--r--android/vm/hardware-properties.ini158
-rw-r--r--android/vm/hw-config-defs.h165
-rw-r--r--android/vm/hw-config.c39
-rw-r--r--android/vm/hw-config.h46
-rw-r--r--android/vm/info.c1534
-rw-r--r--android/vm/info.h161
22 files changed, 3469 insertions, 0 deletions
diff --git a/android/build/binary.make b/android/build/binary.make
new file mode 100644
index 0000000..379ef9a
--- /dev/null
+++ b/android/build/binary.make
@@ -0,0 +1,29 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# definitions shared by host_executable.make and host_static_library.make
+#
+
+# the directory where we're going to place our object files
+LOCAL_OBJS_DIR := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE))
+LOCAL_OBJECTS :=
+LOCAL_CC ?= $(CC)
+LOCAL_C_SOURCES := $(filter %.c,$(LOCAL_SRC_FILES))
+
+$(foreach src,$(LOCAL_C_SOURCES), \
+ $(eval $(call compile-c-source,$(src))) \
+)
+
+CLEAN_OBJS_DIRS += $(LOCAL_OBJS_DIR)
diff --git a/android/build/clear_vars.make b/android/build/clear_vars.make
new file mode 100644
index 0000000..a9289b0
--- /dev/null
+++ b/android/build/clear_vars.make
@@ -0,0 +1,30 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# called multiple times to clear variables used to define a given 'module'
+#
+LOCAL_NO_DEFAULT_COMPILER_FLAGS:=
+LOCAL_CC :=
+LOCAL_CXX :=
+LOCAL_CFLAGS :=
+LOCAL_LDFLAGS :=
+LOCAL_LDLIBS :=
+LOCAL_SRC_FILES :=
+LOCAL_MODULE :=
+LOCAL_MODULE_PATH:=
+LOCAL_STATIC_LIBRARIES :=
+LOCAL_BUILT_MODULE :=
+LOCAL_PREBUILT_OBJ_FILES :=
+
diff --git a/android/build/definitions.make b/android/build/definitions.make
new file mode 100644
index 0000000..c4183ea
--- /dev/null
+++ b/android/build/definitions.make
@@ -0,0 +1,88 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# shared definitions
+ifeq ($(strip $(SHOW)),)
+define pretty
+@echo $1
+endef
+hide := @
+else
+define pretty
+endef
+hide :=
+endif
+
+define my-dir
+.
+endef
+
+# return the directory containing the intermediate files for a given
+# kind of executable
+# $1 = type (EXECUTABLES or STATIC_LIBRARIES)
+# $2 = module name
+# $3 = ignored
+#
+define intermediates-dir-for
+$(OBJS_DIR)/intermediates/$(2)
+endef
+
+# Generate the full path of a given static library
+define library-path
+$(OBJS_DIR)/$(1).a
+endef
+
+define executable-path
+$(OBJS_DIR)/$(1)$(EXE)
+endef
+
+# Compile a C source file
+#
+define compile-c-source
+SRC:=$(1)
+OBJ:=$$(LOCAL_OBJS_DIR)/$$(SRC:%.c=%.o)
+LOCAL_OBJECTS += $$(OBJ)
+$$(OBJ): PRIVATE_CFLAGS := $$(CFLAGS) $$(LOCAL_CFLAGS) -I$$(LOCAL_PATH) -I$$(OBJS_DIR)
+$$(OBJ): PRIVATE_CC := $$(LOCAL_CC)
+$$(OBJ): PRIVATE_OBJ := $$(OBJ)
+$$(OBJ): PRIVATE_MODULE := $$(LOCAL_MODULE)
+$$(OBJ): PRIVATE_SRC := $$(SRC_PATH)/$$(SRC)
+$$(OBJ): PRIVATE_SRC0 := $$(SRC)
+$$(OBJ): $$(SRC_PATH)/$$(SRC)
+ @mkdir -p $$(dir $$(PRIVATE_OBJ))
+ @echo "Compile: $$(PRIVATE_MODULE) <= $$(PRIVATE_SRC0)"
+ $(hide) $$(PRIVATE_CC) $$(PRIVATE_CFLAGS) -c -o $$(PRIVATE_OBJ) -MMD -MP -MF $$(PRIVATE_OBJ).d.tmp $$(PRIVATE_SRC)
+ $(hide) $$(SRC_PATH)/android/build/mkdeps.sh $$(PRIVATE_OBJ) $$(PRIVATE_OBJ).d.tmp $$(PRIVATE_OBJ).d
+endef
+
+# for now, we only use prebuilt SDL libraries, so copy them
+define copy-prebuilt-lib
+_SRC := $(1)
+_SRC1 := $$(notdir $$(_SRC))
+_DST := $$(OBJS_DIR)/$$(_SRC1)
+LIBRARIES += $$(_DST)
+$$(_DST): PRIVATE_DST := $$(_DST)
+$$(_DST): PRIVATE_SRC := $$(_SRC)
+$$(_DST): $$(_SRC)
+ @mkdir -p $$(dir $$(PRIVATE_DST))
+ @echo "Prebuilt: $$(PRIVATE_DST)"
+ $(hide) cp -f $$(PRIVATE_SRC) $$(PRIVATE_DST)
+endef
+
+define create-dir
+$(1):
+ mkdir -p $(1)
+endef
+
diff --git a/android/build/getdir.make b/android/build/getdir.make
new file mode 100644
index 0000000..a4dadd3
--- /dev/null
+++ b/android/build/getdir.make
@@ -0,0 +1,19 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# used to return in 'dir' the name of the current operating system
+# we really get the value from the configuration script
+#
+dir := $(HOST_OS)
diff --git a/android/build/host_executable.make b/android/build/host_executable.make
new file mode 100644
index 0000000..a9b51d8
--- /dev/null
+++ b/android/build/host_executable.make
@@ -0,0 +1,36 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# first, call a library containing all object files
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# now, link the executable with it
+LOCAL_BUILT_LIBRARY := $(LOCAL_BUILT_MODULE)
+LOCAL_BUILT_MODULE := $(call executable-path,$(LOCAL_MODULE))
+
+LOCAL_LDLIBS := $(foreach lib,$(LOCAL_STATIC_LIBRARIES),$(call library-path,$(lib))) $(LOCAL_LDLIBS)
+
+$(LOCAL_BUILT_MODULE): PRIVATE_LDFLAGS := $(LDFLAGS) $(LOCAL_LDFLAGS)
+$(LOCAL_BUILT_MODULE): PRIVATE_LDLIBS := $(LOCAL_LDLIBS)
+$(LOCAL_BUILT_MODULE): PRIVATE_LIBRARY := $(LOCAL_BUILT_LIBRARY)
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_BUILT_LIBRARY)
+ @ mkdir -p $(dir $@)
+ @ echo "Executable: $@"
+ $(hide) $(LD) $(PRIVATE_LDFLAGS) -o $@ $(PRIVATE_LIBRARY) $(PRIVATE_LDLIBS)
+
+EXECUTABLES += $(LOCAL_BUILT_MODULE)
+$(LOCAL_BUILT_MODULE): $(foreach lib,$(LOCAL_STATIC_LIBRARIES),$(call library-path,$(lib)))
+
diff --git a/android/build/host_static_library.make b/android/build/host_static_library.make
new file mode 100644
index 0000000..3de5a99
--- /dev/null
+++ b/android/build/host_static_library.make
@@ -0,0 +1,35 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# build a host executable, the name of the final executable should be
+# put in LOCAL_BUILT_MODULE for use by the caller
+#
+
+#$(info STATIC_LIBRARY SRCS=$(LOCAL_SRC_FILES))
+LOCAL_BUILT_MODULE := $(call library-path,$(LOCAL_MODULE))
+LOCAL_CC ?= $(CC)
+include $(BUILD_SYSTEM)/binary.make
+
+LOCAL_AR ?= $(AR)
+ARFLAGS := crs
+
+$(LOCAL_BUILT_MODULE): PRIVATE_AR := $(LOCAL_AR)
+$(LOCAL_BUILT_MODULE): PRIVATE_OBJECTS := $(LOCAL_OBJECTS)
+$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
+ @mkdir -p $(dir $@)
+ @echo "Library: $@"
+ $(hide) $(PRIVATE_AR) $(ARFLAGS) $@ $(PRIVATE_OBJECTS)
+
+LIBRARIES += $(LOCAL_BUILT_MODULE)
diff --git a/android/build/mkdeps.sh b/android/build/mkdeps.sh
new file mode 100755
index 0000000..2d25ca3
--- /dev/null
+++ b/android/build/mkdeps.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script is used to transform the dependency files generated by GCC
+# For example, a typical .d file will have a line like:
+#
+# source.o: /full/path/to/source.c other.h headers.h
+# ...
+#
+# the script is used to replace 'source.o' to a full path, as in
+#
+# objs/intermediates/emulator/source.o: /full/path/to/source.c other.h headers.h
+#
+# parameters
+#
+# $1: object file (full path)
+# $2: source dependency file to modify (erased on success)
+# $3: target source dependency file
+#
+
+# quote the object path. we change a single '.' into
+# a '\.' since this will be parsed by sed.
+#
+OBJECT=`echo $1 | sed -e s/\\\\./\\\\\\\\./g`
+#echo OBJECT=$OBJECT
+
+OBJ_NAME=`basename $OBJECT`
+#echo OBJ_NAME=$OBJ_NAME
+
+# we replace $OBJ_NAME with $OBJECT
+#
+cat $2 | sed -e s%$OBJ_NAME%$OBJECT%g > $3 && rm -f $2
+
+
+
diff --git a/android/config/check-alsa.c b/android/config/check-alsa.c
new file mode 100644
index 0000000..4ab2945
--- /dev/null
+++ b/android/config/check-alsa.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <dlfcn.h>
+#include <stdio.h>
+#include <alsa/asoundlib.h>
+
+#define D(...) fprintf(stderr,__VA_ARGS__)
+#define STRINGIFY(x) _STRINGIFY(x)
+#define _STRINGIFY(x) #x
+
+#define DYN_SYMBOLS \
+ DYN_FUNCTION(size_t,snd_pcm_sw_params_sizeof,(void)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_current,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params_set_start_threshold,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params_current,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYN_FUNCTION(size_t,snd_pcm_hw_params_sizeof,(void)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_any,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_access,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_format,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_rate_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_channels_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYN_FUNCTION(int,snd_pcm_prepare,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_period_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_period_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_avail_update,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(int,snd_pcm_drop,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_writei,(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_readi,(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)) \
+ DYN_FUNCTION(snd_pcm_state_t,snd_pcm_state,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(const char*,snd_strerror,(int errnum)) \
+ DYN_FUNCTION(int,snd_pcm_open,(snd_pcm_t **pcm, const char *name,snd_pcm_stream_t stream, int mode)) \
+ DYN_FUNCTION(int,snd_pcm_close,(snd_pcm_t *pcm)) \
+
+
+
+/* define pointers to library functions we're going to use */
+#define DYN_FUNCTION(ret,name,sig) \
+ static ret (*func_ ## name)sig;
+
+DYN_SYMBOLS
+
+#undef DYN_FUNCTION
+
+#define func_snd_pcm_hw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(func_snd_pcm_hw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_hw_params_sizeof()); } while (0)
+
+#define func_snd_pcm_sw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(func_snd_pcm_sw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_sw_params_sizeof()); } while (0)
+
+static void* alsa_lib;
+
+int main(void)
+{
+ int result = 1;
+
+ alsa_lib = dlopen( "libasound.so", RTLD_NOW );
+ if (alsa_lib == NULL)
+ alsa_lib = dlopen( "libasound.so.2", RTLD_NOW );
+
+ if (alsa_lib == NULL) {
+ D("could not find libasound on this system\n");
+ return 1;
+ }
+
+#undef DYN_FUNCTION
+#define DYN_FUNCTION(ret,name,sig) \
+ do { \
+ (func_ ##name) = dlsym( alsa_lib, STRINGIFY(name) ); \
+ if ((func_##name) == NULL) { \
+ D("could not find %s in libasound\n", STRINGIFY(name)); \
+ goto Fail; \
+ } \
+ } while (0);
+
+ DYN_SYMBOLS
+
+ result = 0;
+ goto Exit;
+
+Fail:
+ D("failed to open library\n");
+
+Exit:
+ dlclose(alsa_lib);
+ return result;
+}
diff --git a/android/config/check-esd.c b/android/config/check-esd.c
new file mode 100644
index 0000000..a8eb11b
--- /dev/null
+++ b/android/config/check-esd.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* this file is used to test that we can use libesd with lazy dynamic linking */
+
+#include <esd.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+#define D(...) fprintf(stderr,__VA_ARGS__)
+#define STRINGIFY(x) _STRINGIFY(x)
+#define _STRINGIFY(x) #x
+
+#define ESD_SYMBOLS \
+ ESD_FUNCTION(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
+ ESD_FUNCTION(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
+ ESD_FUNCTION(int,esd_open_sound,( const char *host )) \
+ ESD_FUNCTION(int,esd_close,(int)) \
+
+/* define pointers to library functions we're going to use */
+#define ESD_FUNCTION(ret,name,sig) \
+ static ret (*func_ ## name)sig;
+
+ESD_SYMBOLS
+
+#undef ESD_FUNCTION
+static void* esd_lib;
+
+int main( void )
+{
+ int fd;
+
+ esd_lib = dlopen( "libesd.so", RTLD_NOW );
+ if (esd_lib == NULL)
+ esd_lib = dlopen( "libesd.so.0", RTLD_NOW );
+
+ if (esd_lib == NULL) {
+ D("could not find libesd on this system");
+ return 1;
+ }
+
+#undef ESD_FUNCTION
+#define ESD_FUNCTION(ret,name,sig) \
+ do { \
+ (func_ ##name) = dlsym( esd_lib, STRINGIFY(name) ); \
+ if ((func_##name) == NULL) { \
+ D("could not find %s in libesd\n", STRINGIFY(name)); \
+ return 1; \
+ } \
+ } while (0);
+
+ ESD_SYMBOLS
+
+ return 0;
+}
diff --git a/android/globals.h b/android/globals.h
new file mode 100644
index 0000000..625c84a
--- /dev/null
+++ b/android/globals.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2007-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.
+*/
+#ifndef _ANDROID_GLOBALS_H
+#define _ANDROID_GLOBALS_H
+
+#include "android/vm/info.h"
+#include "android/vm/hw-config.h"
+
+/* this structure is setup when loading the virtual machine
+ * after that, you can read the 'flags' field to determine
+ * wether a data or cache wipe has been in effect.
+ */
+extern AvmInfoParams android_vmParams[1];
+
+/* a pointer to the android virtual machine information
+ * object, which can be queried for the paths of various
+ * image files or the skin
+ */
+extern AvmInfo* android_vmInfo;
+
+/* the hardware configuration for this specific virtual machine */
+extern AndroidHwConfig android_hw[1];
+
+#endif /* _ANDROID_GLOBALS_H */
diff --git a/android/tools/gen-hw-config.py b/android/tools/gen-hw-config.py
new file mode 100755
index 0000000..ae3a8de
--- /dev/null
+++ b/android/tools/gen-hw-config.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+# this script is used to generate 'android/vm/hw-config.h' by
+# parsing 'android/vm/hardware-properties.ini'
+#
+#
+import sys, os, string, re
+
+# location of source file, relative to current program directory
+relativeSourcePath = "../vm/hardware-properties.ini"
+
+# location of target file, relative to current program directory
+relativeTargetPath = "../vm/hw-config-defs.h"
+
+def quoteStringForC(str):
+ """quote a string so it can be used in C"""
+ return '\\"'.join('"'+p+'"' for p in str.split('"'))
+
+# a dictionary that maps item types as they appear in the .ini
+# file into macro names in the generated C header
+#
+typesToMacros = {
+ 'integer': 'HWCFG_INT',
+ 'string': 'HWCFG_STRING',
+ 'boolean': 'HWCFG_BOOL',
+ 'diskSize': 'HWCFG_DISKSIZE',
+ 'double': 'HWCFG_DOUBLE'
+ }
+
+# the list of macro names
+macroNames = typesToMacros.values()
+
+# target program header
+targetHeader = """\
+/* this file is automatically generated from 'hardware-properties.ini'
+ * DO NOT EDIT IT. To re-generate it, use android/tools/gen-hw-config.py'
+ */"""
+
+# locate source and target
+programDir = os.path.dirname(sys.argv[0])
+sourceFile = os.path.normpath(os.path.join(programDir,relativeSourcePath))
+targetFile = os.path.normpath(os.path.join(programDir,relativeTargetPath))
+
+# parse the source file and record items
+# I would love to use Python's ConfigParser, but it doesn't
+# support files without sections, or multiply defined items
+#
+items = []
+lastItem = None
+
+class Item:
+ def __init__(self,name):
+ self.name = name
+ self.type = type
+ self.default = None
+ self.abstract = ""
+ self.description = ""
+
+ def add(self,key,val):
+ if key == 'type':
+ self.type = val
+ elif key == 'default':
+ self.default = val
+ elif key == 'abstract':
+ self.abstract = val
+ elif key == 'description':
+ self.description = val
+
+for line in open(sourceFile):
+ line = line.strip()
+ # ignore empty lines and comments
+ if len(line) == 0 or line[0] in ";#":
+ continue
+ key, value = line.split('=')
+
+ key = key.strip()
+ value = value.strip()
+
+ if key == 'name':
+ if lastItem: items.append(lastItem)
+ lastItem = Item(value)
+ else:
+ lastItem.add(key, value)
+
+if lastItem:
+ items.append(lastItem)
+
+
+print targetHeader
+
+# write guards to prevent bad compiles
+for m in macroNames:
+ print """\
+#ifndef %(macro)s
+#error %(macro)s not defined
+#endif""" % { 'macro':m }
+print ""
+
+for item in items:
+ if item.type == None:
+ sys.stderr.write("ignoring config item with no type '%s'\n" % item.name)
+ continue
+
+ if not typesToMacros.has_key(item.type):
+ sys.stderr.write("ignoring config item with unknown type '%s': '%s'\n" % \
+ (item.type, item.name))
+ continue
+
+ if item.default == None:
+ sys.stderr.write("ignoring config item with no default '%s' */" % item.name)
+ continue
+
+ # convert dots into underscores
+ varMacro = typesToMacros[item.type]
+ varNameStr = quoteStringForC(item.name)
+ varName = item.name.replace(".","_")
+ varDefault = item.default
+ varAbstract = quoteStringForC(item.abstract)
+ varDesc = quoteStringForC(item.description)
+
+ if item.type in [ 'string', 'boolean', 'diskSize' ]:
+ # quote default value for strings
+ varDefault = quoteStringForC(varDefault)
+
+ print "%s(\n %s,\n %s,\n %s,\n %s,\n %s)\n" % \
+ (varMacro,varName,varNameStr,varDefault,varAbstract,varDesc)
+
+
+for m in macroNames:
+ print "#undef %s" % m
+
+print "/* end of auto-generated file */"
diff --git a/android/utils/debug.h b/android/utils/debug.h
new file mode 100644
index 0000000..28b93ee
--- /dev/null
+++ b/android/utils/debug.h
@@ -0,0 +1,18 @@
+/* Copyright (C) 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.
+*/
+#ifndef _ANDROID_UTILS_DEBUG_H
+#define _ANDROID_UTILS_DEBUG_H
+
+/* we'll move android_debug.h here later */
+#include "android_debug.h"
+
+#endif /* _ANDROID_UTILS_DEBUG_H */
diff --git a/android/utils/dirscanner.c b/android/utils/dirscanner.c
new file mode 100644
index 0000000..9f44d2d
--- /dev/null
+++ b/android/utils/dirscanner.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 2007-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 "android/utils/dirscanner.h"
+#include "android_utils.h"
+#include "vl.h"
+#include <stddef.h>
+
+#define DIRSCANNER_BASE \
+ char root[PATH_MAX]; \
+ int rootLen; \
+ char full[PATH_MAX]; \
+
+
+#if _WIN32
+
+#include <io.h>
+
+struct DirScanner {
+ DIRSCANNER_BASE
+ intptr_t findIndex1;
+ struct _finddata_t findData;
+};
+
+/* note: findIndex1 contains the find index + 1
+ * so a value of 0 means 'invalid'
+ */
+
+static int
+_dirScannerInit( DirScanner* s )
+{
+ char* p = s->root + s->rootLen;
+ char* end = s->root + sizeof s->root;
+ int ret;
+
+ /* create file spec by appending \* to root */
+ p = bufprint(p, end, "\\*");
+ if (p >= end)
+ return -1;
+
+ ret = _findfirst(s->root, &s->findData) + 1;
+
+ s->findIndex1 = ret+1;
+ return ret;
+}
+
+static void
+_dirScanner_done( DirScanner* s )
+{
+ if (s->findIndex1 > 0) {
+ _findclose(s->findIndex1-1);
+ s->findIndex1 = 0;
+ }
+}
+
+const char*
+dirScanner_next( DirScanner* s )
+{
+ char* ret = NULL;
+
+ if (!s || s->findIndex1 <= 0)
+ return NULL;
+
+ while (ret == NULL) {
+ ret = s->findData.name;
+
+ /* ignore special directories */
+ if (!strcmp(ret, ".") || !strcmp(ret, "..")) {
+ ret = NULL;
+ }
+ /* find next one */
+ if (_findnext(s->findIndex1-1, &s->findData) < 0) {
+ _dirScanner_done(s);
+ break;
+ }
+ }
+ return ret;
+}
+
+#else /* !_WIN32 */
+
+#include <dirent.h>
+struct DirScanner {
+ DIRSCANNER_BASE
+ DIR* dir;
+ struct dirent* entry;
+};
+
+static int
+_dirScannerInit( DirScanner* s )
+{
+ s->dir = opendir(s->root);
+
+ if (s->dir == NULL)
+ return -1;
+
+ s->entry = NULL;
+ return 0;
+}
+
+static void
+_dirScanner_done( DirScanner* s )
+{
+ if (s->dir) {
+ closedir(s->dir);
+ s->dir = NULL;
+ }
+}
+
+const char*
+dirScanner_next( DirScanner* s )
+{
+ char* ret = NULL;
+
+ if (!s || s->dir == NULL)
+ return NULL;
+
+ for (;;)
+ {
+ /* read new entry if needed */
+ s->entry = readdir(s->dir);
+ if (s->entry == NULL) {
+ _dirScanner_done(s);
+ break;
+ }
+
+ /* ignore special directories */
+ ret = s->entry->d_name;
+
+ if (!strcmp(ret,".") || !strcmp(ret,"..")) {
+ ret = NULL;
+ continue;
+ }
+ break;
+ }
+ return ret;
+}
+
+#endif /* !_WIN32 */
+
+DirScanner*
+dirScanner_new ( const char* rootPath )
+{
+ DirScanner* s = qemu_mallocz(sizeof *s);
+ char* p = s->root;
+ char* end = p + sizeof s->root;
+
+ p = bufprint(p, end, "%s", rootPath);
+ if (p >= end)
+ goto FAIL;
+
+ s->rootLen = (p - s->root);
+
+ if (_dirScannerInit(s) < 0)
+ goto FAIL;
+
+ return s;
+
+FAIL:
+ dirScanner_free(s);
+ return NULL;
+}
+
+
+void
+dirScanner_free( DirScanner* s )
+{
+ if (!s)
+ return;
+
+ _dirScanner_done(s);
+ qemu_free(s);
+}
+
+
+const char*
+dirScanner_nextFull( DirScanner* s )
+{
+ const char* name = dirScanner_next(s);
+ char* p;
+ char* end;
+
+ if (name == NULL)
+ return NULL;
+
+ p = s->full;
+ end = p + sizeof s->full;
+
+ p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name);
+ if (p >= end) {
+ /* ignore if the full name is too long */
+ return dirScanner_nextFull(s);
+ }
+ return s->full;
+}
diff --git a/android/utils/dirscanner.h b/android/utils/dirscanner.h
new file mode 100644
index 0000000..9486cfc
--- /dev/null
+++ b/android/utils/dirscanner.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2007-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.
+*/
+#ifndef _ANDROID_UTILS_DIR_H
+#define _ANDROID_UTILS_DIR_H
+
+/* simple utility to parse directories for files */
+/* needed because Unix and Windows don't use the same stuff */
+
+typedef struct DirScanner DirScanner;
+
+DirScanner* dirScanner_new ( const char* rootPath );
+void dirScanner_free( DirScanner* s );
+const char* dirScanner_next( DirScanner* s );
+const char* dirScanner_nextFull( DirScanner* s );
+
+#endif /* _ANDROID_UTILS_DIR_H */
diff --git a/android/utils/ini.c b/android/utils/ini.c
new file mode 100644
index 0000000..d99ecdd
--- /dev/null
+++ b/android/utils/ini.c
@@ -0,0 +1,366 @@
+/* Copyright (C) 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 "android/utils/ini.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include "android_debug.h"
+#include "osdep.h"
+
+/* W() is used to print warnings, D() to print debugging info */
+#define W(...) dwarning(__VA_ARGS__)
+#define D(...) VERBOSE_PRINT(vm_config,__VA_ARGS__)
+
+/* a simple .ini file parser and container for Android
+ * no sections support. see android/utils/ini.h for
+ * more details on the supported file format.
+ */
+typedef struct {
+ char* key;
+ char* value;
+} IniPair;
+
+struct IniFile {
+ int numPairs;
+ int maxPairs;
+ IniPair* pairs;
+};
+
+void
+iniFile_free( IniFile* i )
+{
+ int nn;
+ for (nn = 0; nn < i->numPairs; nn++) {
+ free(i->pairs[nn].key);
+ i->pairs[nn].key = NULL;
+ i->pairs[nn].value = NULL;
+ }
+ free(i->pairs);
+ free(i);
+}
+
+static IniFile*
+iniFile_alloc( void )
+{
+ IniFile* i = calloc(1, sizeof(*i));
+ return i;
+}
+
+static void
+iniFile_addPair( IniFile* i, const char* key, int keyLen,
+ const char* value, int valueLen )
+{
+ IniPair* pair;
+
+ if (i->numPairs >= i->maxPairs) {
+ int oldMax = i->maxPairs;
+ int newMax = oldMax + (oldMax >> 1) + 4;
+ IniPair* newPairs = realloc(i->pairs, newMax*sizeof(newPairs[0]));
+
+ i->pairs = newPairs;
+ i->maxPairs = newMax;
+ }
+
+ pair = i->pairs + i->numPairs;
+
+ pair->key = malloc(keyLen + valueLen + 2);
+ memcpy(pair->key, key, keyLen);
+ pair->key[keyLen] = 0;
+
+ pair->value = pair->key + keyLen + 1;
+ memcpy(pair->value, value, valueLen);
+ pair->value[valueLen] = 0;
+
+ i->numPairs += 1;
+}
+
+const char*
+iniFile_getValue( IniFile* i, const char* key )
+{
+ if (i && key) {
+ int nn;
+
+ for (nn = 0; nn < i->numPairs; nn++) {
+ if (!strcmp(i->pairs[nn].key,key))
+ return i->pairs[nn].value;
+ }
+ }
+ return NULL;
+}
+
+int
+iniFile_getPairCount( IniFile* i )
+{
+ return i ? i->numPairs : 0;
+}
+
+void
+iniFile_getPair( IniFile* i,
+ int index,
+ const char* *pKey,
+ const char* *pValue )
+{
+ const char* key = NULL;
+ const char* value = NULL;
+
+ if (i && index >= 0 && index < i->numPairs) {
+ key = i->pairs[index].key;
+ value = i->pairs[index].value;
+ }
+ *pKey = key;
+ *pValue = value;
+}
+
+/* NOTE: we avoid using <ctype.h> functions to avoid locale-specific
+ * behaviour that can be the source of strange bugs.
+ */
+
+static const char*
+skipSpaces( const char* p )
+{
+ while (*p == ' ' || *p == '\t')
+ p ++;
+ return p;
+}
+
+static const char*
+skipToEOL( const char* p )
+{
+ while (*p && (*p != '\n' && *p != '\r'))
+ p ++;
+
+ if (*p) {
+ p ++;
+ if (p[-1] == '\r' && p[0] == '\n')
+ p ++;
+ }
+ return p;
+}
+
+static int
+isKeyStartChar( int c )
+{
+ return ((unsigned)(c-'a') < 26 ||
+ (unsigned)(c-'A') < 26 ||
+ c == '_');
+}
+
+static int
+isKeyChar( int c )
+{
+ return isKeyStartChar(c) || ((unsigned)(c-'0') < 10) || (c == '.');
+}
+
+IniFile*
+iniFile_newFromMemory( const char* text, const char* fileName )
+{
+ const char* p = text;
+ IniFile* ini = iniFile_alloc();
+ int lineno = 0;
+
+ if (!fileName)
+ fileName = "<unknownFile>";
+
+ D("%s: parsing as .ini file", fileName);
+
+ while (*p) {
+ const char* key;
+ int keyLen;
+ const char* value;
+ int valueLen;
+
+ lineno += 1;
+
+ /* skip leading whitespace */
+ p = skipSpaces(p);
+
+ /* skip comments and empty lines */
+ if (*p == 0 || *p == ';' || *p == '#' || *p == '\n' || *p == '\r') {
+ p = skipToEOL(p);
+ continue;
+ }
+
+ /* check the key name */
+ key = p++;
+ if (!isKeyStartChar(*key)) {
+ p = skipToEOL(p);
+ W("%s:%d: key name doesn't start with valid character. line ignored",
+ fileName, lineno);
+ continue;
+ }
+
+ while (isKeyChar(*p))
+ p++;
+
+ keyLen = p - key;
+ p = skipSpaces(p);
+
+ /* check the equal */
+ if (*p != '=') {
+ W("%s:%d: missing expected assignment operator (=). line ignored",
+ fileName, lineno);
+ p = skipToEOL(p);
+ continue;
+ }
+ p += 1;
+
+ /* skip spaces before the value */
+ p = skipSpaces(p);
+ value = p;
+
+ /* find the value */
+ while (*p && (*p != '\n' && *p != '\r'))
+ p += 1;
+
+ /* remove trailing spaces */
+ while (p > value && (p[-1] == ' ' || p[-1] == '\t'))
+ p --;
+
+ valueLen = p - value;
+
+ iniFile_addPair(ini, key, keyLen, value, valueLen);
+ D("%s:%d: KEY='%.*s' VALUE='%.*s'", fileName, lineno,
+ keyLen, key, valueLen, value);
+
+ p = skipToEOL(p);
+ }
+
+ return ini;
+}
+
+IniFile*
+iniFile_newFromFile( const char* filepath )
+{
+ FILE* fp = fopen(filepath, "rt");
+ char* text;
+ long size;
+ IniFile* ini = NULL;
+
+ if (fp == NULL) {
+ W("could not open .ini file: %s: %s",
+ filepath, strerror(errno));
+ return NULL;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ /* avoid reading a very large file that was passed by mistake
+ * this threshold is quite liberal.
+ */
+#define MAX_INI_FILE_SIZE 655360
+
+ if (size < 0 || size > MAX_INI_FILE_SIZE) {
+ W("hardware configuration file '%s' too large (%ld bytes)",
+ filepath, size);
+ goto EXIT;
+ }
+
+ /* read the file, add a sentinel at the end of it */
+ text = malloc(size+1);
+ fread(text, 1, size, fp);
+ text[size] = 0;
+
+ ini = iniFile_newFromMemory(text, filepath);
+ free(text);
+
+EXIT:
+ fclose(fp);
+ return ini;
+}
+
+char*
+iniFile_getString( IniFile* f, const char* key )
+{
+ const char* val = iniFile_getValue(f, key);
+
+ if (!val)
+ return NULL;
+
+ return qemu_strdup(val);
+}
+
+int
+iniFile_getInteger( IniFile* f, const char* key, int defaultValue )
+{
+ const char* valueStr = iniFile_getValue(f, key);
+ int value = defaultValue;
+
+ if (valueStr != NULL) {
+ char* end;
+ long l = strtol(valueStr, &end, 10);
+ if (end != NULL && end[0] == 0 && (int)l == l)
+ value = l;
+ }
+ return value;
+}
+
+double
+iniFile_getDouble( IniFile* f, const char* key, double defaultValue )
+{
+ const char* valueStr = iniFile_getValue(f, key);
+ double value = defaultValue;
+
+ if (valueStr != NULL) {
+ char* end;
+ double d = strtod(valueStr, &end);
+ if (end != NULL && end[0] == 0)
+ value = d;
+ }
+ return value;
+}
+
+int
+iniFile_getBoolean( IniFile* f, const char* key, const char* defaultValue )
+{
+ const char* value = iniFile_getValue(f, key);
+
+ if (!value)
+ value = defaultValue;
+
+ if (!strcmp(value,"1") ||
+ !strcmp(value,"yes") ||
+ !strcmp(value,"YES") ||
+ !strcmp(value,"true") ||
+ !strcmp(value,"TRUE"))
+ {
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int64_t
+iniFile_getDiskSize( IniFile* f, const char* key, const char* defaultValue )
+{
+ const char* valStr = iniFile_getValue(f, key);
+ int64_t value = 0;
+
+ if (!valStr)
+ valStr = defaultValue;
+
+ if (valStr != NULL) {
+ char* end;
+
+ value = strtoll(valStr, &end, 10);
+ if (*end == 'k' || *end == 'K')
+ value *= 1024ULL;
+ else if (*end == 'm' || *end == 'M')
+ value *= 1024*1024ULL;
+ else if (*end == 'g' || *end == 'G')
+ value *= 1024*1024*1024ULL;
+ }
+ return value;
+}
diff --git a/android/utils/ini.h b/android/utils/ini.h
new file mode 100644
index 0000000..41b369b
--- /dev/null
+++ b/android/utils/ini.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 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.
+*/
+#ifndef _ANDROID_UTILS_INI_H
+#define _ANDROID_UTILS_INI_H
+
+#include <stdint.h>
+
+/* the emulator supports a simple .ini file format for its configuration
+ * files. Here's the BNF for it:
+ *
+ * file := <line>*
+ * line := <comment> | <LF> | <assignment>
+ * comment := (';'|'#') <noLF>* <LF>
+ * assignment := <space>* <keyName> <space>* '=' <space>* <valueString> <space>* <LF>
+ * keyName := <keyNameStartChar> <keyNameChar>*
+ * keyNameStartChar := [A-Za-z_]
+ * keyNameChar := [A-Za-z0-9_.]
+ * valueString := <noLF>*
+ * space := ' ' | '\t'
+ * LF := '\r\n' | '\n' | '\r'
+ * noLF := [^<LF>]
+ *
+ * Or, in English:
+ *
+ * - no support for sections
+ * - empty lines are ignored, as well as lines beginning with ';' or '#'
+ * - lines must be of the form: "<keyName> = <value>"
+ * - key names must start with a letter or an underscore
+ * - other key name characters can be letters, digits, underscores or dots
+ *
+ * - leading and trailing space are allowed and ignored before/after the key name
+ * and before/after the value
+ *
+ * - there is no restriction on the value, except that it can't contain
+ * leading/trailing space/tab characters or newline/charfeed characters
+ *
+ * - empty values are possible, and will be stored as an empty string.
+ * - any badly formatted line is discarded (and will print a warning)
+ *
+ */
+
+/* an opaque structure used to model an .ini configuration file */
+typedef struct IniFile IniFile;
+
+/* creates a new IniFile object from a config file loaded in memory.
+ * 'fileName' is only used when writing a warning to stderr in case
+ * of badly formed output
+ */
+IniFile* iniFile_newFromMemory( const char* text, const char* fileName );
+
+/* creates a new IniFile object from a file path,
+ * returns NULL if the file cannot be opened.
+ */
+IniFile* iniFile_newFromFile( const char* filePath);
+
+/* free an IniFile object */
+void iniFile_free( IniFile* f );
+
+/* returns the number of (key.value) pairs in an IniFile */
+int iniFile_getPairCount( IniFile* f );
+
+/* return a specific (key,value) pair from an IniFile.
+ * if the index is not correct, both '*pKey' and '*pValue' will be
+ * set to NULL.
+ *
+ * you should probably use iniFile_getValue() and its variants instead
+ */
+void iniFile_getPair( IniFile* f,
+ int index,
+ const char* *pKey,
+ const char* *pValue );
+
+/* returns the value of a given key from an IniFile.
+ * NULL if the key is not assigned in the corresponding configuration file
+ */
+const char* iniFile_getValue( IniFile* f, const char* key );
+
+/* returns a copy of the value of a given key, or NULL
+ */
+char* iniFile_getString( IniFile* f, const char* key );
+
+/* returns an integer value, or a default in case the value string is
+ * missing or badly formatted
+ */
+int iniFile_getInteger( IniFile* f, const char* key, int defaultValue );
+
+/* returns a double value, or a default in case the value string is
+ * missing or badly formatted
+ */
+double iniFile_getDouble( IniFile* f, const char* key, double defaultValue );
+
+/* returns a copy of a given key's value, if any, or NULL if it is missing
+ * caller must call free() to release it */
+char* iniFile_getString( IniFile* f, const char* key );
+
+/* parses a key value as a boolean. Accepted values are "1", "0", "yes", "YES",
+ * "no" and "NO". Returns either 1 or 0.
+ * note that the default value must be provided as a string too
+ */
+int iniFile_getBoolean( IniFile* f, const char* key, const char* defaultValue );
+
+/* parses a key value as a disk size. this means it can be an integer followed
+ * by a suffix that can be one of "mMkKgG" which correspond to KiB, MiB and GiB
+ * multipliers.
+ *
+ * NOTE: we consider that 1K = 1024, not 1000.
+ */
+int64_t iniFile_getDiskSize( IniFile* f, const char* key, const char* defaultValue );
+
+/* */
+
+#endif /* _ANDROID_UTILS_INI_H */
diff --git a/android/vm/hardware-properties.ini b/android/vm/hardware-properties.ini
new file mode 100644
index 0000000..3589e45
--- /dev/null
+++ b/android/vm/hardware-properties.ini
@@ -0,0 +1,158 @@
+# This file describes the properties of a given virtual device configuration file.
+#
+# Note: Most top-level properties are boolean that control whether a feature is
+# present or not. Sub-features that depend on it are ignored if their
+# parent is set to 'false' or 'no'
+#
+# This file is parsed by 'android/tools/gen-hw-config.py' to generate
+# 'android/vm/hw-config-defs.h'. The latter is a special header containing
+# macro statements that is used several times:
+#
+# - once to define the fields of the AndroidHwConfig structure
+# (see android/vm/hw-config.h)
+#
+# - once to implement the hardware configuration loader
+# (see android/vm/hw-config.h)
+#
+# Hopefully, this file should also be read by a virtual device creation
+# tool/wizard to provide a nice user interface (hence the presence of
+# the 'abstract' and 'description' keys which are not currently used)
+#
+#
+# NOTE: if you remove items from this file, be sure that you do not break
+# the emulator build.
+#
+
+# Ram size
+name = hw.ramSize
+type = integer
+default = 96
+abstract = Device ram size
+description = The amount of physical RAM on the device, in megabytes.
+
+# Touch screen support
+name = hw.touchScreen
+type = boolean
+default = yes
+abstract = Touch-screen support
+description = Whether there is a touch screen or not on the device.
+
+# Trackball support
+name = hw.trackBall
+type = boolean
+default = yes
+abstract = Track-ball support
+description = Whether there is a trackball on the device.
+
+# Keyboard support (qwerty/azerty)
+name = hw.keyboard
+type = boolean
+default = yes
+abstract = Keyboard support
+description = Whether the device has a QWERTY keyboard.
+
+# DPad keys
+name = hw.dPad
+type = boolean
+default = yes
+abstract = DPad support
+description = Whether the device has DPad keys
+
+# GSM Modem support
+name = hw.gsmModem
+type = boolean
+default = yes
+abstract = GSM modem support
+description = Whether there is a GSM modem in the device.
+
+# Wifi support
+name = hw.wifi
+type = boolean
+default = no
+abstract = Wifi support
+description = Whether the device has a Wifi chipset.
+
+# Bluetooth support
+name = hw.bluetooth
+type = boolean
+default = no
+abstract = Bluetooth support
+description = Whether the device has a Bluetooth chipset.
+
+# Camera support
+name = hw.camera
+type = boolean
+default = no
+abstract = Camera support
+description = Whether the device has a camera.
+
+name = hw.camera.maxHorizontalPixels
+type = integer
+default = 640
+abstract = Maximum horizontal camera pixels
+
+name = hw.camera.maxVerticalPixels
+type = integer
+default = 480
+abstract = Maximum vertical camera pixels
+
+# GPS support
+name = hw.gps
+type = boolean
+default = no
+abstract = GPS support
+description = Whether there is a GPS in the device.
+
+# Accelerometer
+name = hw.accelerometer
+type = boolean
+default = no
+abstract = Accelerometer support
+description = Whether there is an accelerometer in the device.
+
+# Battery
+name = hw.battery
+type = boolean
+default = yes
+abstract = Battery support
+description = Whether the device can run on a battery.
+
+# Audio input
+name = hw.audioInput
+type = boolean
+default = yes
+abstract = Audio recording support
+description = Whether the device can record audio
+
+# Audio output
+name = hw.audioOutput
+type = boolean
+default = yes
+abstract = Audio playback support
+description = Whether the device can play audio
+
+# Compass
+name = hw.compass
+type = boolean
+default = no
+abstract = Compass support
+description = Whether there is a compass in the device.
+
+# SDCard support
+name = hw.sdCard
+type = boolean
+default = yes
+abstract = SD Card support
+description = Whether the device supports insertion/removal of virtual SD Cards.
+
+# Cache partition
+name = disk.cachePartition
+type = boolean
+default = yes
+abstract = Cache partition support
+description = Whether we use a /cache partition on the device.
+
+name = disk.cachePartition.size
+type = diskSize
+abstract = Cache partition size
+default = 66MB
diff --git a/android/vm/hw-config-defs.h b/android/vm/hw-config-defs.h
new file mode 100644
index 0000000..5c3b9ab
--- /dev/null
+++ b/android/vm/hw-config-defs.h
@@ -0,0 +1,165 @@
+/* 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_INT(
+ hw_ramSize,
+ "hw.ramSize",
+ 96,
+ "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_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_wifi,
+ "hw.wifi",
+ "no",
+ "Wifi support",
+ "Whether the device has a Wifi chipset.")
+
+HWCFG_BOOL(
+ hw_bluetooth,
+ "hw.bluetooth",
+ "no",
+ "Bluetooth support",
+ "Whether the device has a Bluetooth chipset.")
+
+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",
+ "no",
+ "GPS support",
+ "Whether there is a GPS in the device.")
+
+HWCFG_BOOL(
+ hw_accelerometer,
+ "hw.accelerometer",
+ "no",
+ "Accelerometer support",
+ "Whether there is an accelerometer in the device.")
+
+HWCFG_BOOL(
+ hw_battery,
+ "hw.battery",
+ "yes",
+ "Battery support",
+ "Whether the device can run on a battery.")
+
+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_compass,
+ "hw.compass",
+ "no",
+ "Compass support",
+ "Whether there is a compass in the device.")
+
+HWCFG_BOOL(
+ hw_sdCard,
+ "hw.sdCard",
+ "yes",
+ "SD Card support",
+ "Whether the device supports insertion/removal of virtual SD Cards.")
+
+HWCFG_BOOL(
+ disk_cachePartition,
+ "disk.cachePartition",
+ "yes",
+ "Cache partition support",
+ "Whether we use a /cache partition on the device.")
+
+HWCFG_DISKSIZE(
+ disk_cachePartition_size,
+ "disk.cachePartition.size",
+ "66MB",
+ "Cache partition size",
+ "")
+
+#undef HWCFG_INT
+#undef HWCFG_BOOL
+#undef HWCFG_DISKSIZE
+#undef HWCFG_STRING
+#undef HWCFG_DOUBLE
+/* end of auto-generated file */
diff --git a/android/vm/hw-config.c b/android/vm/hw-config.c
new file mode 100644
index 0000000..7018d32
--- /dev/null
+++ b/android/vm/hw-config.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 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 "android/vm/hw-config.h"
+#include "android/utils/ini.h"
+#include <string.h>
+#include <stdlib.h>
+
+
+/* the global variable containing the hardware config for this device */
+AndroidHwConfig android_hw[1];
+
+int
+androidHwConfig_read( AndroidHwConfig* config,
+ IniFile* ini )
+{
+ if (ini == NULL)
+ return -1;
+
+ /* use the magic of macros to implement the hardware configuration loaded */
+
+#define HWCFG_BOOL(n,s,d,a,t) config->n = iniFile_getBoolean(ini, s, d);
+#define HWCFG_INT(n,s,d,a,t) config->n = iniFile_getInteger(ini, s, d);
+#define HWCFG_STRING(n,s,d,a,t) config->n = iniFile_getString(ini, s, d);
+#define HWCFG_DOUBLE(n,s,d,a,t) config->n = iniFile_getDouble(ini, s, d);
+#define HWCFG_DISKSIZE(n,s,d,a,t) config->n = iniFile_getDiskSize(ini, s, d);
+
+#include "android/vm/hw-config-defs.h"
+
+ return 0;
+}
diff --git a/android/vm/hw-config.h b/android/vm/hw-config.h
new file mode 100644
index 0000000..0ab231d
--- /dev/null
+++ b/android/vm/hw-config.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 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.
+*/
+#ifndef _ANDROID_VM_HW_CONFIG_H
+#define _ANDROID_VM_HW_CONFIG_H
+
+#include <stdint.h>
+#include "android/utils/ini.h"
+
+typedef char hw_bool_t;
+typedef int hw_int_t;
+typedef int64_t hw_disksize_t;
+typedef char* hw_string_t;
+typedef double hw_double_t;
+
+/* these macros are used to define the fields of AndroidHwConfig
+ * declared below
+ */
+#define HWCFG_BOOL(n,s,d,a,t) hw_bool_t n;
+#define HWCFG_INT(n,s,d,a,t) hw_int_t n;
+#define HWCFG_STRING(n,s,d,a,t) hw_string_t n;
+#define HWCFG_DOUBLE(n,s,d,a,t) hw_double_t n;
+#define HWCFG_DISKSIZE(n,s,d,a,t) hw_disksize_t n;
+
+typedef struct {
+#include "android/vm/hw-config-defs.h"
+} AndroidHwConfig;
+
+/* reads a hardware configuration file from disk.
+ * returns -1 if the file could not be read, or 0 in case of success.
+ *
+ * note that default values are written to hwConfig if the configuration
+ * file doesn't have the corresponding hardware properties.
+ */
+int androidHwConfig_read( AndroidHwConfig* hwConfig,
+ IniFile* configFile );
+
+#endif /* _ANDROID_VM_HW_CONFIG_H */
diff --git a/android/vm/info.c b/android/vm/info.c
new file mode 100644
index 0000000..e3f04ff
--- /dev/null
+++ b/android/vm/info.c
@@ -0,0 +1,1534 @@
+/* Copyright (C) 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 "android/vm/info.h"
+#include "android_utils.h"
+#include "android/utils/debug.h"
+#include "android/utils/dirscanner.h"
+#include "osdep.h"
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* global variables - see android/globals.h */
+AvmInfoParams android_vmParams[1];
+AvmInfo* android_vmInfo;
+
+/* for debugging */
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+#define DD(...) VERBOSE_PRINT(vm_config,__VA_ARGS__)
+
+/* technical note on how all of this is supposed to work:
+ *
+ * we assume the following SDK layout:
+ *
+ * SDK/
+ * tools/
+ * emulator[.exe]
+ * libs/
+ * hardware-properties.ini
+ * ...
+ *
+ * platforms/
+ * <platform1>/
+ * build.prop
+ * images/
+ * <default kernel/disk images>
+ * skins/
+ * default/ --> default skin
+ * layout
+ * <skin bitmaps>
+ * <skin2>/ --> another skin
+ * layout
+ * <skin bitmaps>
+ * <skin3>/ --> skin alias to <skin2>
+ * alias-<skin2>
+ *
+ * <platform2>/
+ * build.prop
+ * images/
+ * <other default kernel/disk images>
+ *
+ * add-ons/
+ * <partner1>/
+ * manifest.ini
+ * images/
+ * <replacement disk images>
+ *
+ * <partner2>/
+ * manifest.ini
+ * <replacement disk images>
+ * hardware.ini
+ * skins/
+ * default/
+ * layout
+ * <skin bitmaps>
+ * <skin2>/
+ * layout
+ * <skin bitmaps>
+ *
+ *
+ * we define a 'platform' as a directory that provides a complete
+ * set of disk/kernel images, some skins, as well as a build.prop
+ * file.
+ *
+ * we define an 'addon' as a directory that provides additionnal
+ * or replacement files related to a given existing platform.
+ * each add-on provides at the minimum a 'manifest.ini' file
+ * that describes it (see below).
+ *
+ * important notes:
+ *
+ * - the build.prop file of a given platform directory contains
+ * a line that reads 'ro.build.version.sdk=<version>' where
+ * <version> is an integer corresponding to the corresponding
+ * official API version number as defined by Android.
+ *
+ * each platform provided with the SDK must have a unique
+ * version number.
+ *
+ * - the manifest.ini of a given addon must contain lines
+ * that include:
+ *
+ * name=<addOnName>
+ * vendor=<vendorName>
+ * api=<version>
+ *
+ * where <version> is used to identify the platform the add-on
+ * refers to. Note that the platform's directory name is
+ * irrelevant to the matching algorithm.
+ *
+ * each addon available must have a unique
+ * <vendor>:<name>:<sdk> triplet
+ *
+ * - an add-on can provide a hardware.ini file. If present, this
+ * is used to force the hardware setting of any virtual machine
+ * built from the add-on.
+ *
+ * - the file in SDK/tools/lib/hardware-properties.ini declares which
+ * hardware properties are supported by the emulator binary.
+ * these can appear in the config.ini file of a given virtual
+ * machine, or the hardware.ini of a given add-on.
+ *
+ * normally, a virtual machine corresponds to:
+ *
+ * - a root configuration file, placed in ~/.android/vm/<foo>.ini
+ * where <foo> is the name of the virtual machine.
+ *
+ * - a "content" directory, which contains disk images for the
+ * virtual machine (e.g. at a minimum, the userdata.img file)
+ * plus some configuration information.
+ *
+ * - the root config file must have at least two lines like:
+ *
+ * path=<pathToContentDirectory>
+ * target=<targetAddonOrPlatform>
+ *
+ * the 'path' value must point to the location of
+ * the virtual machine's content directory. By default, this
+ * should be ~/.android/vm/<foo>/, though the user should be
+ * able to choose an alternative path at creation time.
+ *
+ * the 'target' value can be one of:
+ *
+ * android-<version>
+ * <vendor>:<name>:<version>
+ *
+ * the first form is used to refer to a given platform.
+ * the second form is used to refer to a unique add-on.
+ * in both forms, <version> must be an integer that
+ * matches one of the available platforms.
+ *
+ * <vendor>:<name>:<version> must match the triplet of one
+ * of the available add-ons
+ *
+ * if the target value is incorrect, or if the content path
+ * is invalid, the emulator will abort with an error.
+ *
+ * - the content directory shall contain a 'config.ini' that
+ * contains hardware properties for the virtual machine
+ * (as defined by SDK/tools/lib/hardware-properties.ini), as
+ * well as additional lines like:
+ *
+ * sdcard=<pathToDefaultSDCard>
+ * skin=<defaultSkinName>
+ * options=<additionalEmulatorStartupOptions>
+ *
+ *
+ * Finally, to find the skin to be used with a given virtual
+ * machine, the following logic is used:
+ *
+ * - if no skin name has been manually specified on
+ * the command line, or in the config.ini file,
+ * look in $CONTENT/skin/layout and use it if available.
+ *
+ * - otherwise, set SKINNAME to 'default' if not manually
+ * specified, and look for $ADDON/skins/$SKINNAME/layout
+ * and use it if available
+ *
+ * - otherwise, look for $PLATFORM/skins/$SKINNAME/layout
+ * and use it if available.
+ *
+ * - otherwise, look for $PLATFORM/skins/$SKINNAME/alias-<other>.
+ * if a file exist by that name, look at $PLATFORM/skins/<other>/layout
+ * and use it if available. Aliases are not recursives :-)
+ */
+
+/* now, things get a little bit more complicated when working
+ * within the Android build system. In this mode, which can be
+ * detected by looking at the definition of the ANDROID_PRODUCT_OUT
+ * environment variable, we're going to simply pick the image files
+ * from the out directory, or from $BUILDROOT/prebuilt
+ */
+
+/* the name of the $SDKROOT subdirectory that contains all platforms */
+#define PLATFORMS_SUBDIR "platforms"
+
+/* the name of the $SDKROOT subdirectory that contains add-ons */
+#define ADDONS_SUBDIR "add-ons"
+
+/* this is the subdirectory of $HOME/.android where all
+ * root configuration files (and default content directories)
+ * are located.
+ */
+#define ANDROID_VM_DIR "vm"
+
+/* 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
+ * to collision depending on the image type.
+ *
+ * the enumeration below is used to record information about
+ * each image file path.
+ *
+ * READONLY means that the file will be mounted read-only
+ * and this doesn't need to be locked. must be first in list
+ *
+ * MUSTLOCK means that the file should be locked before
+ * being mounted by the emulator
+ *
+ * TEMPORARY means that the file has been copied to a
+ * temporary image, which can be mounted read/write
+ * but doesn't require locking.
+ */
+typedef enum {
+ IMAGE_STATE_READONLY, /* unlocked */
+ IMAGE_STATE_MUSTLOCK, /* must be locked */
+ IMAGE_STATE_LOCKED, /* locked */
+ IMAGE_STATE_LOCKED_EMPTY, /* locked and empty */
+ IMAGE_STATE_TEMPORARY, /* copied to temp file (no lock needed) */
+} AvmImageState;
+
+struct AvmInfo {
+ /* for the Android build system case */
+ char inAndroidBuild;
+ char* androidOut;
+ char* androidBuildRoot;
+
+ /* for the normal virtual machine case */
+ char* machineName;
+ char* sdkRootPath;
+ int platformVersion;
+ char* platformPath;
+ char* addonTarget;
+ char* addonPath;
+ char* contentPath;
+ IniFile* rootIni; /* root <foo>.ini file */
+ IniFile* configIni; /* virtual machine's config.ini */
+
+ /* for both */
+ char* skinName; /* skin name */
+ char* skinDirPath; /* skin directory */
+
+ /* image files */
+ char* imagePath [ AVM_IMAGE_MAX ];
+ char imageState[ AVM_IMAGE_MAX ];
+};
+
+
+void
+avmInfo_free( AvmInfo* i )
+{
+ if (i) {
+ int nn;
+
+ for (nn = 0; nn < AVM_IMAGE_MAX; nn++)
+ qemu_free(i->imagePath[nn]);
+
+ qemu_free(i->skinName);
+ qemu_free(i->skinDirPath);
+
+ if (i->configIni) {
+ iniFile_free(i->configIni);
+ i->configIni = NULL;
+ }
+
+ if (i->rootIni) {
+ iniFile_free(i->rootIni);
+ i->rootIni = NULL;
+ }
+
+ qemu_free(i->contentPath);
+ qemu_free(i->sdkRootPath);
+
+ if (i->inAndroidBuild) {
+ qemu_free(i->androidOut);
+ qemu_free(i->androidBuildRoot);
+ } else {
+ qemu_free(i->platformPath);
+ qemu_free(i->addonTarget);
+ qemu_free(i->addonPath);
+ }
+
+ qemu_free(i->machineName);
+ qemu_free(i);
+ }
+}
+
+/* list of default file names for each supported image file type */
+static const char* const _imageFileNames[ AVM_IMAGE_MAX ] = {
+#define _AVM_IMG(x,y,z) y,
+ AVM_IMAGE_LIST
+#undef _AVM_IMG
+};
+
+/* list of short text description for each supported image file type */
+static const char* const _imageFileText[ AVM_IMAGE_MAX ] = {
+#define _AVM_IMG(x,y,z) z,
+ AVM_IMAGE_LIST
+#undef _AVM_IMG
+};
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** NORMAL VIRTUAL MACHINE SUPPORT
+ *****
+ *****/
+
+/* compute path to the root SDK directory
+ * assume we are in $SDKROOT/tools/emulator[.exe]
+ */
+static int
+_getSdkRoot( AvmInfo* i )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ (void) bufprint_app_dir(temp, end);
+
+ i->sdkRootPath = path_parent(temp, 1);
+ if (i->sdkRootPath == NULL) {
+ derror("can't find root of SDK directory");
+ return -1;
+ }
+ D("found SDK root at %s", i->sdkRootPath);
+ return 0;
+}
+
+/* returns the full path of the platform subdirectory
+ * corresponding to a given API version
+ */
+static char*
+_findPlatformByVersion( const char* sdkRoot, int version )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof temp;
+ char* subdir = NULL;
+ DirScanner* scanner;
+
+ DD("> %s(%s,%d)", __FUNCTION__, sdkRoot, version);
+ p = bufprint(temp, end, "%s/%s", sdkRoot, PLATFORMS_SUBDIR);
+ if (p >= end) {
+ DD("! path too long");
+ return NULL;
+ }
+
+ scanner = dirScanner_new(temp);
+ if (scanner == NULL) {
+ DD("! cannot scan path %s: %s", temp, strerror(errno));
+ return NULL;
+ }
+
+ for (;;) {
+ IniFile* ini;
+ int apiVersion;
+
+ subdir = (char*) dirScanner_nextFull(scanner);
+ if (subdir == NULL)
+ break;
+
+ /* look for a file named "build.prop */
+ p = bufprint(temp, end, "%s/build.prop", subdir);
+ if (p >= end)
+ continue;
+
+ if (!path_exists(temp)) {
+ DD("! no file at %s", temp);
+ continue;
+ }
+
+ ini = iniFile_newFromFile(temp);
+ if (ini == NULL)
+ continue;
+
+ apiVersion = iniFile_getInteger(ini, "ro.build.version.sdk", -1);
+ iniFile_free(ini);
+
+ DD("! found %s (version %d)", temp, apiVersion);
+
+ if (apiVersion == version) {
+ /* Bingo */
+ subdir = qemu_strdup(subdir);
+ break;
+ }
+ }
+
+ if (!subdir) {
+ DD("< didn't found anything");
+ }
+
+ dirScanner_free(scanner);
+ return subdir;
+}
+
+/* returns the full path of the addon corresponding to a given target,
+ * or NULL if not found. on success, *pversion will contain the SDK
+ * version number
+ */
+static char*
+_findAddonByTarget( const char* sdkRoot, const char* target, int *pversion )
+{
+ char* targetCopy = qemu_strdup(target);
+ char* targetVendor = NULL;
+ char* targetName = NULL;
+ int targetVersion = -1;
+
+ char temp[PATH_MAX];
+ char* p;
+ char* end;
+ DirScanner* scanner;
+ char* subdir;
+
+ DD("> %s(%s,%s)", __FUNCTION__, sdkRoot, target);
+
+ /* extract triplet from target string */
+ targetVendor = targetCopy;
+
+ p = strchr(targetVendor, ':');
+ if (p == NULL) {
+ DD("< missing first column separator");
+ goto FAIL;
+ }
+ *p = 0;
+ targetName = p + 1;
+ p = strchr(targetName, ':');
+ if (p == NULL) {
+ DD("< missing second column separator");
+ goto FAIL;
+ }
+ *p++ = 0;
+
+ targetVersion = atoi(p);
+
+ if (targetVersion == 0) {
+ DD("< invalid version number");
+ goto FAIL;
+ }
+ /* now scan addons directory */
+ p = temp;
+ end = p + sizeof temp;
+
+ p = bufprint(p, end, "%s/%s", sdkRoot, ADDONS_SUBDIR);
+ if (p >= end) {
+ DD("< add-on path too long");
+ goto FAIL;
+ }
+ scanner = dirScanner_new(temp);
+ if (scanner == NULL) {
+ DD("< cannot scan add-on path %s: %s", temp, strerror(errno));
+ goto FAIL;
+ }
+ for (;;) {
+ IniFile* ini;
+ const char* vendor;
+ const char* name;
+ int version;
+ int matches;
+
+ subdir = (char*) dirScanner_nextFull(scanner);
+ if (subdir == NULL)
+ break;
+
+ /* try to open the manifest.ini file */
+ p = bufprint(temp, end, "%s/manifest.ini", subdir);
+ if (p >= end)
+ continue;
+
+ ini = iniFile_newFromFile(temp);
+ if (ini == NULL)
+ continue;
+
+ DD("! scanning manifest.ini in %s", temp);
+
+ /* find the vendor, name and version */
+ vendor = iniFile_getValue(ini, "vendor");
+ name = iniFile_getValue(ini, "name");
+ version = iniFile_getInteger(ini, "api", -1);
+
+ matches = 0;
+
+ matches += (version == targetVersion);
+ matches += (vendor && !strcmp(vendor, targetVendor));
+ matches += (name && !strcmp(name, targetName));
+
+ DD("! matches=%d vendor=[%s] name=[%s] version=%d",
+ matches,
+ vendor ? vendor : "<NULL>",
+ name ? name : "<NULL>",
+ version);
+
+ iniFile_free(ini);
+
+ if (matches == 3) {
+ /* bingo */
+ *pversion = version;
+ subdir = qemu_strdup(subdir);
+ break;
+ }
+ }
+
+ dirScanner_free(scanner);
+
+ DD("< returning %s", subdir ? subdir : "<NULL>");
+ return subdir;
+
+FAIL:
+ qemu_free(targetCopy);
+ return NULL;
+}
+
+static int
+_checkAvmName( const char* name )
+{
+ int len = strlen(name);
+ int len2 = strspn(name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789_.-");
+ return (len == len2);
+}
+
+/* parse the root config .ini file. it is located in
+ * ~/.android/vm/<name>.ini or Windows equivalent
+ */
+static int
+_getRootIni( AvmInfo* i )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ p = bufprint_config_path(temp, end);
+ p = bufprint(p, end, "/" ANDROID_VM_DIR "/%s.ini", i->machineName);
+ if (p >= end) {
+ derror("machine name too long");
+ return -1;
+ }
+
+ i->rootIni = iniFile_newFromFile(temp);
+ if (i->rootIni == NULL) {
+ derror("unknown virtual machine name: '%s'", i->machineName);
+ return -1;
+ }
+ D("root virtual machine file at %s", temp);
+ return 0;
+}
+
+/* the .ini variable name that points to the content directory
+ * in a root AVM ini file. This is required */
+# define ROOT_PATH_KEY "path"
+# define ROOT_TARGET_KEY "target"
+
+/* retrieve the content path and target from the root .ini file */
+static int
+_getTarget( AvmInfo* i )
+{
+ i->contentPath = iniFile_getString(i->rootIni, ROOT_PATH_KEY);
+ i->addonTarget = iniFile_getString(i->rootIni, ROOT_TARGET_KEY);
+
+ iniFile_free(i->rootIni);
+ i->rootIni = NULL;
+
+ if (i->contentPath == NULL) {
+ derror("bad config: %s",
+ "virtual machine file lacks a "ROOT_PATH_KEY" entry");
+ return -1;
+ }
+
+ if (i->addonTarget == NULL) {
+ derror("bad config: %s",
+ "virtual machine file lacks a "ROOT_TARGET_KEY" entry");
+ return -1;
+ }
+
+ D("virtual machine content at %s", i->contentPath);
+ D("virtual machine target is %s", i->addonTarget);
+
+ if (!strncmp(i->addonTarget, "android-", 8)) { /* target is platform */
+ char* end;
+ const char* versionString = i->addonTarget+8;
+ int version = (int) strtol(versionString, &end, 10);
+ if (*end != 0 || version <= 0) {
+ derror("bad config: invalid platform version: '%s'", versionString);
+ return -1;
+ }
+ i->platformVersion = version;
+ i->platformPath = _findPlatformByVersion(i->sdkRootPath,
+ version);
+ if (i->platformPath == NULL) {
+ derror("bad config: unknown platform version: '%d'", version);
+ return -1;
+ }
+ }
+ else /* target is add-on */
+ {
+ i->addonPath = _findAddonByTarget(i->sdkRootPath, i->addonTarget,
+ &i->platformVersion);
+ if (i->addonPath == NULL) {
+ derror("bad config: %s",
+ "unknown add-on target: '%s'", i->addonTarget);
+ return -1;
+ }
+
+ i->platformPath = _findPlatformByVersion(i->sdkRootPath,
+ i->platformVersion);
+ if (i->platformPath == NULL) {
+ derror("bad config: %s",
+ "unknown add-on platform version: '%d'", i->platformVersion);
+ return -1;
+ }
+ D("virtual machine add-on path: %s", i->addonPath);
+ }
+ D("virtual machine platform path: %s", i->platformPath);
+ D("virtual machine platform version %d", i->platformVersion);
+ return 0;
+}
+
+
+/* find and parse the config.ini file from the content directory */
+static int
+_getConfigIni(AvmInfo* 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 machine 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 machine has no config file - no problem");
+ return 0;
+ }
+#endif
+
+ i->configIni = iniFile_newFromFile(temp);
+ if (i->configIni == NULL) {
+ derror("bad config: %s",
+ "virtual machine directory lacks config.ini");
+ return -1;
+ }
+ D("virtual machine config file: %s", temp);
+ return 0;
+}
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** KERNEL/DISK IMAGE LOADER
+ *****
+ *****/
+
+/* a structure used to handle the loading of
+ * kernel/disk images.
+ */
+typedef struct {
+ AvmInfo* info;
+ AvmInfoParams* params;
+ AvmImageType id;
+ const char* imageFile;
+ const char* imageText;
+ char** pPath;
+ char* pState;
+ char temp[PATH_MAX];
+} ImageLoader;
+
+static void
+imageLoader_init( ImageLoader* l, AvmInfo* info, AvmInfoParams* 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, AvmImageType 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 ? qemu_strdup(path) : NULL;
+
+ qemu_free(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 add-on and/or platform
+ * 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 )
+{
+ AvmInfo* i = l->info;
+ char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp);
+
+ do {
+ /* try the add-on directory, if any */
+ if (i->addonPath != NULL) {
+ DD("searching %s in add-on directory: %s",
+ l->imageFile, i->addonPath);
+
+ p = bufprint(temp, end, "%s/images/%s",
+ i->addonPath, l->imageFile);
+
+ if (p < end && path_exists(temp))
+ break;
+ }
+
+ /* or try the platform directory */
+ DD("searching %s in platform directory: %s",
+ l->imageFile, i->platformPath);
+
+ p = bufprint(temp, end, "%s/images/%s",
+ i->platformPath, l->imageFile);
+ if (p < end && path_exists(temp))
+ break;
+
+ DD("could not find %s in SDK", l->imageFile);
+ return NULL;
+
+ } while (0);
+
+ 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 )
+{
+ AvmInfo* i = l->info;
+ char* temp = l->temp, *p = temp, *end = p + sizeof(l->temp);
+
+ DD("searching %s in content directory", l->imageFile);
+ 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("not found %s in content directory", l->imageFile);
+ return NULL;
+ }
+
+ /* 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 (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 (make_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;
+}
+
+
+/* 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 (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]
+ *
+ * returns the path to the file. Note that it returns NULL
+ * only if the file was optional and could not be found.
+ *
+ * if the file is required and missing, the function aborts
+ * the program.
+ */
+static char*
+imageLoader_load( ImageLoader* l,
+ unsigned flags )
+{
+ const char* path = NULL;
+
+ DD("looking for %s image (%s)", l->imageText, l->imageFile);
+
+ /* first, check user-provided path */
+ path = l->params->forcePaths[l->id];
+ if (path != NULL) {
+ imageLoader_setPath(l, path);
+ if (path_exists(path))
+ 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);
+ }
+ }
+ else {
+ const char* contentFile;
+
+ /* second, look in the content directory */
+ path = imageLoader_lookupContent(l);
+ if (path) goto EXIT;
+
+ contentFile = qemu_strdup(l->temp);
+
+ /* it's not there */
+ if (flags & IMAGE_SEARCH_SDK) {
+ /* third, look in the SDK directory */
+ path = imageLoader_lookupSdk(l);
+ if (path) {
+ qemu_free((char*)contentFile);
+ goto EXIT;
+ }
+ }
+ DD("found no %s image (%s)", l->imageText, l->imageFile);
+
+ /* if the file is required, abort */
+ if (flags & IMAGE_REQUIRED) {
+ derror("could not find required %s image (%s)",
+ l->imageText, l->imageFile);
+ exit(2);
+ }
+
+ path = imageLoader_setPath(l, contentFile);
+ qemu_free((char*)contentFile);
+ }
+
+ /* otherwise, do we need to create it ? */
+ if (flags & IMAGE_EMPTY_IF_MISSING) {
+ imageLoader_empty(l, flags);
+ return l->pPath[0];
+ }
+ return NULL;
+
+EXIT:
+ imageLoader_lock(l, flags);
+ return l->pPath[0];
+}
+
+
+
+/* find the correct path of all image files we're going to need
+ * and lock the files that need it.
+ */
+static int
+_getImagePaths(AvmInfo* i, AvmInfoParams* params )
+{
+ int wipeData = (params->flags & AVMINFO_WIPE_DATA) != 0;
+ int wipeCache = (params->flags & AVMINFO_WIPE_CACHE) != 0;
+ int noCache = (params->flags & AVMINFO_NO_CACHE) != 0;
+ int noSdCard = (params->flags & AVMINFO_NO_SDCARD) != 0;
+
+ 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, AVM_IMAGE_KERNEL );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK | IMAGE_DONT_LOCK );
+
+ imageLoader_set ( l, AVM_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, AVM_IMAGE_SYSTEM );
+ imageLoader_load( l, IMAGE_REQUIRED | IMAGE_SEARCH_SDK );
+
+ /* 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, AVM_IMAGE_USERDATA );
+ if ( !imageLoader_load( l, IMAGE_OPTIONAL |
+ IMAGE_EMPTY_IF_MISSING |
+ 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;
+
+ if (imageLoader_lookupSdk(l)) {
+ derror("can't locate initial %s image in SDK",
+ l->imageText);
+ exit(2);
+ }
+ srcPath = imageLoader_extractPath(l);
+
+ imageLoader_copyFrom( l, srcPath );
+ qemu_free((char*) srcPath);
+ }
+ 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, AVM_IMAGE_CACHE);
+ imageLoader_load(l, IMAGE_OPTIONAL |
+ IMAGE_EMPTY_IF_MISSING );
+
+ if (wipeCache) {
+ if (make_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_set (l, AVM_IMAGE_SDCARD);
+ imageLoader_load(l, IMAGE_OPTIONAL |
+ IMAGE_IGNORE_IF_LOCKED);
+
+ /* 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 SD Card path by hand,
+ * warn him. */
+ if (params->forcePaths[AVM_IMAGE_SDCARD] != NULL)
+ dwarning("ignoring non-existing SD Card image");
+
+ imageLoader_setPath(l, NULL);
+ }
+ }
+
+ return 0;
+}
+
+/* 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 of the real skin
+ * directory (after alias expansion, if needed)
+ */
+static int
+_checkSkinDir( char* temp, char* end, const char* skinDirRoot, const char* skinName )
+{
+ DirScanner* scanner;
+ char *p, *q;
+
+ p = bufprint(temp, end, "%s/skins/%s",
+ skinDirRoot, skinName);
+
+ if (p >= end || !path_exists(temp))
+ return -1;
+
+ /* first, is this a normal skin directory ? */
+ q = bufprint(q, end, "/layout");
+ if (q < end && path_exists(temp)) {
+ /* yes */
+ *p = 0;
+ return 1;
+ }
+
+ /* second, is it an alias to another skin ? */
+ *p = 0;
+ scanner = dirScanner_new(temp);
+ if (scanner != NULL) {
+ for (;;) {
+ const char* file = dirScanner_next(scanner);
+
+ if (file == NULL)
+ break;
+
+ if (strncmp(file, "alias-", 6) || file[6] == 0)
+ continue;
+
+ p = bufprint(temp, end, "%s/skins/%s",
+ skinDirRoot, file+6);
+
+ q = bufprint(p, end, "/layout");
+ if (q < end && path_exists(temp)) {
+ /* yes, it's an alias */
+ *p = 0;
+ return 1;
+ }
+ }
+ dirScanner_free(scanner);
+ }
+ return 0;
+}
+
+static int
+_getSkin( AvmInfo* i, AvmInfoParams* params )
+{
+ char* skinName;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ char explicitSkin = 1;
+
+ /* determine the skin name, the default is "default"
+ * unless specified by the caller or in config.ini
+ */
+ if (params->skinName) {
+ skinName = qemu_strdup(params->skinName);
+ } else {
+ skinName = iniFile_getString( i->configIni, "skin" );
+ if (skinName == NULL) {
+ skinName = qemu_strdup("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/layout", i->contentPath);
+ if (p < end && path_exists(temp)) {
+ /* use this one - cheat a little */
+ qemu_free(i->skinName);
+ i->skinName = qemu_strdup("skin");
+ i->skinDirPath = qemu_strdup(i->contentPath);
+ return 0;
+ }
+ }
+
+ /* look in content directory */
+ if (_checkSkinDir(temp, end, i->contentPath, skinName))
+ break;
+
+ /* look in the add-on directory, if any */
+ if (i->addonPath &&
+ _checkSkinDir(temp, end, i->addonPath, skinName))
+ break;
+
+ /* look in the platforms directory */
+ if (_checkSkinDir(temp, end, i->platformPath, skinName))
+ break;
+
+ /* didn't find it */
+ if (explicitSkin)
+ dwarning("could not find directory for skin '%s'", skinName);
+
+ return -1;
+
+ } while (0);
+
+ i->skinDirPath = qemu_strdup(temp);
+ return 0;
+}
+
+
+AvmInfo*
+avmInfo_new( const char* name, AvmInfoParams* params )
+{
+ AvmInfo* i;
+
+ if (name == NULL)
+ return NULL;
+
+ if (!_checkAvmName(name)) {
+ derror("virtual machine name contains invalid characters");
+ exit(1);
+ }
+
+ i = qemu_mallocz(sizeof *i);
+ i->machineName = qemu_strdup(name);
+
+ if ( _getSdkRoot(i) < 0 ||
+ _getRootIni(i) < 0 ||
+ _getTarget(i) < 0 ||
+ _getConfigIni(i) < 0 )
+ goto FAIL;
+
+ if ( _getImagePaths(i, params) < 0 ||
+ _getSkin (i, params) < 0 )
+ goto FAIL;
+
+ return i;
+
+FAIL:
+ avmInfo_free(i);
+ return NULL;
+}
+
+/***************************************************************
+ ***************************************************************
+ *****
+ ***** ANDROID BUILD SUPPORT
+ *****
+ ***** The code below corresponds to the case where we're
+ ***** starting the emulator inside the Android build
+ ***** system. The main differences are that:
+ *****
+ ***** - the $ANDROID_PRODUCT_OUT directory is used as the
+ ***** content file.
+ *****
+ ***** - built images must not be modified by the emulator,
+ ***** so system.img must be copied to a temporary file
+ ***** and userdata.img must be copied to userdata-qemu.img
+ ***** if the latter doesn't exist.
+ *****
+ ***** - the kernel and default skin directory are taken from
+ ***** prebuilt
+ *****
+ ***** - there is no root .ini file, or any config.ini in
+ ***** the content directory, no SDK platform version
+ ***** and no add-on to consider.
+ *****/
+
+/* used to fake a config.ini located in the content directory */
+static int
+_getBuildConfigIni( AvmInfo* i )
+{
+ /* a blank file is ok at the moment */
+ i->configIni = iniFile_newFromMemory( "", 0 );
+ return 0;
+}
+
+static int
+_getBuildImagePaths( AvmInfo* i, AvmInfoParams* params )
+{
+ int wipeData = (params->flags & AVMINFO_WIPE_DATA) != 0;
+ int noCache = (params->flags & AVMINFO_NO_CACHE) != 0;
+ int noSdCard = (params->flags & AVMINFO_NO_SDCARD) != 0;
+
+ 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, AVM_IMAGE_KERNEL );
+
+ if ( !imageLoader_load( l, IMAGE_OPTIONAL |
+ IMAGE_DONT_LOCK ) )
+ {
+#define PREBUILT_KERNEL_PATH "prebuilt/android-arm/kernel/kernel-qemu"
+ 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, AVM_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[AVM_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 (copy_file( l->pPath[0], srcData ) < 0) {
+ derror("could not initialize %s image from %s: %s",
+ l->imageText, temp, strerror(errno));
+ exit(2);
+ }
+ }
+
+ qemu_free(srcData);
+
+ /** load the ramdisk image
+ **/
+ imageLoader_set ( l, AVM_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, AVM_IMAGE_SYSTEM );
+ 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, AVM_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, AVM_IMAGE_SDCARD);
+ imageLoader_load(l, IMAGE_OPTIONAL | IMAGE_IGNORE_IF_LOCKED);
+ }
+
+ return 0;
+}
+
+static int
+_getBuildSkin( AvmInfo* i, AvmInfoParams* 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 = "HVGA";
+ DD("selecting default skin name '%s'", skinName);
+ }
+
+ i->skinName = qemu_strdup(skinName);
+
+ if (!skinDir) {
+
+#define PREBUILT_SKINS_DIR "development/emulator/skins"
+
+ /* the (current) default skin directory */
+ p = bufprint( temp, end, "%s/%s",
+ i->androidBuildRoot, PREBUILT_SKINS_DIR );
+ } else {
+ p = bufprint( temp, end, "%s", skinDir );
+ }
+
+ q = bufprint(p, end, "/%s/layout", skinName);
+ if (q >= end || !path_exists(temp)) {
+ if (skinDir)
+ dwarning("could not find valid skin '%s' in %s:\n",
+ skinName, skinDir);
+ else
+ DD("could not find directory for skin '%s'",
+ skinName);
+ return -1;
+ }
+ *p = 0;
+ DD("found skin path: %s", temp);
+ i->skinDirPath = qemu_strdup(temp);
+
+ return 0;
+}
+
+AvmInfo*
+avmInfo_newForAndroidBuild( const char* androidBuildRoot,
+ const char* androidOut,
+ AvmInfoParams* params )
+{
+ AvmInfo* i;
+
+ i = qemu_mallocz(sizeof *i);
+
+ i->inAndroidBuild = 1;
+ i->androidBuildRoot = qemu_strdup(androidBuildRoot);
+ i->androidOut = qemu_strdup(androidOut);
+ i->contentPath = qemu_strdup(androidOut);
+
+ /* TODO: find a way to provide better information from the build files */
+ i->machineName = qemu_strdup("<build>");
+
+ if (_getBuildConfigIni(i) < 0 ||
+ _getBuildImagePaths(i, params) < 0 )
+ goto FAIL;
+
+ /* we don't need to fail if there is no valid skin */
+ _getBuildSkin(i, params);
+
+ return i;
+
+FAIL:
+ avmInfo_free(i);
+ return NULL;
+}
+
+const char*
+avmInfo_getName( AvmInfo* i )
+{
+ return i ? i->machineName : NULL;
+}
+
+const char*
+avmInfo_getImageFile( AvmInfo* i, AvmImageType imageType )
+{
+ if (i == NULL || (unsigned)imageType >= AVM_IMAGE_MAX)
+ return NULL;
+
+ return i->imagePath[imageType];
+}
+
+int
+avmInfo_isImageReadOnly( AvmInfo* i, AvmImageType imageType )
+{
+ if (i == NULL || (unsigned)imageType >= AVM_IMAGE_MAX)
+ return 1;
+
+ return (i->imageState[imageType] == IMAGE_STATE_READONLY);
+}
+
+const char*
+avmInfo_getSkinName( AvmInfo* i )
+{
+ return i->skinName;
+}
+
+const char*
+avmInfo_getSkinDir ( AvmInfo* i )
+{
+ return i->skinDirPath;
+}
+
+int
+avmInfo_getHwConfig( AvmInfo* i, AndroidHwConfig* hw )
+{
+ IniFile* ini = i->configIni;
+ int ret;
+
+ if (ini == NULL)
+ ini = iniFile_newFromMemory("", 0);
+
+ ret = androidHwConfig_read(hw, ini);
+
+ if (ini != i->configIni)
+ iniFile_free(ini);
+
+ return ret;
+}
+
+
+char*
+avmInfo_getTracePath( AvmInfo* i, const char* traceName )
+{
+ char tmp[MAX_PATH], *p=tmp, *end=p + sizeof(tmp);
+
+ if (i == NULL || traceName == NULL || traceName[0] == 0)
+ return NULL;
+
+ if (i->inAndroidBuild) {
+ p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
+ i->androidOut, traceName );
+ } else {
+ p = bufprint( p, end, "%s" PATH_SEP "traces" PATH_SEP "%s",
+ i->contentPath, traceName );
+ }
+ return qemu_strdup(tmp);
+}
diff --git a/android/vm/info.h b/android/vm/info.h
new file mode 100644
index 0000000..cdad34f
--- /dev/null
+++ b/android/vm/info.h
@@ -0,0 +1,161 @@
+/* Copyright (C) 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.
+*/
+#ifndef ANDROID_VM_INFO_H
+#define ANDROID_VM_INFO_H
+
+#include "android/utils/ini.h"
+#include "android/vm/hw-config.h"
+
+/* An Android Virtual Machine (AVM for short) corresponds to a
+ * directory containing all kernel/disk images for a given virtual
+ * device, as well as information about its hardware capabilities,
+ * SDK version number, skin, etc...
+ *
+ * Each AVM has a human-readable name and is backed by a root
+ * configuration file and a content directory. For example, an
+ * AVM named 'foo' will correspond to the following:
+ *
+ * - a root configuration file named ~/.android/vm/foo.ini
+ * describing where the AVM's content can be found
+ *
+ * - a content directory like ~/.android/vm/foo/ containing all
+ * disk image and configuration files for the virtual device.
+ *
+ * the 'foo.ini' file should contain at least one line of the form:
+ *
+ * rootPath=<content-path>
+ *
+ * it may also contain other lines that cache stuff found in the
+ * content directory, like hardware properties or SDK version number.
+ *
+ * it is possible to move the content directory by updating the foo.ini
+ * file to point to the new location. This can be interesting when your
+ * $HOME directory is located on a network share or in a roaming profile
+ * (Windows), given that the content directory of a single virtual device
+ * can easily use more than 100MB of data.
+ *
+ */
+
+/* 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 _AVM_IMG
+ */
+#define AVM_IMAGE_LIST \
+ _AVM_IMG(KERNEL,"kernel-qemu","kernel") \
+ _AVM_IMG(RAMDISK,"ramdisk.img","ramdisk") \
+ _AVM_IMG(SYSTEM,"system.img","system") \
+ _AVM_IMG(USERDATA,"userdata.img","user data") \
+ _AVM_IMG(CACHE,"cache.img","cache") \
+ _AVM_IMG(SDCARD,"sdcard.img","SD Card") \
+
+/* define the enumared values corresponding to each AVM image type
+ * examples are: AVM_IMAGE_KERNEL, AVM_IMAGE_SYSTEM, etc..
+ */
+#define _AVM_IMG(x,y,z) AVM_IMAGE_##x ,
+typedef enum {
+ AVM_IMAGE_LIST
+ AVM_IMAGE_MAX /* do not remove */
+} AvmImageType;
+#undef _AVM_IMG
+
+/* AvmInfo is an opaque structure used to model the information
+ * corresponding to a given AVM instance
+ */
+typedef struct AvmInfo AvmInfo;
+
+/* various flags used when creating an AvmInfo object */
+typedef enum {
+ /* use to force a data wipe */
+ AVMINFO_WIPE_DATA = (1 << 0),
+ /* use to ignore the cache partition */
+ AVMINFO_NO_CACHE = (1 << 1),
+ /* use to wipe cache partition, ignored if NO_CACHE is set */
+ AVMINFO_WIPE_CACHE = (1 << 2),
+ /* use to ignore ignore SDCard image (default or provided) */
+ AVMINFO_NO_SDCARD = (1 << 3),
+} AvmFlags;
+
+typedef struct {
+ unsigned flags;
+ const char* skinName;
+ const char* skinRootPath;
+ const char* forcePaths[AVM_IMAGE_MAX];
+} AvmInfoParams;
+
+/* Creates a new AvmInfo object from a name. Returns NULL if name is NULL
+ * or contains characters that are not part of the following list:
+ * letters, digits, underscores, dashes and periods
+ */
+AvmInfo* avmInfo_new( const char* name, AvmInfoParams* params );
+
+/* A special function used to setup an AvmInfo for use when starting
+ * the emulator from the Android build system. In this specific instance
+ * we're going to create temporary files to hold all writable image
+ * files, and activate all hardware features by default
+ *
+ * 'androidBuildRoot' must be the absolute path to the root of the
+ * Android build system (i.e. the 'android' directory)
+ *
+ * 'androidOut' must be the target-specific out directory where
+ * disk images will be looked for.
+ */
+AvmInfo* avmInfo_newForAndroidBuild( const char* androidBuildRoot,
+ const char* androidOut,
+ AvmInfoParams* params );
+
+/* Frees an AvmInfo object and the corresponding strings that may be
+ * returned by its getXXX() methods
+ */
+void avmInfo_free( AvmInfo* i );
+
+/* Return the name of the Android Virtual Machine
+ */
+const char* avmInfo_getName( AvmInfo* i );
+
+/* 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 AvmInfo object.
+ */
+const char* avmInfo_getImageFile( AvmInfo* i, AvmImageType imageType );
+
+/* Returns 1 if the corresponding image file is read-only
+ */
+int avmInfo_isImageReadOnly( AvmInfo* i, AvmImageType imageType );
+
+/* lock an image file if it is writable. returns 0 on success, or -1
+ * otherwise. note that if the file is read-only, it doesn't need to
+ * be locked and the function will return success.
+ */
+int avmInfo_lockImageFile( AvmInfo* i, AvmImageType imageType, int abortOnError);
+
+/* Manually set the path of a given image file. */
+void avmInfo_setImageFile( AvmInfo* i, AvmImageType imageType, const char* imagePath );
+
+/* Returns the path of the skin directory */
+/* the string belongs to the AvmInfo object */
+const char* avmInfo_getSkinPath( AvmInfo* i );
+
+/* Returns the name of the virtual machine's skin */
+const char* avmInfo_getSkinName( AvmInfo* i );
+
+/* Returns the root skin directory for this machine */
+const char* avmInfo_getSkinDir ( AvmInfo* i );
+
+/* Reads the AVM's hardware configuration into 'hw'. returns -1 on error, 0 otherwise */
+int avmInfo_getHwConfig( AvmInfo* i, AndroidHwConfig* hw );
+
+/* Returns a *copy* of the path used to store trace 'foo'. result must be freed by caller */
+char* avmInfo_getTracePath( AvmInfo* i, const char* traceName );
+
+/* */
+
+#endif /* ANDROID_VM_INFO_H */