1 /* Copyright (C) 2011 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <errno.h> 15 #include "android/utils/debug.h" 16 #include "android/utils/bufprint.h" 17 #include "android/utils/ini.h" 18 #include "android/utils/panic.h" 19 #include "android/utils/path.h" 20 #include "android/utils/system.h" 21 #include "android/avd/util.h" 22 23 #define D(...) VERBOSE_PRINT(init,__VA_ARGS__) 24 25 /* this is the subdirectory of $HOME/.android where all 26 * root configuration files (and default content directories) 27 * are located. 28 */ 29 #define ANDROID_AVD_DIR "avd" 30 31 32 /* Return the path to the Android SDK root installation. 33 * 34 * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT 35 * environment variable, or 0 otherwise. 36 * 37 * Caller must free() returned string. 38 */ 39 char* 40 path_getSdkRoot( char *pFromEnv ) 41 { 42 const char* env; 43 char* sdkPath; 44 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 45 46 /* If ANDROID_SDK_ROOT is defined is must point to a directory 47 * containing a valid SDK installation. 48 */ 49 #define SDK_ROOT_ENV "ANDROID_SDK_ROOT" 50 51 env = getenv(SDK_ROOT_ENV); 52 if (env != NULL && env[0] != 0) { 53 if (path_exists(env)) { 54 D("found " SDK_ROOT_ENV ": %s", env); 55 *pFromEnv = 1; 56 return ASTRDUP(env); 57 } 58 D(SDK_ROOT_ENV " points to unknown directory: %s", env); 59 } 60 61 *pFromEnv = 0; 62 63 /* We assume the emulator binary is under tools/ so use its 64 * parent as the Android SDK root. 65 */ 66 (void) bufprint_app_dir(temp, end); 67 sdkPath = path_parent(temp, 1); 68 if (sdkPath == NULL) { 69 derror("can't find root of SDK directory"); 70 return NULL; 71 } 72 D("found SDK root at %s", sdkPath); 73 return sdkPath; 74 } 75 76 77 /* Return the path to the AVD's root configuration .ini file. it is located in 78 * ~/.android/avd/<name>.ini or Windows equivalent 79 * 80 * This file contains the path to the AVD's content directory, which 81 * includes its own config.ini. 82 */ 83 char* 84 path_getRootIniPath( const char* avdName ) 85 { 86 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 87 88 p = bufprint_config_path(temp, end); 89 p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", avdName); 90 if (p >= end) { 91 return NULL; 92 } 93 if (!path_exists(temp)) { 94 return NULL; 95 } 96 return ASTRDUP(temp); 97 } 98 99 100 char* 101 path_getSdkHome(void) 102 { 103 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 104 p = bufprint_config_path(temp, end); 105 if (p >= end) { 106 APANIC("User path too long!: %s\n", temp); 107 } 108 return strdup(temp); 109 } 110 111 112 static char* 113 _getAvdContentPath(const char* avdName) 114 { 115 char* sdkHome = path_getSdkHome(); 116 char* avdPath = NULL; 117 IniFile* ini; 118 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 119 120 /* Look for the root .ini file */ 121 p = bufprint(temp, end, "%s/avd/%s.ini", sdkHome, avdName); 122 if (p >= end) { 123 APANIC("AVD Name too long: %s\n", avdName); 124 } 125 126 ini = iniFile_newFromFile(temp); 127 if (ini == NULL) { 128 APANIC("Could not open: %s", temp); 129 } 130 131 avdPath = iniFile_getString(ini, "path", NULL); 132 133 iniFile_free(ini); 134 AFREE(sdkHome); 135 136 return avdPath; 137 } 138 139 140 static char* 141 _getAvdTargetArch(const char* avdPath) 142 { 143 IniFile* ini; 144 char* targetArch = NULL; 145 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 146 p = bufprint(temp, end, "%s/config.ini", avdPath); 147 if (p >= end) { 148 APANIC("AVD path too long: %s\n", avdPath); 149 } 150 ini = iniFile_newFromFile(temp); 151 if (ini == NULL) { 152 APANIC("Could not open AVD config file: %s", temp); 153 } 154 targetArch = iniFile_getString(ini, "hw.cpu.arch", "arm"); 155 iniFile_free(ini); 156 157 return targetArch; 158 } 159 160 char* 161 path_getAvdTargetArch( const char* avdName ) 162 { 163 char* avdPath = _getAvdContentPath(avdName); 164 char* avdArch = _getAvdTargetArch(avdPath); 165 166 return avdArch; 167 } 168 169 /* Retrieves the value of a given system property defined in a .prop 170 * file. This is a text file that contains definitions of the format: 171 * <name>=<value> 172 * 173 * Returns NULL if property <name> is undefined or empty. 174 * Returned string must be freed by the caller. 175 */ 176 static char* 177 _getSystemProperty( const char* propFile, const char* propName ) 178 { 179 FILE* file; 180 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 181 int propNameLen = strlen(propName); 182 char* result = NULL; 183 184 file = fopen(propFile, "rb"); 185 if (file == NULL) { 186 D("Could not open file: %s: %s", temp, strerror(errno)); 187 return NULL; 188 } 189 190 while (fgets(temp, sizeof temp, file) != NULL) { 191 /* Trim trailing newlines, if any */ 192 p = memchr(temp, '\0', sizeof temp); 193 if (p == NULL) 194 p = end; 195 if (p > temp && p[-1] == '\n') { 196 *--p = '\0'; 197 } 198 if (p > temp && p[-1] == '\r') { 199 *--p = '\0'; 200 } 201 /* force zero-termination in case of full-buffer */ 202 if (p == end) 203 *--p = '\0'; 204 205 /* check that the line starts with the property name */ 206 if (memcmp(temp, propName, propNameLen) != 0) { 207 continue; 208 } 209 p = temp + propNameLen; 210 211 /* followed by an equal sign */ 212 if (p >= end || *p != '=') 213 continue; 214 p++; 215 216 /* followed by something */ 217 if (p >= end || !*p) 218 break; 219 220 result = ASTRDUP(p); 221 break; 222 } 223 fclose(file); 224 return result; 225 } 226 227 static char* 228 _getBuildProperty( const char* androidOut, const char* propName ) 229 { 230 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 231 232 p = bufprint(temp, end, "%s/system/build.prop", androidOut); 233 if (p >= end) { 234 D("%s: ANDROID_PRODUCT_OUT too long: %s", __FUNCTION__, androidOut); 235 return NULL; 236 } 237 return _getSystemProperty(temp, propName); 238 } 239 240 char* 241 path_getBuildTargetArch( const char* androidOut ) 242 { 243 const char* defaultArch = "arm"; 244 char* result = NULL; 245 char* cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi"); 246 247 if (cpuAbi == NULL) { 248 D("Coult not find CPU ABI in build properties!"); 249 D("Default target architecture=%s", defaultArch); 250 result = ASTRDUP(defaultArch); 251 } else { 252 /* Translate ABI to cpu arch if necessary */ 253 if (!strcmp("armeabi",cpuAbi)) 254 result = "arm"; 255 else if (!strcmp("armeabi-v7a", cpuAbi)) 256 result = "arm"; 257 else 258 result = cpuAbi; 259 260 D("Found target ABI=%s, architecture=%s", cpuAbi, result); 261 result = ASTRDUP(result); 262 AFREE(cpuAbi); 263 } 264 return result; 265 } 266 267 char* 268 path_getBuildTargetAbi( const char* androidOut ) 269 { 270 const char* defaultAbi = "armeabi"; 271 char* result = NULL; 272 char* cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi"); 273 274 if (cpuAbi == NULL) { 275 D("Coult not find CPU ABI in build properties!"); 276 D("Default target ABI: %s", defaultAbi); 277 result = ASTRDUP(defaultAbi); 278 } else { 279 D("Found target ABI=%s", cpuAbi); 280 result = cpuAbi; 281 } 282 return result; 283 } 284 285 286 int 287 path_getBuildTargetApiLevel( const char* androidOut ) 288 { 289 const int defaultLevel = 1000; 290 int level = defaultLevel; 291 char* sdkVersion = _getBuildProperty(androidOut, "ro.build.version.sdk"); 292 293 if (sdkVersion != NULL) { 294 long value; 295 char* end; 296 value = strtol(sdkVersion, &end, 10); 297 if (end == NULL || *end != '\0' || value != (int)value) { 298 D("Invalid SDK version build property: '%s'", sdkVersion); 299 D("Defaulting to target API level %d", level); 300 } else { 301 level = (int)value; 302 /* Sanity check, the Android SDK doesn't support anything 303 * before Android 1.5, a.k.a API level 3 */ 304 if (level < 3) 305 level = 3; 306 D("Found target API level: %d", level); 307 } 308 AFREE(sdkVersion); 309 } else { 310 D("Could not find target API level / SDK version in build properties!"); 311 D("Default target API level: %d", level); 312 } 313 return level; 314 } 315 316