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 { 156 s = raw + " (" + raw + ")"; 157 } 158 return s; 159 } 160 161 /** 162 * Returns the target hash string. 163 */ 164 public String getTargetHash() { 165 return mTargetHash; 166 } 167 168 /** Returns the target of the AVD, or <code>null</code> if it has not been resolved. */ 169 public IAndroidTarget getTarget() { 170 return mTarget; 171 } 172 173 /** Returns the {@link AvdStatus} of the receiver. */ 174 public AvdStatus getStatus() { 175 return mStatus; 176 } 177 178 /** 179 * Helper method that returns the default AVD folder that would be used for a given 180 * AVD name <em>if and only if</em> the AVD was created with the default choice. 181 * <p/> 182 * Callers must NOT use this to "guess" the actual folder from an actual AVD since 183 * the purpose of the AVD .ini file is to be able to change this folder. Callers 184 * should however use this to create a new {@link AvdInfo} to setup its data folder 185 * to the default. 186 * <p/> 187 * The default is {@code getDefaultAvdFolder()/avdname.avd/}. 188 * <p/> 189 * For an actual existing AVD, callers must use {@link #getDataFolderPath()} instead. 190 * 191 * @param manager The AVD Manager, used to get the AVD storage path. 192 * @param avdName The name of the desired AVD. 193 * @throws AndroidLocationException if there's a problem getting android root directory. 194 */ 195 public static File getDefaultAvdFolder(AvdManager manager, String avdName) 196 throws AndroidLocationException { 197 return new File(manager.getBaseAvdFolder(), 198 avdName + AvdManager.AVD_FOLDER_EXTENSION); 199 } 200 201 /** 202 * Helper method that returns the .ini {@link File} for a given AVD name. 203 * <p/> 204 * The default is {@code getDefaultAvdFolder()/avdname.ini}. 205 * 206 * @param manager The AVD Manager, used to get the AVD storage path. 207 * @param avdName The name of the desired AVD. 208 * @throws AndroidLocationException if there's a problem getting android root directory. 209 */ 210 public static File getDefaultIniFile(AvdManager manager, String avdName) 211 throws AndroidLocationException { 212 String avdRoot = manager.getBaseAvdFolder(); 213 return new File(avdRoot, avdName + AvdManager.INI_EXTENSION); 214 } 215 216 /** 217 * Returns the .ini {@link File} for this AVD. 218 */ 219 public File getIniFile() { 220 return mIniFile; 221 } 222 223 /** 224 * Helper method that returns the Config {@link File} for a given AVD name. 225 */ 226 public static File getConfigFile(String path) { 227 return new File(path, AvdManager.CONFIG_INI); 228 } 229 230 /** 231 * Returns the Config {@link File} for this AVD. 232 */ 233 public File getConfigFile() { 234 return getConfigFile(mFolderPath); 235 } 236 237 /** 238 * Returns an unmodifiable map of properties for the AVD. This can be null. 239 */ 240 public Map<String, String> getProperties() { 241 return mProperties; 242 } 243 244 /** 245 * Returns the error message for the AVD or <code>null</code> if {@link #getStatus()} 246 * returns {@link AvdStatus#OK} 247 */ 248 public String getErrorMessage() { 249 switch (mStatus) { 250 case ERROR_PATH: 251 return String.format("Missing AVD 'path' property in %1$s", getIniFile()); 252 case ERROR_CONFIG: 253 return String.format("Missing config.ini file in %1$s", mFolderPath); 254 case ERROR_TARGET_HASH: 255 return String.format("Missing 'target' property in %1$s", getIniFile()); 256 case ERROR_TARGET: 257 return String.format("Unknown target '%1$s' in %2$s", 258 mTargetHash, getIniFile()); 259 case ERROR_PROPERTIES: 260 return String.format("Failed to parse properties from %1$s", 261 getConfigFile()); 262 case ERROR_IMAGE_DIR: 263 return String.format( 264 "Invalid value in image.sysdir. Run 'android update avd -n %1$s'", 265 mName); 266 case OK: 267 assert false; 268 return null; 269 } 270 271 return null; 272 } 273 274 /** 275 * Returns whether an emulator is currently running the AVD. 276 */ 277 public boolean isRunning() { 278 File f = new File(mFolderPath, "userdata-qemu.img.lock"); //$NON-NLS-1$ 279 return f.isFile(); 280 } 281 282 /** 283 * Compares this object with the specified object for order. Returns a 284 * negative integer, zero, or a positive integer as this object is less 285 * than, equal to, or greater than the specified object. 286 * 287 * @param o the Object to be compared. 288 * @return a negative integer, zero, or a positive integer as this object is 289 * less than, equal to, or greater than the specified object. 290 */ 291 public int compareTo(AvdInfo o) { 292 // first handle possible missing targets (if the AVD failed to load for unresolved targets) 293 if (mTarget == null && o != null && o.mTarget == null) { 294 return 0; 295 } if (mTarget == null) { 296 return +1; 297 } else if (o == null || o.mTarget == null) { 298 return -1; 299 } 300 301 // then compare the targets 302 int targetDiff = mTarget.compareTo(o.mTarget); 303 304 if (targetDiff == 0) { 305 // same target? compare on the avd name 306 return mName.compareTo(o.mName); 307 } 308 309 return targetDiff; 310 } 311 } 312