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