| /* 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) |
| { |
| 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); |
| } |
| return strdup(temp); |
| } |
| |
| |
| 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", propFile, 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; |
| } |
| |
| char* |
| path_getBuildTargetAbi( const char* androidOut ) |
| { |
| const char* defaultAbi = "armeabi"; |
| 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 ABI: %s", defaultAbi); |
| result = ASTRDUP(defaultAbi); |
| } else { |
| D("Found target ABI=%s", cpuAbi); |
| result = 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; |
| } |
| |
| int |
| path_getAdbdCommunicationMode( const char* androidOut ) |
| { |
| char* prop = _getBuildProperty(androidOut, "ro.adb.qemud"); |
| if (prop != NULL) { |
| long val = 0; |
| char* end; |
| val = strtol(prop, &end, 10); |
| if (end == NULL || *end != '\0' || val != (int)val) { |
| D("Invalid ro.adb.qemud build property: '%s'", prop); |
| val = 0; |
| } else { |
| D("Found ro.adb.qemud build property: %d", val); |
| } |
| AFREE(prop); |
| return (int)val; |
| } else { |
| /* Missing ro.adb.qemud means "legacy" ADBD. */ |
| return 0; |
| } |
| } |