diff options
-rw-r--r-- | Makefile.android | 13 | ||||
-rw-r--r-- | Makefile.common | 1 | ||||
-rw-r--r-- | Makefile.target | 5 | ||||
-rw-r--r-- | android/avd/hardware-properties.ini | 16 | ||||
-rw-r--r-- | android/avd/hw-config-defs.h | 14 | ||||
-rw-r--r-- | android/avd/info.c | 226 | ||||
-rw-r--r-- | android/avd/util.c | 304 | ||||
-rw-r--r-- | android/avd/util.h | 57 | ||||
-rw-r--r-- | android/main-emulator.c | 169 | ||||
-rw-r--r-- | android/utils/path.c | 86 | ||||
-rw-r--r-- | android/utils/path.h | 9 | ||||
-rw-r--r-- | vl-android.c | 23 |
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 fb3118e..98c2325 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 89b0e3f..5d67fc6 100644 --- a/vl-android.c +++ b/vl-android.c @@ -5626,6 +5626,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. * |