1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.sdklib.internal.avd; 18 19 import com.android.prefs.AndroidLocation.AndroidLocationException; 20 import com.android.sdklib.IAndroidTarget; 21 import com.android.sdklib.SdkConstants; 22 23 import java.io.File; 24 import java.util.Collections; 25 import java.util.Map; 26 27 /** 28 * An immutable structure describing an Android Virtual Device. 29 */ 30 public final class AvdInfo implements Comparable<AvdInfo> { 31 32 /** 33 * Status for an {@link AvdInfo}. Indicates whether or not this AVD is valid. 34 */ 35 public static enum AvdStatus { 36 /** No error */ 37 OK, 38 /** Missing 'path' property in the ini file */ 39 ERROR_PATH, 40 /** Missing config.ini file in the AVD data folder */ 41 ERROR_CONFIG, 42 /** Missing 'target' property in the ini file */ 43 ERROR_TARGET_HASH, 44 /** Target was not resolved from its hash */ 45 ERROR_TARGET, 46 /** Unable to parse config.ini */ 47 ERROR_PROPERTIES, 48 /** System Image folder in config.ini doesn't exist */ 49 ERROR_IMAGE_DIR; 50 } 51 52 private final String mName; 53 private final File mIniFile; 54 private final String mFolderPath; 55 private final String mTargetHash; 56 private final IAndroidTarget mTarget; 57 private final String mAbiType; 58 private final Map<String, String> mProperties; 59 private final AvdStatus mStatus; 60 61 /** 62 * Creates a new valid AVD info. Values are immutable. 63 * <p/> 64 * Such an AVD is available and can be used. 65 * The error string is set to null. 66 * 67 * @param name The name of the AVD (for display or reference) 68 * @param iniFile The path to the config.ini file 69 * @param folderPath The path to the data directory 70 * @param targetHash the target hash 71 * @param target The target. Can be null, if the target was not resolved. 72 * @param abiType Name of the abi. 73 * @param properties The property map. Cannot be null. 74 */ 75 public AvdInfo(String name, 76 File iniFile, 77 String folderPath, 78 String targetHash, 79 IAndroidTarget target, 80 String abiType, 81 Map<String, String> properties) { 82 this(name, iniFile, folderPath, targetHash, target, abiType, properties, AvdStatus.OK); 83 } 84 85 /** 86 * Creates a new <em>invalid</em> AVD info. Values are immutable. 87 * <p/> 88 * Such an AVD is not complete and cannot be used. 89 * The error string must be non-null. 90 * 91 * @param name The name of the AVD (for display or reference) 92 * @param iniFile The path to the config.ini file 93 * @param folderPath The path to the data directory 94 * @param targetHash the target hash 95 * @param target The target. Can be null, if the target was not resolved. 96 * @param abiType Name of the abi. 97 * @param properties The property map. Can be null. 98 * @param status The {@link AvdStatus} of this AVD. Cannot be null. 99 */ 100 public AvdInfo(String name, 101 File iniFile, 102 String folderPath, 103 String targetHash, 104 IAndroidTarget target, 105 String abiType, 106 Map<String, String> properties, 107 AvdStatus status) { 108 mName = name; 109 mIniFile = iniFile; 110 mFolderPath = folderPath; 111 mTargetHash = targetHash; 112 mTarget = target; 113 mAbiType = abiType; 114 mProperties = properties == null ? null : Collections.unmodifiableMap(properties); 115 mStatus = status; 116 } 117 118 /** Returns the name of the AVD. */ 119 public String getName() { 120 return mName; 121 } 122 123 /** Returns the path of the AVD data directory. */ 124 public String getDataFolderPath() { 125 return mFolderPath; 126 } 127 128 /** Returns the processor type of the AVD. */ 129 public String getAbiType() { 130 return mAbiType; 131 } 132 133 public String getCpuArch() { 134 String cpuArch = mProperties.get(AvdManager.AVD_INI_CPU_ARCH); 135 if (cpuArch != null) { 136 return cpuArch; 137 } 138 139 // legacy 140 return SdkConstants.CPU_ARCH_ARM; 141 } 142 143 /** Convenience function to return a more user friendly name of the abi type. */ 144 public static String getPrettyAbiType(String raw) { 145 String s = null; 146 if (raw.equalsIgnoreCase(SdkConstants.ABI_ARMEABI)) { 147 s = "ARM (" + SdkConstants.ABI_ARMEABI + ")"; 148 149 } else if (raw.equalsIgnoreCase(SdkConstants.ABI_ARMEABI_V7A)) { 150 s = "ARM (" + SdkConstants.ABI_ARMEABI_V7A + ")"; 151 152 } else if (raw.equalsIgnoreCase(SdkConstants.ABI_INTEL_ATOM)) { 153 s = "Intel Atom (" + SdkConstants.ABI_INTEL_ATOM + ")"; 154 155 } else if (raw.equalsIgnoreCase(SdkConstants.ABI_MIPS)) { 156 s = "Mips (" + SdkConstants.ABI_MIPS + ")"; 157 158 } else { 159 s = raw + " (" + raw + ")"; 160 } 161 return s; 162 } 163 164 /** 165 * Returns the target hash string. 166 */ 167 public String getTargetHash() { 168 return mTargetHash; 169 } 170 171 /** Returns the target of the AVD, or <code>null</code> if it has not been resolved. */ 172 public IAndroidTarget getTarget() { 173 return mTarget; 174 } 175 176 /** Returns the {@link AvdStatus} of the receiver. */ 177 public AvdStatus getStatus() { 178 return mStatus; 179 } 180 181 /** 182 * Helper method that returns the default AVD folder that would be used for a given 183 * AVD name <em>if and only if</em> the AVD was created with the default choice. 184 * <p/> 185 * Callers must NOT use this to "guess" the actual folder from an actual AVD since 186 * the purpose of the AVD .ini file is to be able to change this folder. Callers 187 * should however use this to create a new {@link AvdInfo} to setup its data folder 188 * to the default. 189 * <p/> 190 * The default is {@code getDefaultAvdFolder()/avdname.avd/}. 191 * <p/> 192 * For an actual existing AVD, callers must use {@link #getDataFolderPath()} instead. 193 * 194 * @param manager The AVD Manager, used to get the AVD storage path. 195 * @param avdName The name of the desired AVD. 196 * @throws AndroidLocationException if there's a problem getting android root directory. 197 */ 198 public static File getDefaultAvdFolder(AvdManager manager, String avdName) 199 throws AndroidLocationException { 200 return new File(manager.getBaseAvdFolder(), 201 avdName + AvdManager.AVD_FOLDER_EXTENSION); 202 } 203 204 /** 205 * Helper method that returns the .ini {@link File} for a given AVD name. 206 * <p/> 207 * The default is {@code getDefaultAvdFolder()/avdname.ini}. 208 * 209 * @param manager The AVD Manager, used to get the AVD storage path. 210 * @param avdName The name of the desired AVD. 211 * @throws AndroidLocationException if there's a problem getting android root directory. 212 */ 213 public static File getDefaultIniFile(AvdManager manager, String avdName) 214 throws AndroidLocationException { 215 String avdRoot = manager.getBaseAvdFolder(); 216 return new File(avdRoot, avdName + AvdManager.INI_EXTENSION); 217 } 218 219 /** 220 * Returns the .ini {@link File} for this AVD. 221 */ 222 public File getIniFile() { 223 return mIniFile; 224 } 225 226 /** 227 * Helper method that returns the Config {@link File} for a given AVD name. 228 */ 229 public static File getConfigFile(String path) { 230 return new File(path, AvdManager.CONFIG_INI); 231 } 232 233 /** 234 * Returns the Config {@link File} for this AVD. 235 */ 236 public File getConfigFile() { 237 return getConfigFile(mFolderPath); 238 } 239 240 /** 241 * Returns an unmodifiable map of properties for the AVD. This can be null. 242 */ 243 public Map<String, String> getProperties() { 244 return mProperties; 245 } 246 247 /** 248 * Returns the error message for the AVD or <code>null</code> if {@link #getStatus()} 249 * returns {@link AvdStatus#OK} 250 */ 251 public String getErrorMessage() { 252 switch (mStatus) { 253 case ERROR_PATH: 254 return String.format("Missing AVD 'path' property in %1$s", getIniFile()); 255 case ERROR_CONFIG: 256 return String.format("Missing config.ini file in %1$s", mFolderPath); 257 case ERROR_TARGET_HASH: 258 return String.format("Missing 'target' property in %1$s", getIniFile()); 259 case ERROR_TARGET: 260 return String.format("Unknown target '%1$s' in %2$s", 261 mTargetHash, getIniFile()); 262 case ERROR_PROPERTIES: 263 return String.format("Failed to parse properties from %1$s", 264 getConfigFile()); 265 case ERROR_IMAGE_DIR: 266 return String.format( 267 "Invalid value in image.sysdir. Run 'android update avd -n %1$s'", 268 mName); 269 case OK: 270 assert false; 271 return null; 272 } 273 274 return null; 275 } 276 277 /** 278 * Returns whether an emulator is currently running the AVD. 279 */ 280 public boolean isRunning() { 281 File f = new File(mFolderPath, "userdata-qemu.img.lock"); //$NON-NLS-1$ 282 return f.isFile(); 283 } 284 285 /** 286 * Compares this object with the specified object for order. Returns a 287 * negative integer, zero, or a positive integer as this object is less 288 * than, equal to, or greater than the specified object. 289 * 290 * @param o the Object to be compared. 291 * @return a negative integer, zero, or a positive integer as this object is 292 * less than, equal to, or greater than the specified object. 293 */ 294 @Override 295 public int compareTo(AvdInfo o) { 296 // first handle possible missing targets (if the AVD failed to load for unresolved targets) 297 if (mTarget == null && o != null && o.mTarget == null) { 298 return 0; 299 } if (mTarget == null) { 300 return +1; 301 } else if (o == null || o.mTarget == null) { 302 return -1; 303 } 304 305 // then compare the targets 306 int targetDiff = mTarget.compareTo(o.mTarget); 307 308 if (targetDiff == 0) { 309 // same target? compare on the avd name 310 return mName.compareTo(o.mName); 311 } 312 313 return targetDiff; 314 } 315 } 316