aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2011-03-25 10:34:47 +0100
committerDavid 'Digit' Turner <digit@android.com>2011-05-02 18:05:18 +0200
commit2d238fd9871687b1557f15b8878a6cf3e9634b57 (patch)
tree1ecdd74927037aea7bc899c78a9cdddefb38ff22
parentec1d38fbb171c45fc8b79734efb80e2c21db6ef8 (diff)
downloadexternal_qemu-2d238fd9871687b1557f15b8878a6cf3e9634b57.zip
external_qemu-2d238fd9871687b1557f15b8878a6cf3e9634b57.tar.gz
external_qemu-2d238fd9871687b1557f15b8878a6cf3e9634b57.tar.bz2
Add 'emulator' launcher program.
This patch renames the current ARM-specific emulator binary to 'emulator-arm' and introduces a new tiny (less than 20KB) 'emulator' launcher program. The role of 'emulator' is to launch either 'emulator-arm' or 'emulator-x86' based on the target AVD or platform build being used. This program will be replaced in the future by what is currently known as 'emulator-ui', but is a good placeholder until this work is completed. + Move some utility functions from android/avd/info.[hc] to android/avd/util.[hc] so that 'emulator' can use them directly. IMPORTANT: For platform builds, the target architecture is detected automatically by parsing the build.prop file. For SDK AVDs however, there is no easy way to determine the target architecture, so the patch adds a new hw.cpu.arch property which can have value 'arm' or 'x86' Change-Id: I0084c196695a75c8b9230ba716b3cd2e12610ded
-rw-r--r--Makefile.android13
-rw-r--r--Makefile.common1
-rw-r--r--Makefile.target5
-rw-r--r--android/avd/hardware-properties.ini16
-rw-r--r--android/avd/hw-config-defs.h14
-rw-r--r--android/avd/info.c226
-rw-r--r--android/avd/util.c304
-rw-r--r--android/avd/util.h57
-rw-r--r--android/main-emulator.c169
-rw-r--r--android/utils/path.c86
-rw-r--r--android/utils/path.h9
-rw-r--r--vl-android.c23
12 files changed, 694 insertions, 229 deletions
diff --git a/Makefile.android b/Makefile.android
index 4b6e211..efc6fc3 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -202,6 +202,19 @@ include $(LOCAL_PATH)/Makefile.target
##############################################################################
##############################################################################
###
+### emulator: LAUNCHER FOR TARGET-SPECIFIC EMULATOR
+###
+###
+$(call start-emulator-program, emulator)
+
+LOCAL_SRC_FILES := android/main-emulator.c
+LOCAL_STATIC_LIBRARIES := emulator-common
+
+$(call end-emulator-program)
+
+##############################################################################
+##############################################################################
+###
### emulator-ui: UI FRONT-END PROGRAM
###
###
diff --git a/Makefile.common b/Makefile.common
index 4bdc8ec..05497c8 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -69,6 +69,7 @@ LOCAL_SRC_FILES += \
android/keycode-array.c \
android/avd/hw-config.c \
android/avd/info.c \
+ android/avd/util.c \
android/sync-utils.c \
android/utils/assert.c \
android/utils/bufprint.c \
diff --git a/Makefile.target b/Makefile.target
index 77f08c3..8006c8d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -289,12 +289,7 @@ $(call end-emulator-program)
###
###
-# Special case, "emulator-arm" is named "emulator" for now.
-ifeq ($(EMULATOR_TARGET_ARCH),arm)
-$(call start-emulator-program, emulator)
-else
$(call start-emulator-program, emulator-$(EMULATOR_TARGET_ARCH))
-endif
LOCAL_STATIC_LIBRARIES := \
emulator-libui \
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini
index 151d3df..65ba61d 100644
--- a/android/avd/hardware-properties.ini
+++ b/android/avd/hardware-properties.ini
@@ -23,6 +23,22 @@
# the emulator build.
#
+# CPU Architecture
+name = hw.cpu.arch
+type = string
+default = arm
+abstract = CPU Architecture
+description = The CPU Architecture to emulator
+
+# CPU Model
+# Leave it empty, and the default value will be computed from
+# hw.cpu.arch. This is only useful for experimentation for now.
+name = hw.cpu.model
+type = string
+default =
+abstract = CPU model
+description = The CPU model (QEMU-specific string)
+
# Ram size
# Default value will be computed based on screen pixels
# or skin version
diff --git a/android/avd/hw-config-defs.h b/android/avd/hw-config-defs.h
index 6308bd5..bb523d5 100644
--- a/android/avd/hw-config-defs.h
+++ b/android/avd/hw-config-defs.h
@@ -17,6 +17,20 @@
#error HWCFG_DOUBLE not defined
#endif
+HWCFG_STRING(
+ hw_cpu_arch,
+ "hw.cpu.arch",
+ "arm",
+ "CPU Architecture",
+ "The CPU Architecture to emulator")
+
+HWCFG_STRING(
+ hw_cpu_model,
+ "hw.cpu.model",
+ "",
+ "CPU model",
+ "The CPU model (QEMU-specific string)")
+
HWCFG_INT(
hw_ramSize,
"hw.ramSize",
diff --git a/android/avd/info.c b/android/avd/info.c
index 6f7c904..a9fc711 100644
--- a/android/avd/info.c
+++ b/android/avd/info.c
@@ -10,6 +10,7 @@
** GNU General Public License for more details.
*/
#include "android/avd/info.h"
+#include "android/avd/util.h"
#include "android/config/config.h"
#include "android/utils/path.h"
#include "android/utils/bufprint.h"
@@ -63,12 +64,6 @@ AvdInfo* android_avdInfo;
* with one of the usual options.
*/
-/* this is the subdirectory of $HOME/.android where all
- * root configuration files (and default content directories)
- * are located.
- */
-#define ANDROID_AVD_DIR "avd"
-
/* the prefix of config.ini keys that will be used for search directories
* of system images.
*/
@@ -230,50 +225,6 @@ static const char* const _imageFileText[ AVD_IMAGE_MAX ] = {
*****
*****/
-/* Return the path to the Android SDK root installation.
- *
- * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT
- * environment variable, or 0 otherwise.
- *
- * Caller must free() returned string.
- */
-static char*
-_getSdkRoot( char *pFromEnv )
-{
- const char* env;
- char* sdkPath;
- char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
- /* If ANDROID_SDK_ROOT is defined is must point to a directory
- * containing a valid SDK installation.
- */
-#define SDK_ROOT_ENV "ANDROID_SDK_ROOT"
-
- env = getenv(SDK_ROOT_ENV);
- if (env != NULL && env[0] != 0) {
- if (path_exists(env)) {
- D("found " SDK_ROOT_ENV ": %s", env);
- *pFromEnv = 1;
- return ASTRDUP(env);
- }
- D(SDK_ROOT_ENV " points to unknown directory: %s", env);
- }
-
- *pFromEnv = 0;
-
- /* We assume the emulator binary is under tools/ so use its
- * parent as the Android SDK root.
- */
- (void) bufprint_app_dir(temp, end);
- sdkPath = path_parent(temp, 1);
- if (sdkPath == NULL) {
- derror("can't find root of SDK directory");
- return NULL;
- }
- D("found SDK root at %s", sdkPath);
- return sdkPath;
-}
-
/* Parse a given config.ini file and extract the list of SDK search paths
* from it. Returns the number of valid paths stored in 'searchPaths', or -1
* in case of problem.
@@ -326,171 +277,6 @@ _checkAvdName( const char* name )
return (len == len2);
}
-/* Return the path to the AVD's root configuration .ini file. it is located in
- * ~/.android/avd/<name>.ini or Windows equivalent
- *
- * This file contains the path to the AVD's content directory, which
- * includes its own config.ini.
- */
-static char*
-_getRootIniPath( const char* avdName )
-{
- char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
- p = bufprint_config_path(temp, end);
- p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", avdName);
- if (p >= end) {
- return NULL;
- }
- if (!path_exists(temp)) {
- return NULL;
- }
- return ASTRDUP(temp);
-}
-
-
-/* Retrieves the value of a given system property defined in a .prop
- * file. This is a text file that contains definitions of the format:
- * <name>=<value>
- *
- * Returns NULL if property <name> is undefined or empty.
- * Returned string must be freed by the caller.
- */
-static char*
-_getSystemProperty( const char* propFile, const char* propName )
-{
- FILE* file;
- char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
- int propNameLen = strlen(propName);
- char* result = NULL;
-
- file = fopen(propFile, "rb");
- if (file == NULL) {
- D("Could not open file: %s: %s", temp, strerror(errno));
- return NULL;
- }
-
- while (fgets(temp, sizeof temp, file) != NULL) {
- /* Trim trailing newlines, if any */
- p = memchr(temp, '\0', sizeof temp);
- if (p == NULL)
- p = end;
- if (p > temp && p[-1] == '\n') {
- *--p = '\0';
- }
- if (p > temp && p[-1] == '\r') {
- *--p = '\0';
- }
- /* force zero-termination in case of full-buffer */
- if (p == end)
- *--p = '\0';
-
- /* check that the line starts with the property name */
- if (memcmp(temp, propName, propNameLen) != 0) {
- continue;
- }
- p = temp + propNameLen;
-
- /* followed by an equal sign */
- if (p >= end || *p != '=')
- continue;
- p++;
-
- /* followed by something */
- if (p >= end || !*p)
- break;
-
- result = ASTRDUP(p);
- break;
- }
- fclose(file);
- return result;
-}
-
-/* Return a build property. This is a system property defined in a file
- * named $ANDROID_PRODUCT_OUT/system/build.prop
- *
- * Returns NULL if undefined or empty. Returned string must be freed
- * by the caller.
- */
-static char*
-_getBuildProperty( const char* androidOut, const char* propName )
-{
- char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
-
- p = bufprint(temp, end, "%s/system/build.prop", androidOut);
- if (p >= end) {
- D("%s: ANDROID_PRODUCT_OUT too long: %s", __FUNCTION__, androidOut);
- return NULL;
- }
- return _getSystemProperty(temp, propName);
-}
-
-/* Retrieves a string corresponding to the target architecture
- * when in the Android platform tree. The only way to do that
- * properly for now is to look at $OUT/system/build.prop:
- *
- * ro.product.cpu-abi=<abi>
- *
- * Where <abi> can be 'armeabi', 'armeabi-v7a' or 'x86'.
- */
-static char*
-_getBuildTargetArch( const char* androidOut )
-{
- const char* defaultArch = "arm";
- char* result = NULL;
- char* cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi");
-
- if (cpuAbi == NULL) {
- D("Coult not find CPU ABI in build properties!");
- D("Default target architecture=%s", defaultArch);
- result = ASTRDUP(defaultArch);
- } else {
- /* Translate ABI to cpu arch if necessary */
- if (!strcmp("armeabi",cpuAbi))
- result = "arm";
- else if (!strcmp("armeabi-v7a", cpuAbi))
- result = "arm";
- else
- result = cpuAbi;
-
- D("Found target ABI=%s, architecture=%s", cpuAbi, result);
- result = ASTRDUP(result);
- AFREE(cpuAbi);
- }
- return result;
-}
-
-static int
-_getBuildTargetApiLevel( const char* androidOut )
-{
- const int defaultLevel = 1000;
- int level = defaultLevel;
- char* sdkVersion = _getBuildProperty(androidOut, "ro.build.version.sdk");
-
- if (sdkVersion != NULL) {
- long value;
- char* end;
- value = strtol(sdkVersion, &end, 10);
- if (end == NULL || *end != '\0' || value != (int)value) {
- D("Invalid SDK version build property: '%s'", sdkVersion);
- D("Defaulting to target API level %d", level);
- } else {
- level = (int)value;
- /* Sanity check, the Android SDK doesn't support anything
- * before Android 1.5, a.k.a API level 3 */
- if (level < 3)
- level = 3;
- D("Found target API level: %d", level);
- }
- AFREE(sdkVersion);
- } else {
- D("Could not find target API level / SDK version in build properties!");
- D("Default target API level: %d", level);
- }
- return level;
-}
-
/* Returns the full path of a given file.
*
* If 'fileName' is an absolute path, this returns a simple copy.
@@ -536,7 +322,7 @@ _checkSkinPath( const char* skinPath )
*/
static char*
_checkSkinSkinsDir( const char* skinDirRoot,
- const char* skinName )
+ const char* skinName )
{
DirScanner* scanner;
char* result;
@@ -649,7 +435,7 @@ static int
_avdInfo_getSdkRoot( AvdInfo* i )
{
- i->sdkRootPath = _getSdkRoot(&i->sdkRootPathFromEnv);
+ i->sdkRootPath = path_getSdkRoot(&i->sdkRootPathFromEnv);
if (i->sdkRootPath == NULL)
return -1;
@@ -662,7 +448,7 @@ _avdInfo_getSdkRoot( AvdInfo* i )
static int
_avdInfo_getRootIni( AvdInfo* i )
{
- char* iniPath = _getRootIniPath( i->deviceName );
+ char* iniPath = path_getRootIniPath( i->deviceName );
if (iniPath == NULL) {
derror("unknown virtual device name: '%s'", i->deviceName);
@@ -1027,8 +813,8 @@ avdInfo_newForAndroidBuild( const char* androidBuildRoot,
i->androidBuildRoot = ASTRDUP(androidBuildRoot);
i->androidOut = ASTRDUP(androidOut);
i->contentPath = ASTRDUP(androidOut);
- i->targetArch = _getBuildTargetArch(i->androidOut);
- i->apiLevel = _getBuildTargetApiLevel(i->androidOut);
+ i->targetArch = path_getBuildTargetArch(i->androidOut);
+ i->apiLevel = path_getBuildTargetApiLevel(i->androidOut);
/* TODO: find a way to provide better information from the build files */
i->deviceName = ASTRDUP("<build>");
diff --git a/android/avd/util.c b/android/avd/util.c
new file mode 100644
index 0000000..fdeb0fe
--- /dev/null
+++ b/android/avd/util.c
@@ -0,0 +1,304 @@
+/* Copyright (C) 2011 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 <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "android/utils/debug.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/ini.h"
+#include "android/utils/panic.h"
+#include "android/utils/path.h"
+#include "android/utils/system.h"
+#include "android/avd/util.h"
+
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+
+/* this is the subdirectory of $HOME/.android where all
+ * root configuration files (and default content directories)
+ * are located.
+ */
+#define ANDROID_AVD_DIR "avd"
+
+
+/* Return the path to the Android SDK root installation.
+ *
+ * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT
+ * environment variable, or 0 otherwise.
+ *
+ * Caller must free() returned string.
+ */
+char*
+path_getSdkRoot( char *pFromEnv )
+{
+ const char* env;
+ char* sdkPath;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ /* If ANDROID_SDK_ROOT is defined is must point to a directory
+ * containing a valid SDK installation.
+ */
+#define SDK_ROOT_ENV "ANDROID_SDK_ROOT"
+
+ env = getenv(SDK_ROOT_ENV);
+ if (env != NULL && env[0] != 0) {
+ if (path_exists(env)) {
+ D("found " SDK_ROOT_ENV ": %s", env);
+ *pFromEnv = 1;
+ return ASTRDUP(env);
+ }
+ D(SDK_ROOT_ENV " points to unknown directory: %s", env);
+ }
+
+ *pFromEnv = 0;
+
+ /* We assume the emulator binary is under tools/ so use its
+ * parent as the Android SDK root.
+ */
+ (void) bufprint_app_dir(temp, end);
+ sdkPath = path_parent(temp, 1);
+ if (sdkPath == NULL) {
+ derror("can't find root of SDK directory");
+ return NULL;
+ }
+ D("found SDK root at %s", sdkPath);
+ return sdkPath;
+}
+
+
+/* Return the path to the AVD's root configuration .ini file. it is located in
+ * ~/.android/avd/<name>.ini or Windows equivalent
+ *
+ * This file contains the path to the AVD's content directory, which
+ * includes its own config.ini.
+ */
+char*
+path_getRootIniPath( const char* avdName )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ p = bufprint_config_path(temp, end);
+ p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", avdName);
+ if (p >= end) {
+ return NULL;
+ }
+ if (!path_exists(temp)) {
+ return NULL;
+ }
+ return ASTRDUP(temp);
+}
+
+
+char*
+path_getSdkHome(void)
+{
+ const char* sdkHome = getenv("ANDROID_SDK_HOME");
+
+ if (sdkHome == NULL || *sdkHome == '\0') {
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ p = bufprint_config_path(temp, end);
+ if (p >= end) {
+ APANIC("User path too long!: %s\n", temp);
+ }
+ sdkHome = strdup(temp);
+ } else {
+ sdkHome = strdup(sdkHome);
+ }
+ return (char*)sdkHome;
+}
+
+
+static char*
+_getAvdContentPath(const char* avdName)
+{
+ char* sdkHome = path_getSdkHome();
+ char* avdPath = NULL;
+ IniFile* ini;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ /* Look for the root .ini file */
+ p = bufprint(temp, end, "%s/avd/%s.ini", sdkHome, avdName);
+ if (p >= end) {
+ APANIC("AVD Name too long: %s\n", avdName);
+ }
+
+ ini = iniFile_newFromFile(temp);
+ if (ini == NULL) {
+ APANIC("Could not open: %s", temp);
+ }
+
+ avdPath = iniFile_getString(ini, "path", NULL);
+
+ iniFile_free(ini);
+ AFREE(sdkHome);
+
+ return avdPath;
+}
+
+
+static char*
+_getAvdTargetArch(const char* avdPath)
+{
+ IniFile* ini;
+ char* targetArch = NULL;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ p = bufprint(temp, end, "%s/config.ini", avdPath);
+ if (p >= end) {
+ APANIC("AVD path too long: %s\n", avdPath);
+ }
+ ini = iniFile_newFromFile(temp);
+ if (ini == NULL) {
+ APANIC("Could not open AVD config file: %s", temp);
+ }
+ targetArch = iniFile_getString(ini, "hw.cpu.arch", "arm");
+ iniFile_free(ini);
+
+ return targetArch;
+}
+
+char*
+path_getAvdTargetArch( const char* avdName )
+{
+ char* avdPath = _getAvdContentPath(avdName);
+ char* avdArch = _getAvdTargetArch(avdPath);
+
+ return avdArch;
+}
+
+/* Retrieves the value of a given system property defined in a .prop
+ * file. This is a text file that contains definitions of the format:
+ * <name>=<value>
+ *
+ * Returns NULL if property <name> is undefined or empty.
+ * Returned string must be freed by the caller.
+ */
+static char*
+_getSystemProperty( const char* propFile, const char* propName )
+{
+ FILE* file;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+ int propNameLen = strlen(propName);
+ char* result = NULL;
+
+ file = fopen(propFile, "rb");
+ if (file == NULL) {
+ D("Could not open file: %s: %s", temp, strerror(errno));
+ return NULL;
+ }
+
+ while (fgets(temp, sizeof temp, file) != NULL) {
+ /* Trim trailing newlines, if any */
+ p = memchr(temp, '\0', sizeof temp);
+ if (p == NULL)
+ p = end;
+ if (p > temp && p[-1] == '\n') {
+ *--p = '\0';
+ }
+ if (p > temp && p[-1] == '\r') {
+ *--p = '\0';
+ }
+ /* force zero-termination in case of full-buffer */
+ if (p == end)
+ *--p = '\0';
+
+ /* check that the line starts with the property name */
+ if (memcmp(temp, propName, propNameLen) != 0) {
+ continue;
+ }
+ p = temp + propNameLen;
+
+ /* followed by an equal sign */
+ if (p >= end || *p != '=')
+ continue;
+ p++;
+
+ /* followed by something */
+ if (p >= end || !*p)
+ break;
+
+ result = ASTRDUP(p);
+ break;
+ }
+ fclose(file);
+ return result;
+}
+
+static char*
+_getBuildProperty( const char* androidOut, const char* propName )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ p = bufprint(temp, end, "%s/system/build.prop", androidOut);
+ if (p >= end) {
+ D("%s: ANDROID_PRODUCT_OUT too long: %s", __FUNCTION__, androidOut);
+ return NULL;
+ }
+ return _getSystemProperty(temp, propName);
+}
+
+char*
+path_getBuildTargetArch( const char* androidOut )
+{
+ const char* defaultArch = "arm";
+ char* result = NULL;
+ char* cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi");
+
+ if (cpuAbi == NULL) {
+ D("Coult not find CPU ABI in build properties!");
+ D("Default target architecture=%s", defaultArch);
+ result = ASTRDUP(defaultArch);
+ } else {
+ /* Translate ABI to cpu arch if necessary */
+ if (!strcmp("armeabi",cpuAbi))
+ result = "arm";
+ else if (!strcmp("armeabi-v7a", cpuAbi))
+ result = "arm";
+ else
+ result = cpuAbi;
+
+ D("Found target ABI=%s, architecture=%s", cpuAbi, result);
+ result = ASTRDUP(result);
+ AFREE(cpuAbi);
+ }
+ return result;
+}
+
+
+int
+path_getBuildTargetApiLevel( const char* androidOut )
+{
+ const int defaultLevel = 1000;
+ int level = defaultLevel;
+ char* sdkVersion = _getBuildProperty(androidOut, "ro.build.version.sdk");
+
+ if (sdkVersion != NULL) {
+ long value;
+ char* end;
+ value = strtol(sdkVersion, &end, 10);
+ if (end == NULL || *end != '\0' || value != (int)value) {
+ D("Invalid SDK version build property: '%s'", sdkVersion);
+ D("Defaulting to target API level %d", level);
+ } else {
+ level = (int)value;
+ /* Sanity check, the Android SDK doesn't support anything
+ * before Android 1.5, a.k.a API level 3 */
+ if (level < 3)
+ level = 3;
+ D("Found target API level: %d", level);
+ }
+ AFREE(sdkVersion);
+ } else {
+ D("Could not find target API level / SDK version in build properties!");
+ D("Default target API level: %d", level);
+ }
+ return level;
+}
+
diff --git a/android/avd/util.h b/android/avd/util.h
new file mode 100644
index 0000000..27f8f28
--- /dev/null
+++ b/android/avd/util.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2011 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_AVD_UTIL_H
+#define _ANDROID_AVD_UTIL_H
+
+/* A collection of simple functions to extract relevant AVD-related
+ * information either from an SDK AVD or a platform build.
+ */
+
+/* Return the path to the Android SDK root installation.
+ *
+ * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT
+ * environment variable, or 0 otherwise.
+ *
+ * Caller must free() returned string.
+ */
+char* path_getSdkRoot( char *pFromEnv );
+
+/* Return the path to the AVD's root configuration .ini file. it is located in
+ * ~/.android/avd/<name>.ini or Windows equivalent
+ *
+ * This file contains the path to the AVD's content directory, which
+ * includes its own config.ini.
+ */
+char* path_getRootIniPath( const char* avdName );
+
+/* Return the target architecture for a given AVD.
+ * Called must free() returned string.
+ */
+char* path_getAvdTargetArch( const char* avdName );
+
+/* Retrieves a string corresponding to the target architecture
+ * when in the Android platform tree. The only way to do that
+ * properly for now is to look at $OUT/system/build.prop:
+ *
+ * ro.product.cpu-abi=<abi>
+ *
+ * Where <abi> can be 'armeabi', 'armeabi-v7a' or 'x86'.
+ */
+char* path_getBuildTargetArch( const char* androidOut );
+
+/* Retrieve the target API level when in the Android platform tree.
+ * This can be a very large number like 1000 if the value cannot
+ * be extracted from the appropriate file
+ */
+int path_getBuildTargetApiLevel( const char* androidOut );
+
+#endif /* _ANDROID_AVD_UTIL_H */
diff --git a/android/main-emulator.c b/android/main-emulator.c
new file mode 100644
index 0000000..211291b
--- /dev/null
+++ b/android/main-emulator.c
@@ -0,0 +1,169 @@
+/* Copyright (C) 2011 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.
+*/
+
+/* This is the source code to the tiny "emulator" launcher program
+ * that is in charge of starting the target-specific emulator binary
+ * for a given AVD, i.e. either 'emulator-arm' or 'emulator-x86'
+ *
+ * This program will be replaced in the future by what is currently
+ * known as 'emulator-ui', but is a good placeholder until this
+ * migration is completed.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <android/utils/panic.h>
+#include <android/utils/path.h>
+#include <android/utils/bufprint.h>
+#include <android/avd/util.h>
+
+/* Required by android/utils/debug.h */
+int android_verbose;
+
+
+#define DEBUG 1
+
+#if DEBUG
+# define D(...) do { if (android_verbose) printf("emulator:" __VA_ARGS__); } while (0)
+#else
+# define D(...) do{}while(0)
+#endif
+
+/* Forward declarations */
+static char* getTargetEmulatorPath(const char* progName, const char* avdArch);
+
+/* Main routine */
+int main(int argc, char** argv)
+{
+ const char* avdName = NULL;
+ char* avdArch = NULL;
+ char* emulatorPath;
+
+ /* Define ANDROID_EMULATOR_DEBUG to 1 in your environment if you want to
+ * see the debug messages from this launcher program.
+ */
+ const char* debug = getenv("ANDROID_EMULATOR_DEBUG");
+
+ if (debug != NULL && *debug && *debug != '0')
+ android_verbose = 1;
+
+ /* Parse command-line and look for an avd name
+ * Either in the form or '-avd <name>' or '@<name>'
+ */
+ int nn;
+ for (nn = 1; nn < argc; nn++) {
+ const char* opt = argv[nn];
+
+ if (!strcmp(opt,"-qemu"))
+ break;
+
+ if (!strcmp(opt,"-avd") && nn+1 < argc) {
+ avdName = argv[nn+1];
+ break;
+ }
+ else if (opt[0] == '@' && opt[1] != '\0') {
+ avdName = opt+1;
+ break;
+ }
+ }
+
+ /* If there is an AVD name, we're going to extract its target architecture
+ * by looking at its config.ini
+ */
+ if (avdName != NULL) {
+ D("Found AVD name '%s'\n", avdName);
+ avdArch = path_getAvdTargetArch(avdName);
+ D("Found AVD target architecture: %s\n", avdArch);
+ } else {
+ /* Otherwise, using the ANDROID_PRODUCT_OUT directory */
+ const char* androidOut = getenv("ANDROID_PRODUCT_OUT");
+
+ if (androidOut != NULL && *androidOut != '\0') {
+ D("Found ANDROID_PRODUCT_OUT: %s\n", androidOut);
+ avdArch = path_getBuildTargetArch(androidOut);
+ D("Found build target architecture: %s\n", avdArch);
+ }
+ }
+
+ if (avdArch == NULL) {
+ avdArch = "arm";
+ D("Can't determine target AVD architecture: defaulting to %s\n", avdArch);
+ }
+
+ /* Find the architecture-specific program in the same directory */
+ emulatorPath = getTargetEmulatorPath(argv[0], avdArch);
+ D("Found target-specific emulator binary: %s\n", emulatorPath);
+
+ /* Replace it in our command-line */
+ argv[0] = emulatorPath;
+
+ /* Launch it with the same set of options ! */
+ /* execv() should be available on Windows with mingw32 */
+ execv(emulatorPath, argv);
+
+ /* We could not launch the program ! */
+ fprintf(stderr, "Could not launch '%s': %s\n", emulatorPath, strerror(errno));
+ return errno;
+}
+
+
+/* Find the target-specific emulator binary. This will be something
+ * like <programDir>/emulator-<targetArch>, where <programDir> is
+ * the directory of the current program.
+ */
+static char*
+getTargetEmulatorPath(const char* progName, const char* avdArch)
+{
+ char* progDir;
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+#ifdef _WIN32
+ const char* exeExt = ".exe";
+#else
+ const char* exeExt = "";
+#endif
+
+ /* Get program's directory name in progDir */
+ path_split(progName, &progDir, NULL);
+
+ p = bufprint(temp, end, "%s/emulator-%s%s", progDir, avdArch, exeExt);
+ free(progDir);
+ if (p >= end) {
+ APANIC("Path too long: %s\n", progName);
+ }
+
+ if (path_exists(temp)) {
+ return strdup(temp);
+ }
+
+ /* Mmm, the file doesn't exist, If there is no slash / backslash
+ * in our path, we're going to try to search it in our path.
+ */
+#ifdef _WIN32
+ if (strchr(progName, '/') == NULL && strchr(progName, '\\') == NULL) {
+#else
+ if (strchr(progName, '/') == NULL) {
+#endif
+ p = bufprint(temp, end, "emulator-%s%s", avdArch, exeExt);
+ if (p < end) {
+ char* resolved = path_search_exec(temp);
+ if (resolved != NULL)
+ return resolved;
+ }
+ }
+
+ /* Otherwise, the program is missing */
+ APANIC("Missing arch-specific emulator program: %s\n", temp);
+ return NULL;
+}
diff --git a/android/utils/path.c b/android/utils/path.c
index e7ef2b0..f64e517 100644
--- a/android/utils/path.c
+++ b/android/utils/path.c
@@ -265,6 +265,14 @@ path_can_write( const char* path )
return (ret == 0);
}
+ABool
+path_can_exec( const char* path )
+{
+ int ret;
+ CHECKED(ret, access(path, X_OK));
+ return (ret == 0);
+}
+
/* try to make a directory. returns 0 on success, -1 on failure
* (error code in errno) */
APosixStatus
@@ -325,7 +333,7 @@ path_mkdir_recursive( char* path, unsigned len, int mode )
return ret;
}
-/* ensure that a given directory exists, create it if not,
+/* ensure that a given directory exists, create it if not,
0 on success, -1 on failure (error code in errno) */
APosixStatus
path_mkdir_if_needed( const char* path, int mode )
@@ -363,9 +371,9 @@ path_get_size( const char* path, uint64_t *psize )
/* result in getting the size of a different file */
LARGE_INTEGER size;
HANDLE file = CreateFile( /* lpFilename */ path,
- /* dwDesiredAccess */ GENERIC_READ,
- /* dwSharedMode */ FILE_SHARE_READ|FILE_SHARE_WRITE,
- /* lpSecurityAttributes */ NULL,
+ /* dwDesiredAccess */ GENERIC_READ,
+ /* dwSharedMode */ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ /* lpSecurityAttributes */ NULL,
/* dwCreationDisposition */ OPEN_EXISTING,
/* dwFlagsAndAttributes */ 0,
/* hTemplateFile */ NULL );
@@ -564,3 +572,73 @@ path_load_file(const char *fn, size_t *pSize)
return NULL;
}
+#ifdef _WIN32
+# define DIR_SEP ';'
+#else
+# define DIR_SEP ':'
+#endif
+
+char*
+path_search_exec( const char* filename )
+{
+ const char* sysPath = getenv("PATH");
+ char temp[PATH_MAX];
+ int count;
+ int slen;
+ const char* p;
+
+ /* If the file contains a directory separator, don't search */
+#ifdef _WIN32
+ if (strchr(filename, '/') != NULL || strchr(filename, '\\') != NULL) {
+#else
+ if (strchr(filename, '/') != NULL) {
+#endif
+ if (path_exists(filename)) {
+ return strdup(filename);
+ } else {
+ return NULL;
+ }
+ }
+
+ /* If system path is empty, don't search */
+ if (sysPath == NULL || sysPath[0] == '\0') {
+ return NULL;
+ }
+
+ /* Count the number of non-empty items in the system path
+ * Items are separated by DIR_SEP, and two successive separators
+ * correspond to an empty item that will be ignored.
+ * Also compute the required string storage length. */
+ count = 0;
+ slen = 0;
+ p = sysPath;
+
+ while (*p) {
+ char* p2 = strchr(p, DIR_SEP);
+ int len;
+ if (p2 == NULL) {
+ len = strlen(p);
+ } else {
+ len = p2 - p;
+ }
+
+ do {
+ if (len <= 0)
+ break;
+
+ snprintf(temp, sizeof(temp), "%.*s/%s", len, p, filename);
+
+ if (path_exists(temp) && path_can_exec(temp)) {
+ return strdup(temp);
+ }
+
+ } while (0);
+
+ p += len;
+ if (*p == DIR_SEP)
+ p++;
+ }
+
+ /* Nothing, really */
+ return NULL;
+}
diff --git a/android/utils/path.h b/android/utils/path.h
index e15e6ed..419e6bf 100644
--- a/android/utils/path.h
+++ b/android/utils/path.h
@@ -64,6 +64,9 @@ extern ABool path_is_absolute( const char* path );
extern ABool path_can_read( const char* path );
extern ABool path_can_write( const char* path );
+/* checks that one can execute a given file */
+extern ABool path_can_exec( const char* path );
+
/* try to make a directory */
extern APosixStatus path_mkdir( const char* path, int mode );
@@ -109,6 +112,12 @@ extern char* path_dirname( const char* path );
*/
extern char* path_basename( const char* path );
+/* look for a given executable in the system path and return its full path.
+ * Returns NULL if not found. Note that on Windows this doesn't not append
+ * an .exe prefix, or other magical thing like Cygwin usually does.
+ */
+extern char* path_search_exec( const char* filename );
+
/** OTHER FILE UTILITIES
**
** path_empty_file() creates an empty file at a given path location.
diff --git a/vl-android.c b/vl-android.c
index 6653286..abfa423 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -5629,6 +5629,29 @@ int main(int argc, char **argv, char **envp)
}
#endif
+ /* Check the CPU Architecture value */
+#if defined(TARGET_ARM)
+ if (strcmp(android_hw->hw_cpu_arch,"arm") != 0) {
+ fprintf(stderr, "-- Invalid CPU architecture: %s, expected 'arm'\n",
+ android_hw->hw_cpu_arch);
+ exit(1);
+ }
+#elif defined(TARGET_X86)
+ if (strcmp(android_hw->hw_cpu_arch,"x86") != 0) {
+ fprintf(stderr, "-- Invalid CPU architecture: %s, expected 'x86'\n",
+ android_hw->hw_cpu_arch);
+ exit(1);
+ }
+#endif
+
+ /* Grab CPU model if provided in hardware.ini */
+ if ( !cpu_model
+ && android_hw->hw_cpu_model
+ && android_hw->hw_cpu_model[0] != '\0')
+ {
+ cpu_model = android_hw->hw_cpu_model;
+ }
+
/* Combine kernel command line passed from the UI with parameters
* collected during initialization.
*