aboutsummaryrefslogtreecommitdiffstats
path: root/android/avd/util.c
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 /android/avd/util.c
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
Diffstat (limited to 'android/avd/util.c')
-rw-r--r--android/avd/util.c304
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;
+}
+