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 <limits.h> 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <errno.h> 16 #include "android/utils/debug.h" 17 #include "android/utils/bufprint.h" 18 #include "android/utils/ini.h" 19 #include "android/utils/property_file.h" 20 #include "android/utils/panic.h" 21 #include "android/utils/path.h" 22 #include "android/utils/system.h" 23 #include "android/avd/util.h" 24 #include "android/avd/keys.h" 25 26 #define D(...) VERBOSE_PRINT(init,__VA_ARGS__) 27 28 /* this is the subdirectory of $HOME/.android where all 29 * root configuration files (and default content directories) 30 * are located. 31 */ 32 #define ANDROID_AVD_DIR "avd" 33 34 35 /* Return the path to the Android SDK root installation. 36 * 37 * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT 38 * environment variable, or 0 otherwise. 39 * 40 * Caller must free() returned string. 41 */ 42 char* 43 path_getSdkRoot( char *pFromEnv ) 44 { 45 const char* env; 46 char* sdkPath; 47 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 48 49 /* If ANDROID_SDK_ROOT is defined is must point to a directory 50 * containing a valid SDK installation. 51 */ 52 #define SDK_ROOT_ENV "ANDROID_SDK_ROOT" 53 54 env = getenv(SDK_ROOT_ENV); 55 if (env != NULL && env[0] != 0) { 56 if (path_exists(env)) { 57 D("found " SDK_ROOT_ENV ": %s", env); 58 *pFromEnv = 1; 59 return ASTRDUP(env); 60 } 61 D(SDK_ROOT_ENV " points to unknown directory: %s", env); 62 } 63 64 *pFromEnv = 0; 65 66 /* We assume the emulator binary is under tools/ so use its 67 * parent as the Android SDK root. 68 */ 69 (void) bufprint_app_dir(temp, end); 70 sdkPath = path_parent(temp, 1); 71 if (sdkPath == NULL) { 72 derror("can't find root of SDK directory"); 73 return NULL; 74 } 75 D("found SDK root at %s", sdkPath); 76 return sdkPath; 77 } 78 79 80 /* Return the path to the AVD's root configuration .ini file. it is located in 81 * ~/.android/avd/<name>.ini or Windows equivalent 82 * 83 * This file contains the path to the AVD's content directory, which 84 * includes its own config.ini. 85 */ 86 char* 87 path_getRootIniPath( const char* avdName ) 88 { 89 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 90 91 p = bufprint_config_path(temp, end); 92 p = bufprint(p, end, PATH_SEP ANDROID_AVD_DIR PATH_SEP "%s.ini", avdName); 93 if (p >= end) { 94 return NULL; 95 } 96 if (!path_exists(temp)) { 97 return NULL; 98 } 99 return ASTRDUP(temp); 100 } 101 102 103 char* 104 path_getSdkHome(void) 105 { 106 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 107 p = bufprint_config_path(temp, end); 108 if (p >= end) { 109 APANIC("User path too long!: %s\n", temp); 110 } 111 return strdup(temp); 112 } 113 114 115 static char* 116 _getAvdContentPath(const char* avdName) 117 { 118 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 119 IniFile* ini = NULL; 120 char* iniPath = path_getRootIniPath(avdName); 121 char* avdPath = NULL; 122 123 if (iniPath != NULL) { 124 ini = iniFile_newFromFile(iniPath); 125 AFREE(iniPath); 126 } 127 128 if (ini == NULL) { 129 APANIC("Could not open: %s\n", iniPath == NULL ? avdName : iniPath); 130 } 131 132 avdPath = iniFile_getString(ini, ROOT_ABS_PATH_KEY, NULL); 133 134 if (!path_is_dir(avdPath)) { 135 // If the absolute path doesn't match an actual directory, try 136 // the relative path if present. 137 const char* relPath = iniFile_getString(ini, ROOT_REL_PATH_KEY, NULL); 138 if (relPath != NULL) { 139 p = bufprint_config_path(temp, end); 140 p = bufprint(p, end, PATH_SEP "%s", relPath); 141 if (p < end && path_is_dir(temp)) { 142 AFREE(avdPath); 143 avdPath = ASTRDUP(temp); 144 } 145 } 146 } 147 148 iniFile_free(ini); 149 150 return avdPath; 151 } 152 153 char* 154 propertyFile_getTargetAbi(const FileData* data) { 155 return propertyFile_getValue((const char*)data->data, 156 data->size, 157 "ro.product.cpu.abi"); 158 } 159 160 161 char* 162 propertyFile_getTargetArch(const FileData* data) { 163 char* ret = propertyFile_getTargetAbi(data); 164 if (ret) { 165 // Translate ABI name into architecture name. 166 // By default, there are the same with a few exceptions. 167 static const struct { 168 const char* input; 169 const char* output; 170 } kData[] = { 171 { "armeabi", "arm" }, 172 { "armeabi-v7a", "arm" }, 173 }; 174 size_t n; 175 for (n = 0; n < sizeof(kData)/sizeof(kData[0]); ++n) { 176 if (!strcmp(ret, kData[n].input)) { 177 free(ret); 178 ret = ASTRDUP(kData[n].output); 179 break; 180 } 181 } 182 } 183 return ret; 184 } 185 186 187 int 188 propertyFile_getInt(const FileData* data, const char* key, int _default, 189 SearchResult* searchResult) { 190 char* prop = propertyFile_getValue((const char*)data->data, 191 data->size, 192 key); 193 if (!prop) { 194 if (searchResult) { 195 *searchResult = RESULT_NOT_FOUND; 196 } 197 return _default; 198 } 199 200 char* end; 201 // long is only 32 bits on windows so it isn't enough to detect int overflow 202 long long val = strtoll(prop, &end, 10); 203 if (val < INT_MIN || val > INT_MAX || 204 end == prop || *end != '\0') { 205 D("Invalid int property: '%s:%s'", key, prop); 206 AFREE(prop); 207 if (searchResult) { 208 *searchResult = RESULT_INVALID; 209 } 210 return _default; 211 } 212 213 AFREE(prop); 214 215 if (searchResult) { 216 *searchResult = RESULT_FOUND; 217 } 218 return (int)val; 219 } 220 221 int 222 propertyFile_getApiLevel(const FileData* data) { 223 const int kMinLevel = 3; 224 const int kMaxLevel = 10000; 225 SearchResult searchResult; 226 int level = propertyFile_getInt(data, "ro.build.version.sdk", kMinLevel, 227 &searchResult); 228 if (searchResult == RESULT_NOT_FOUND) { 229 level = kMaxLevel; 230 D("Could not find SDK version in build.prop, default is: %d", level); 231 } else if (searchResult == RESULT_INVALID || level < 0) { 232 D("Defaulting to target API sdkVersion %d", level); 233 } else { 234 D("Found target API sdkVersion: %d\n", level); 235 } 236 return level; 237 } 238 239 int 240 propertyFile_getAdbdCommunicationMode(const FileData* data) { 241 SearchResult searchResult; 242 int qemud = propertyFile_getInt(data, "ro.adb.qemud", 1, &searchResult); 243 if (searchResult == RESULT_FOUND) { 244 D("Found ro.adb.qemud build property: %d", qemud); 245 return qemud; 246 } 247 D("ro.adb.qemud invalid or not found, API >= 16, defaulting ro.adb.qemud==1"); 248 return 1; 249 } 250 251 char* path_getBuildBuildProp(const char* androidOut) { 252 char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp); 253 p = bufprint(temp, end, "%s/system/build.prop", androidOut); 254 if (p >= end) { 255 D("ANDROID_BUILD_OUT is too long: %s\n", androidOut); 256 return NULL; 257 } 258 if (!path_exists(temp)) { 259 D("Cannot find build properties file: %s\n", temp); 260 return NULL; 261 } 262 return ASTRDUP(temp); 263 } 264 265 266 char* path_getBuildBootProp(const char* androidOut) { 267 char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp); 268 p = bufprint(temp, end, "%s/boot.prop", androidOut); 269 if (p >= end) { 270 D("ANDROID_BUILD_OUT is too long: %s\n", androidOut); 271 return NULL; 272 } 273 if (!path_exists(temp)) { 274 D("Cannot find boot properties file: %s\n", temp); 275 return NULL; 276 } 277 return ASTRDUP(temp); 278 } 279 280 281 char* 282 path_getBuildTargetArch(const char* androidOut) { 283 char* buildPropPath = path_getBuildBuildProp(androidOut); 284 if (!buildPropPath) { 285 return NULL; 286 } 287 288 FileData buildProp[1]; 289 fileData_initFromFile(buildProp, buildPropPath); 290 char* ret = propertyFile_getTargetArch(buildProp); 291 fileData_done(buildProp); 292 AFREE(buildPropPath); 293 return ret; 294 } 295 296 297 static char* 298 _getAvdTargetArch(const char* avdPath) 299 { 300 IniFile* ini; 301 char* targetArch = NULL; 302 char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp); 303 p = bufprint(temp, end, "%s" PATH_SEP "config.ini", avdPath); 304 if (p >= end) { 305 APANIC("AVD path too long: %s\n", avdPath); 306 } 307 ini = iniFile_newFromFile(temp); 308 if (ini == NULL) { 309 APANIC("Could not open AVD config file: %s\n", temp); 310 } 311 targetArch = iniFile_getString(ini, "hw.cpu.arch", "arm"); 312 iniFile_free(ini); 313 314 return targetArch; 315 } 316 317 char* 318 path_getAvdTargetArch( const char* avdName ) 319 { 320 char* avdPath = _getAvdContentPath(avdName); 321 char* avdArch = _getAvdTargetArch(avdPath); 322 AFREE(avdPath); 323 324 return avdArch; 325 } 326 327 const char* 328 emulator_getBackendSuffix(const char* targetArch) 329 { 330 if (!targetArch) 331 return NULL; 332 333 static const struct { 334 const char* avd_arch; 335 const char* emulator_suffix; 336 } kPairs[] = { 337 { "arm", "arm" }, 338 { "x86", "x86" }, 339 { "x86_64", "x86" }, 340 { "mips", "mips" }, 341 { "arm64", "arm" }, 342 // Add more if needed here. 343 }; 344 size_t n; 345 for (n = 0; n < sizeof(kPairs)/sizeof(kPairs[0]); ++n) { 346 if (!strcmp(targetArch, kPairs[n].avd_arch)) { 347 return kPairs[n].emulator_suffix; 348 } 349 } 350 return NULL; 351 } 352