Merge "Add 'emulator' launcher program." into tools_r11
diff --git a/Makefile.android b/Makefile.android
index 4b6e211..efc6fc3 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -202,6 +202,19 @@
 ##############################################################################
 ##############################################################################
 ###
+###  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 fb3118e..98c2325 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -69,6 +69,7 @@
 	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 @@
 ###
 ###
 
-# 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 @@
  * 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 @@
  *****
  *****/
 
-/* 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 @@
     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 @@
  */
 static char*
 _checkSkinSkinsDir( const char*  skinDirRoot,
-               const char*  skinName )
+                    const char*  skinName )
 {
     DirScanner*  scanner;
     char*        result;
@@ -649,7 +435,7 @@
 _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 @@
 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 @@
     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 @@
     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 @@
     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 @@
     /* 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 @@
     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_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_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 89b0e3f..5d67fc6 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -5626,6 +5626,29 @@
     }
 #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.
      *