AI 143828: am: CL 143808 am: CL 143754 SdkManager: list unknown AVDs and why they didn't load.
Original author: raphael Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143828
This commit is contained in:
committed by
The Android Open Source Project
parent
94967f1cd6
commit
42ab43b51a
@@ -459,11 +459,30 @@ class Main {
|
||||
mSdkLog.printf(" Sdcard: %s\n", sdcard);
|
||||
}
|
||||
}
|
||||
|
||||
// Are there some unused AVDs?
|
||||
List<AvdInfo> badAvds = avdManager.getUnavailableAvdList();
|
||||
|
||||
if (badAvds == null || badAvds.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSdkLog.printf("\nThe following Android Virtual Devices are no longer available:\n");
|
||||
boolean needSeparator = false;
|
||||
for (AvdInfo info : badAvds) {
|
||||
if (needSeparator) {
|
||||
mSdkLog.printf("---------\n");
|
||||
}
|
||||
mSdkLog.printf(" Name: %s\n", info.getName() == null ? "--" : info.getName());
|
||||
mSdkLog.printf(" Path: %s\n", info.getPath() == null ? "--" : info.getPath());
|
||||
mSdkLog.printf(" Error: %s\n", info.getError() == null ? "--" : info.getError());
|
||||
needSeparator = true;
|
||||
}
|
||||
} catch (AndroidLocationException e) {
|
||||
errorAndExit(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new AVD. This is a text based creation with command line prompt.
|
||||
*/
|
||||
|
||||
@@ -32,8 +32,11 @@ import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -118,15 +121,43 @@ public final class AvdManager {
|
||||
private final String mPath;
|
||||
private final IAndroidTarget mTarget;
|
||||
private final Map<String, String> mProperties;
|
||||
|
||||
/** Creates a new AVD info. Values are immutable.
|
||||
* @param properties */
|
||||
private final String mError;
|
||||
|
||||
/**
|
||||
* 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 path The path to the config.ini file
|
||||
* @param target The target. Cannot be null.
|
||||
* @param properties The property map. Cannot be null.
|
||||
*/
|
||||
public AvdInfo(String name, String path, IAndroidTarget target,
|
||||
Map<String, String> properties) {
|
||||
this(name, path, target, properties, null /*error*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 path The path to the config.ini file
|
||||
* @param target The target. Can be null.
|
||||
* @param properties The property map. Can be null.
|
||||
* @param error The error describing why this AVD is invalid. Cannot be null.
|
||||
*/
|
||||
public AvdInfo(String name, String path, IAndroidTarget target,
|
||||
Map<String, String> properties, String error) {
|
||||
mName = name;
|
||||
mPath = path;
|
||||
mTarget = target;
|
||||
mProperties = properties;
|
||||
mError = error;
|
||||
}
|
||||
|
||||
/** Returns the name of the AVD. */
|
||||
@@ -144,6 +175,11 @@ public final class AvdManager {
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
/** Returns the error describing why an AVD failed to load. Always null for valid AVDs. */
|
||||
public String getError() {
|
||||
return mError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that returns the .ini {@link File} for a given AVD name.
|
||||
* @throws AndroidLocationException if there's a problem getting android root directory.
|
||||
@@ -634,29 +670,27 @@ public final class AvdManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void buildAvdList(ArrayList<AvdInfo> list) throws AndroidLocationException {
|
||||
/**
|
||||
* Returns a list of files that are potential AVD ini files.
|
||||
* <p/>
|
||||
* This lists the $HOME/.android/avd/<name>.ini files.
|
||||
* Such files are properties file than then indicate where the AVD folder is located.
|
||||
*
|
||||
* @return A new {@link File} array or null. The array might be empty.
|
||||
* @throws AndroidLocationException if there's a problem getting android root directory.
|
||||
*/
|
||||
private File[] buildAvdFilesList() throws AndroidLocationException {
|
||||
// get the Android prefs location.
|
||||
String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
|
||||
|
||||
final boolean avdListDebug = System.getenv("AVD_LIST_DEBUG") != null;
|
||||
if (avdListDebug) {
|
||||
mSdkLog.printf("[AVD LIST DEBUG] AVD root: '%s'\n", avdRoot);
|
||||
}
|
||||
|
||||
// ensure folder validity.
|
||||
File folder = new File(avdRoot);
|
||||
if (folder.isFile()) {
|
||||
if (avdListDebug) {
|
||||
mSdkLog.printf("[AVD LIST DEBUG] AVD root is a file.\n");
|
||||
}
|
||||
throw new AndroidLocationException(String.format("%s is not a valid folder.", avdRoot));
|
||||
} else if (folder.exists() == false) {
|
||||
if (avdListDebug) {
|
||||
mSdkLog.printf("[AVD LIST DEBUG] AVD root folder doesn't exist, creating.\n");
|
||||
}
|
||||
// folder is not there, we create it and return
|
||||
folder.mkdirs();
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
File[] avds = folder.listFiles(new FilenameFilter() {
|
||||
@@ -664,10 +698,6 @@ public final class AvdManager {
|
||||
if (INI_NAME_PATTERN.matcher(name).matches()) {
|
||||
// check it's a file and not a folder
|
||||
boolean isFile = new File(parent, name).isFile();
|
||||
if (avdListDebug) {
|
||||
mSdkLog.printf("[AVD LIST DEBUG] Item '%s': %s\n",
|
||||
name, isFile ? "accepted file" : "rejected");
|
||||
}
|
||||
return isFile;
|
||||
}
|
||||
|
||||
@@ -675,52 +705,130 @@ public final class AvdManager {
|
||||
}
|
||||
});
|
||||
|
||||
return avds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the internal list of available AVDs.
|
||||
* This only contains AVDs that reference the target currently available.
|
||||
*
|
||||
* @param list An array list that will contain the list of AVDs.
|
||||
* @throws AndroidLocationException if there's a problem getting android root directory.
|
||||
*/
|
||||
private void buildAvdList(ArrayList<AvdInfo> list) throws AndroidLocationException {
|
||||
|
||||
File[] avds = buildAvdFilesList();
|
||||
|
||||
for (File avd : avds) {
|
||||
AvdInfo info = parseAvdInfo(avd);
|
||||
AvdInfo info = parseAvdInfo(avd, false /*acceptError*/);
|
||||
if (info != null) {
|
||||
list.add(info);
|
||||
if (avdListDebug) {
|
||||
mSdkLog.printf("[AVD LIST DEBUG] Added AVD '%s'\n", info.getPath());
|
||||
}
|
||||
} else if (avdListDebug) {
|
||||
mSdkLog.printf("[AVD LIST DEBUG] Failed to parse AVD '%s'\n", avd.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AvdInfo parseAvdInfo(File path) {
|
||||
Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
|
||||
|
||||
public List<AvdInfo> getUnavailableAvdList() throws AndroidLocationException {
|
||||
AvdInfo[] avds = getAvds();
|
||||
File[] allAvds = buildAvdFilesList();
|
||||
if (allAvds == null || allAvds.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TreeSet<File> list = new TreeSet<File>(Arrays.asList(allAvds));
|
||||
|
||||
for (AvdInfo info : avds) {
|
||||
if (list.remove(info.getIniFile())) {
|
||||
if (list.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<AvdInfo> errorAvds = new ArrayList<AvdInfo>(list.size());
|
||||
for (File file : list) {
|
||||
errorAvds.add(parseAvdInfo(file, true /*acceptError*/));
|
||||
}
|
||||
|
||||
return errorAvds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an AVD config.ini to create an {@link AvdInfo}.
|
||||
*
|
||||
* @param path The path to the AVD config.ini
|
||||
* @param acceptError When false, an AVD that fails to load will be discarded and null will be
|
||||
* returned. When true, such an AVD will be returned with an error description.
|
||||
* @return A new {@link AvdInfo} or null if the file is not valid or null if the AVD is not
|
||||
* valid and acceptError is false.
|
||||
*/
|
||||
private AvdInfo parseAvdInfo(File path, boolean acceptError) {
|
||||
String error = null;
|
||||
Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
|
||||
|
||||
String avdPath = map.get(AVD_INFO_PATH);
|
||||
if (avdPath == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String targetHash = map.get(AVD_INFO_TARGET);
|
||||
if (targetHash == null) {
|
||||
return null;
|
||||
|
||||
IAndroidTarget target = null;
|
||||
File configIniFile = null;
|
||||
Map<String, String> properties = null;
|
||||
|
||||
if (targetHash != null) {
|
||||
target = mSdk.getTargetFromHashString(targetHash);
|
||||
}
|
||||
|
||||
IAndroidTarget target = mSdk.getTargetFromHashString(targetHash);
|
||||
if (target == null) {
|
||||
return null;
|
||||
// load the avd properties.
|
||||
if (avdPath != null) {
|
||||
configIniFile = new File(avdPath, CONFIG_INI);
|
||||
}
|
||||
|
||||
// load the avd properties.
|
||||
File configIniFile = new File(avdPath, CONFIG_INI);
|
||||
Map<String, String> properties = SdkManager.parsePropertyFile(configIniFile, mSdkLog);
|
||||
if (configIniFile != null) {
|
||||
properties = SdkManager.parsePropertyFile(configIniFile, mSdkLog);
|
||||
}
|
||||
|
||||
// get name
|
||||
String name = path.getName();
|
||||
Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
|
||||
|
||||
if (matcher.matches()) {
|
||||
name = matcher.group(1);
|
||||
}
|
||||
|
||||
if (!acceptError) {
|
||||
if (avdPath == null ||
|
||||
targetHash == null ||
|
||||
target == null ||
|
||||
configIniFile == null ||
|
||||
properties == null) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (avdPath == null || configIniFile == null) {
|
||||
error = String.format("Missing AVD 'path' property in %1$s", name);
|
||||
} else if (targetHash == null) {
|
||||
error = String.format("Missing 'target' property in %1$s", name);
|
||||
} else if (target == null) {
|
||||
error = String.format("Unknown 'target=%2$s' property in %1$s", name, targetHash);
|
||||
} else if (properties == null) {
|
||||
error = String.format("Failed to parse properties from %1$s", avdPath);
|
||||
}
|
||||
}
|
||||
|
||||
AvdInfo info = new AvdInfo(
|
||||
matcher.matches() ? matcher.group(1) : path.getName(), // should not happen
|
||||
name,
|
||||
avdPath,
|
||||
target,
|
||||
properties);
|
||||
properties,
|
||||
error);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a new AVD config.ini file from a set of properties.
|
||||
*
|
||||
* @param iniFile The file to generate.
|
||||
* @param values THe properties to place in the ini file.
|
||||
* @throws IOException if {@link FileWriter} fails to open, write or close the file.
|
||||
*/
|
||||
private static void createConfigIni(File iniFile, Map<String, String> values)
|
||||
throws IOException {
|
||||
FileWriter writer = new FileWriter(iniFile);
|
||||
@@ -732,6 +840,15 @@ public final class AvdManager {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the tool to create a new SD card image file.
|
||||
*
|
||||
* @param toolLocation The path to the mksdcard tool.
|
||||
* @param size The size of the new SD Card, compatible with {@link #SDCARD_SIZE_PATTERN}.
|
||||
* @param location The path of the new sdcard image file to generate.
|
||||
* @param log The logger object, to report errors.
|
||||
* @return True if the sdcard could be created.
|
||||
*/
|
||||
private boolean createSdCard(String toolLocation, String size, String location, ISdkLog log) {
|
||||
try {
|
||||
String[] command = new String[3];
|
||||
|
||||
Reference in New Issue
Block a user