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", propFile, 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 if (!strncmp("mips", cpuAbi, 4)) 258 result = "mips"; 259 else 260 result = cpuAbi; 261 262 D("Found target ABI=%s, architecture=%s", cpuAbi, result); 263 result = ASTRDUP(result); 264 AFREE(cpuAbi); 265 } 266 return result; 267 } 268 269 char* 270 path_getBuildTargetAbi( const char* androidOut ) 271 { 272 const char* defaultAbi = "armeabi"; 273 char* result = NULL; 274 char* cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi"); 275 276 if (cpuAbi == NULL) { 277 D("Coult not find CPU ABI in build properties!"); 278 D("Default target ABI: %s", defaultAbi); 279 result = ASTRDUP(defaultAbi); 280 } else { 281 D("Found target ABI=%s", cpuAbi); 282 result = cpuAbi; 283 } 284 return result; 285 } 286 287 288 int 289 path_getBuildTargetApiLevel( const char* androidOut ) 290 { 291 const int defaultLevel = 1000; 292 int level = defaultLevel; 293 char* sdkVersion = _getBuildProperty(androidOut, "ro.build.version.sdk"); 294 295 if (sdkVersion != NULL) { 296 long value; 297 char* end; 298 value = strtol(sdkVersion, &end, 10); 299 if (end == NULL || *end != '\0' || value != (int)value) { 300 D("Invalid SDK version build property: '%s'", sdkVersion); 301 D("Defaulting to target API level %d", level); 302 } else { 303 level = (int)value; 304 /* Sanity check, the Android SDK doesn't support anything 305 * before Android 1.5, a.k.a API level 3 */ 306 if (level < 3) 307 level = 3; 308 D("Found target API level: %d", level); 309 } 310 AFREE(sdkVersion); 311 } else { 312 D("Could not find target API level / SDK version in build properties!"); 313 D("Default target API level: %d", level); 314 } 315 return level; 316 } 317 318 int 319 path_getAdbdCommunicationMode( const char* androidOut ) 320 { 321 char* prop = _getBuildProperty(androidOut, "ro.adb.qemud"); 322 if (prop != NULL) { 323 long val = 0; 324 char* end; 325 val = strtol(prop, &end, 10); 326 if (end == NULL || *end != '\0' || val != (int)val) { 327 D("Invalid ro.adb.qemud build property: '%s'", prop); 328 val = 0; 329 } else { 330 D("Found ro.adb.qemud build property: %d", val); 331 } 332 AFREE(prop); 333 return (int)val; 334 } else { 335 /* Missing ro.adb.qemud means "legacy" ADBD. */ 336 return 0; 337 } 338 } 339