diff options
author | David 'Digit' Turner <digit@android.com> | 2011-03-25 10:34:47 +0100 |
---|---|---|
committer | David 'Digit' Turner <digit@android.com> | 2011-05-03 09:26:46 +0200 |
commit | a3703225151c95a32017e66a3b56229059d78626 (patch) | |
tree | c7323ffd476368c10c91f3ec12f3f66a766f33d2 /android/avd/util.c | |
parent | c9154bef9c32ddf269b078dd15d153fe1be1fa42 (diff) | |
download | external_qemu-a3703225151c95a32017e66a3b56229059d78626.zip external_qemu-a3703225151c95a32017e66a3b56229059d78626.tar.gz external_qemu-a3703225151c95a32017e66a3b56229059d78626.tar.bz2 |
Add 'emulator' launcher program.
NOTE: This integrates https://review.source.android.com/#change,21995
into the tools_r11 branch.
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: Id883b67c0255b6deeae393443a1732e10ab223cb
Diffstat (limited to 'android/avd/util.c')
-rw-r--r-- | android/avd/util.c | 304 |
1 files changed, 304 insertions, 0 deletions
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; +} + |