blob: c3b6329aa72ef11adfc67f0bda62911b4fca48f5 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdklib.internal.avd;
import com.android.SdkConstants;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.devices.Device;
import java.io.File;
import java.util.Collections;
import java.util.Map;
/**
* An immutable structure describing an Android Virtual Device.
*/
public final class AvdInfo implements Comparable<AvdInfo> {
/**
* Status for an {@link AvdInfo}. Indicates whether or not this AVD is valid.
*/
public static enum AvdStatus {
/** No error */
OK,
/** Missing 'path' property in the ini file */
ERROR_PATH,
/** Missing config.ini file in the AVD data folder */
ERROR_CONFIG,
/** Missing 'target' property in the ini file */
ERROR_TARGET_HASH,
/** Target was not resolved from its hash */
ERROR_TARGET,
/** Unable to parse config.ini */
ERROR_PROPERTIES,
/** System Image folder in config.ini doesn't exist */
ERROR_IMAGE_DIR,
/** The {@link Device} this AVD is based on has changed from its original configuration*/
ERROR_DEVICE_CHANGED,
/** The {@link Device} this AVD is based on is no longer available */
ERROR_DEVICE_MISSING
}
private final String mName;
private final File mIniFile;
private final String mFolderPath;
private final String mTargetHash;
private final IAndroidTarget mTarget;
private final String mAbiType;
/** An immutable map of properties. This must not be modified. Map can be empty. Never null. */
private final Map<String, String> mProperties;
private final AvdStatus mStatus;
/**
* Creates a new valid AVD info. Values are immutable.
* <p/>
* Such an AVD is available and can be used.
* The error string is set to null.
*
* @param name The name of the AVD (for display or reference)
* @param iniFile The path to the config.ini file
* @param folderPath The path to the data directory
* @param targetHash the target hash
* @param target The target. Can be null, if the target was not resolved.
* @param abiType Name of the abi.
* @param properties The property map. If null, an empty map will be created.
*/
public AvdInfo(String name,
File iniFile,
String folderPath,
String targetHash,
IAndroidTarget target,
String abiType,
Map<String, String> properties) {
this(name, iniFile, folderPath, targetHash, target, abiType, properties, AvdStatus.OK);
}
/**
* Creates a new <em>invalid</em> AVD info. Values are immutable.
* <p/>
* Such an AVD is not complete and cannot be used.
* The error string must be non-null.
*
* @param name The name of the AVD (for display or reference)
* @param iniFile The path to the config.ini file
* @param folderPath The path to the data directory
* @param targetHash the target hash
* @param target The target. Can be null, if the target was not resolved.
* @param abiType Name of the abi.
* @param properties The property map. If null, an empty map will be created.
* @param status The {@link AvdStatus} of this AVD. Cannot be null.
*/
public AvdInfo(String name,
File iniFile,
String folderPath,
String targetHash,
IAndroidTarget target,
String abiType,
Map<String, String> properties,
AvdStatus status) {
mName = name;
mIniFile = iniFile;
mFolderPath = folderPath;
mTargetHash = targetHash;
mTarget = target;
mAbiType = abiType;
mProperties = properties == null ? Collections.<String, String>emptyMap()
: Collections.unmodifiableMap(properties);
mStatus = status;
}
/** Returns the name of the AVD. */
public String getName() {
return mName;
}
/** Returns the path of the AVD data directory. */
public String getDataFolderPath() {
return mFolderPath;
}
/** Returns the processor type of the AVD. */
public String getAbiType() {
return mAbiType;
}
public String getCpuArch() {
String cpuArch = mProperties.get(AvdManager.AVD_INI_CPU_ARCH);
if (cpuArch != null) {
return cpuArch;
}
// legacy
return SdkConstants.CPU_ARCH_ARM;
}
public String getDeviceManufacturer() {
String deviceManufacturer = mProperties.get(AvdManager.AVD_INI_DEVICE_MANUFACTURER);
if (deviceManufacturer != null && !deviceManufacturer.isEmpty()) {
return deviceManufacturer;
}
return "";
}
public String getDeviceName() {
String deviceName = mProperties.get(AvdManager.AVD_INI_DEVICE_NAME);
if (deviceName != null && !deviceName.isEmpty()) {
return deviceName;
}
return "";
}
/** Convenience function to return a more user friendly name of the abi type. */
public static String getPrettyAbiType(String raw) {
String s = null;
if (raw.equalsIgnoreCase(SdkConstants.ABI_ARMEABI)) {
s = "ARM (" + SdkConstants.ABI_ARMEABI + ")";
} else if (raw.equalsIgnoreCase(SdkConstants.ABI_ARMEABI_V7A)) {
s = "ARM (" + SdkConstants.ABI_ARMEABI_V7A + ")";
} else if (raw.equalsIgnoreCase(SdkConstants.ABI_INTEL_ATOM)) {
s = "Intel Atom (" + SdkConstants.ABI_INTEL_ATOM + ")";
} else if (raw.equalsIgnoreCase(SdkConstants.ABI_MIPS)) {
s = "MIPS (" + SdkConstants.ABI_MIPS + ")";
} else {
s = raw + " (" + raw + ")";
}
return s;
}
/**
* Returns the target hash string.
*/
public String getTargetHash() {
return mTargetHash;
}
/** Returns the target of the AVD, or <code>null</code> if it has not been resolved. */
public IAndroidTarget getTarget() {
return mTarget;
}
/** Returns the {@link AvdStatus} of the receiver. */
public AvdStatus getStatus() {
return mStatus;
}
/**
* Helper method that returns the default AVD folder that would be used for a given
* AVD name <em>if and only if</em> the AVD was created with the default choice.
* <p/>
* Callers must NOT use this to "guess" the actual folder from an actual AVD since
* the purpose of the AVD .ini file is to be able to change this folder. Callers
* should however use this to create a new {@link AvdInfo} to setup its data folder
* to the default.
* <p/>
* The default is {@code getDefaultAvdFolder()/avdname.avd/}.
* <p/>
* For an actual existing AVD, callers must use {@link #getDataFolderPath()} instead.
*
* @param manager The AVD Manager, used to get the AVD storage path.
* @param avdName The name of the desired AVD.
* @throws AndroidLocationException if there's a problem getting android root directory.
*/
public static File getDefaultAvdFolder(AvdManager manager, String avdName)
throws AndroidLocationException {
return new File(manager.getBaseAvdFolder(),
avdName + AvdManager.AVD_FOLDER_EXTENSION);
}
/**
* Helper method that returns the .ini {@link File} for a given AVD name.
* <p/>
* The default is {@code getDefaultAvdFolder()/avdname.ini}.
*
* @param manager The AVD Manager, used to get the AVD storage path.
* @param avdName The name of the desired AVD.
* @throws AndroidLocationException if there's a problem getting android root directory.
*/
public static File getDefaultIniFile(AvdManager manager, String avdName)
throws AndroidLocationException {
String avdRoot = manager.getBaseAvdFolder();
return new File(avdRoot, avdName + AvdManager.INI_EXTENSION);
}
/**
* Returns the .ini {@link File} for this AVD.
*/
public File getIniFile() {
return mIniFile;
}
/**
* Helper method that returns the Config {@link File} for a given AVD name.
*/
public static File getConfigFile(String path) {
return new File(path, AvdManager.CONFIG_INI);
}
/**
* Returns the Config {@link File} for this AVD.
*/
public File getConfigFile() {
return getConfigFile(mFolderPath);
}
/**
* Returns an unmodifiable map of properties for the AVD.
* This can be empty but not null.
* Callers must NOT try to modify this immutable map.
*/
public Map<String, String> getProperties() {
return mProperties;
}
/**
* Returns the error message for the AVD or <code>null</code> if {@link #getStatus()}
* returns {@link AvdStatus#OK}
*/
public String getErrorMessage() {
switch (mStatus) {
case ERROR_PATH:
return String.format("Missing AVD 'path' property in %1$s", getIniFile());
case ERROR_CONFIG:
return String.format("Missing config.ini file in %1$s", mFolderPath);
case ERROR_TARGET_HASH:
return String.format("Missing 'target' property in %1$s", getIniFile());
case ERROR_TARGET:
return String.format("Unknown target '%1$s' in %2$s",
mTargetHash, getIniFile());
case ERROR_PROPERTIES:
return String.format("Failed to parse properties from %1$s",
getConfigFile());
case ERROR_IMAGE_DIR:
return String.format(
"Invalid value in image.sysdir. Run 'android update avd -n %1$s'",
mName);
case ERROR_DEVICE_CHANGED:
return String.format("%1$s %2$s configuration has changed since AVD creation",
mProperties.get(AvdManager.AVD_INI_DEVICE_MANUFACTURER),
mProperties.get(AvdManager.AVD_INI_DEVICE_NAME));
case ERROR_DEVICE_MISSING:
return String.format("%1$s %2$s no longer exists as a device",
mProperties.get(AvdManager.AVD_INI_DEVICE_MANUFACTURER),
mProperties.get(AvdManager.AVD_INI_DEVICE_NAME));
case OK:
assert false;
return null;
}
return null;
}
/**
* Returns whether an emulator is currently running the AVD.
*/
public boolean isRunning() {
File f = new File(mFolderPath, "userdata-qemu.img.lock"); //$NON-NLS-1$
return f.isFile();
}
/**
* Compares this object with the specified object for order. Returns a
* negative integer, zero, or a positive integer as this object is less
* than, equal to, or greater than the specified object.
*
* @param o the Object to be compared.
* @return a negative integer, zero, or a positive integer as this object is
* less than, equal to, or greater than the specified object.
*/
@Override
public int compareTo(AvdInfo o) {
// first handle possible missing targets (if the AVD failed to load for unresolved targets)
if (mTarget == null && o != null && o.mTarget == null) {
return 0;
} if (mTarget == null) {
return +1;
} else if (o == null || o.mTarget == null) {
return -1;
}
// then compare the targets
int targetDiff = mTarget.compareTo(o.mTarget);
if (targetDiff == 0) {
// same target? compare on the avd name
return mName.compareTo(o.mName);
}
return targetDiff;
}
}