AI 143885: am: CL 143883 am: CL 143881 AVD #1703143: delete AVDs not loaded correctly.
This covers the case where an AVD has an invalid target or is missing its AVD folder or the config.ini in it. Made some cosmetic cleanup too. Original author: raphael Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143885
This commit is contained in:
committed by
The Android Open Source Project
parent
dc9a9a7bf7
commit
4ca8a78df7
@@ -100,7 +100,7 @@ public class Sdk implements IProjectListener {
|
|||||||
ISdkLog log = new ISdkLog() {
|
ISdkLog log = new ISdkLog() {
|
||||||
public void error(Throwable throwable, String errorFormat, Object... arg) {
|
public void error(Throwable throwable, String errorFormat, Object... arg) {
|
||||||
if (errorFormat != null) {
|
if (errorFormat != null) {
|
||||||
logMessages.add(String.format(errorFormat, arg));
|
logMessages.add(String.format("Error: " + errorFormat, arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
@@ -109,7 +109,7 @@ public class Sdk implements IProjectListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void warning(String warningFormat, Object... arg) {
|
public void warning(String warningFormat, Object... arg) {
|
||||||
logMessages.add(String.format(warningFormat, arg));
|
logMessages.add(String.format("Warning: " + warningFormat, arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void printf(String msgFormat, Object... arg) {
|
public void printf(String msgFormat, Object... arg) {
|
||||||
|
|||||||
@@ -461,13 +461,13 @@ class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Are there some unused AVDs?
|
// Are there some unused AVDs?
|
||||||
List<AvdInfo> badAvds = avdManager.getUnavailableAvdList();
|
List<AvdInfo> badAvds = avdManager.getUnavailableAvds();
|
||||||
|
|
||||||
if (badAvds == null || badAvds.size() == 0) {
|
if (badAvds == null || badAvds.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSdkLog.printf("\nThe following Android Virtual Devices are no longer available:\n");
|
mSdkLog.printf("\nThe following Android Virtual Devices could not be loaded:\n");
|
||||||
boolean needSeparator = false;
|
boolean needSeparator = false;
|
||||||
for (AvdInfo info : badAvds) {
|
for (AvdInfo info : badAvds) {
|
||||||
if (needSeparator) {
|
if (needSeparator) {
|
||||||
@@ -592,7 +592,7 @@ class Main {
|
|||||||
File dir = new File(oldAvdInfo.getPath());
|
File dir = new File(oldAvdInfo.getPath());
|
||||||
avdManager.recursiveDelete(dir);
|
avdManager.recursiveDelete(dir);
|
||||||
dir.delete();
|
dir.delete();
|
||||||
// Remove old avd info from manager
|
// Remove old AVD info from manager
|
||||||
avdManager.removeAvd(oldAvdInfo);
|
avdManager.removeAvd(oldAvdInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,13 +602,27 @@ class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete an AVD.
|
* Delete an AVD. If the AVD name is not part of the available ones look for an
|
||||||
|
* invalid AVD (one not loaded due to some error) to remove it too.
|
||||||
*/
|
*/
|
||||||
private void deleteAvd() {
|
private void deleteAvd() {
|
||||||
try {
|
try {
|
||||||
String avdName = mSdkCommandLine.getParamName();
|
String avdName = mSdkCommandLine.getParamName();
|
||||||
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
|
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
|
||||||
AvdInfo info = avdManager.getAvd(avdName);
|
AvdInfo info = avdManager.getAvd(avdName);
|
||||||
|
|
||||||
|
if (info == null) {
|
||||||
|
// Look in unavailable AVDs
|
||||||
|
List<AvdInfo> badAvds = avdManager.getUnavailableAvds();
|
||||||
|
if (badAvds != null) {
|
||||||
|
for (AvdInfo i : badAvds) {
|
||||||
|
if (i.getName().equals(avdName)) {
|
||||||
|
info = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
errorAndExit("There is no Android Virtual Device named '%s'.", avdName);
|
errorAndExit("There is no Android Virtual Device named '%s'.", avdName);
|
||||||
|
|||||||
@@ -26,8 +26,10 @@ public interface ISdkLog {
|
|||||||
/**
|
/**
|
||||||
* Prints a warning message on stdout.
|
* Prints a warning message on stdout.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
* The message will be tagged with "Warning" on the output so the caller does not
|
||||||
|
* need to put such a prefix in the format string.
|
||||||
|
* <p/>
|
||||||
* Implementations should only display warnings in verbose mode.
|
* Implementations should only display warnings in verbose mode.
|
||||||
* The message should be prefixed with "Warning:".
|
|
||||||
*
|
*
|
||||||
* @param warningFormat is an optional error format. If non-null, it will be printed
|
* @param warningFormat is an optional error format. If non-null, it will be printed
|
||||||
* using a {@link Formatter} with the provided arguments.
|
* using a {@link Formatter} with the provided arguments.
|
||||||
@@ -38,8 +40,10 @@ public interface ISdkLog {
|
|||||||
/**
|
/**
|
||||||
* Prints an error message on stderr.
|
* Prints an error message on stderr.
|
||||||
* <p/>
|
* <p/>
|
||||||
|
* The message will be tagged with "Error" on the output so the caller does not
|
||||||
|
* need to put such a prefix in the format string.
|
||||||
|
* <p/>
|
||||||
* Implementation should always display errors, independent of verbose mode.
|
* Implementation should always display errors, independent of verbose mode.
|
||||||
* The message should be prefixed with "Error:".
|
|
||||||
*
|
*
|
||||||
* @param t is an optional {@link Throwable} or {@link Exception}. If non-null, it's
|
* @param t is an optional {@link Throwable} or {@link Exception}. If non-null, it's
|
||||||
* message will be printed out.
|
* message will be printed out.
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ public final class AvdManager {
|
|||||||
// AVD shouldn't already exist if removePrevious is false.
|
// AVD shouldn't already exist if removePrevious is false.
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
log.error(null,
|
log.error(null,
|
||||||
"Folder %s is in the way. Use --force if you want to overwrite.",
|
"Folder %1$s is in the way. Use --force if you want to overwrite.",
|
||||||
avdFolder.getAbsolutePath());
|
avdFolder.getAbsolutePath());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -429,9 +429,9 @@ public final class AvdManager {
|
|||||||
|
|
||||||
if (log != null) {
|
if (log != null) {
|
||||||
if (target.isPlatform()) {
|
if (target.isPlatform()) {
|
||||||
log.printf("Created AVD '%s' based on %s\n", name, target.getName());
|
log.printf("Created AVD '%1$s' based on %2$s\n", name, target.getName());
|
||||||
} else {
|
} else {
|
||||||
log.printf("Created AVD '%s' based on %s (%s)\n", name, target.getName(),
|
log.printf("Created AVD '%1$s' based on %2$s (%3$s)\n", name, target.getName(),
|
||||||
target.getVendor());
|
target.getVendor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,29 +563,49 @@ public final class AvdManager {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* This also remove it from the manager's list, The caller does not need to
|
* This also remove it from the manager's list, The caller does not need to
|
||||||
* call {@link #removeAvd(AvdInfo)} afterwards.
|
* call {@link #removeAvd(AvdInfo)} afterwards.
|
||||||
|
* <p/>
|
||||||
|
* This method is designed to somehow work with an unavailable AVD, that is an AVD that
|
||||||
|
* could not be loaded due to some error. That means this method still tries to remove
|
||||||
|
* the AVD ini file or its folder if it can be found. An error will be output if any of
|
||||||
|
* these operations fail.
|
||||||
*
|
*
|
||||||
* @param avdInfo the information on the AVD to delete
|
* @param avdInfo the information on the AVD to delete
|
||||||
*/
|
*/
|
||||||
public void deleteAvd(AvdInfo avdInfo, ISdkLog log) {
|
public void deleteAvd(AvdInfo avdInfo, ISdkLog log) {
|
||||||
try {
|
try {
|
||||||
|
boolean error = false;
|
||||||
|
|
||||||
File f = avdInfo.getIniFile();
|
File f = avdInfo.getIniFile();
|
||||||
if (f.exists()) {
|
if (f != null && f.exists()) {
|
||||||
log.warning("Deleting file %s", f.getCanonicalPath());
|
log.warning("Deleting file %1$s", f.getCanonicalPath());
|
||||||
if (!f.delete()) {
|
if (!f.delete()) {
|
||||||
log.error(null, "Failed to delete %s", f.getCanonicalPath());
|
log.error(null, "Failed to delete %1$s", f.getCanonicalPath());
|
||||||
|
error = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f = new File(avdInfo.getPath());
|
String path = avdInfo.getPath();
|
||||||
if (f.exists()) {
|
if (path != null) {
|
||||||
log.warning("Deleting folder %s", f.getCanonicalPath());
|
f = new File(path);
|
||||||
recursiveDelete(f);
|
if (f.exists()) {
|
||||||
if (!f.delete()) {
|
log.warning("Deleting folder %1$s", f.getCanonicalPath());
|
||||||
log.error(null, "Failed to delete %s", f.getCanonicalPath());
|
recursiveDelete(f);
|
||||||
|
if (!f.delete()) {
|
||||||
|
log.error(null, "Failed to delete %1$s", f.getCanonicalPath());
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAvd(avdInfo);
|
removeAvd(avdInfo);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
log.printf("AVD '%1$s' deleted with errors. See warnings above.",
|
||||||
|
avdInfo.getName());
|
||||||
|
} else {
|
||||||
|
log.printf("AVD '%1$s' deleted.", avdInfo.getName());
|
||||||
|
}
|
||||||
|
|
||||||
} catch (AndroidLocationException e) {
|
} catch (AndroidLocationException e) {
|
||||||
log.error(e, null);
|
log.error(e, null);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -611,14 +631,14 @@ public final class AvdManager {
|
|||||||
try {
|
try {
|
||||||
if (paramFolderPath != null) {
|
if (paramFolderPath != null) {
|
||||||
File f = new File(avdInfo.getPath());
|
File f = new File(avdInfo.getPath());
|
||||||
log.warning("Moving '%s' to '%s'.", avdInfo.getPath(), paramFolderPath);
|
log.warning("Moving '%1$s' to '%2$s'.", avdInfo.getPath(), paramFolderPath);
|
||||||
if (!f.renameTo(new File(paramFolderPath))) {
|
if (!f.renameTo(new File(paramFolderPath))) {
|
||||||
log.error(null, "Failed to move '%s' to '%s'.",
|
log.error(null, "Failed to move '%1$s' to '%2$s'.",
|
||||||
avdInfo.getPath(), paramFolderPath);
|
avdInfo.getPath(), paramFolderPath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update avd info
|
// update AVD info
|
||||||
AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath, avdInfo.getTarget(),
|
AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath, avdInfo.getTarget(),
|
||||||
avdInfo.getProperties());
|
avdInfo.getProperties());
|
||||||
mAvdList.remove(avdInfo);
|
mAvdList.remove(avdInfo);
|
||||||
@@ -633,19 +653,22 @@ public final class AvdManager {
|
|||||||
File oldIniFile = avdInfo.getIniFile();
|
File oldIniFile = avdInfo.getIniFile();
|
||||||
File newIniFile = AvdInfo.getIniFile(newName);
|
File newIniFile = AvdInfo.getIniFile(newName);
|
||||||
|
|
||||||
log.warning("Moving '%s' to '%s'.", oldIniFile.getPath(), newIniFile.getPath());
|
log.warning("Moving '%1$s' to '%2$s'.", oldIniFile.getPath(), newIniFile.getPath());
|
||||||
if (!oldIniFile.renameTo(newIniFile)) {
|
if (!oldIniFile.renameTo(newIniFile)) {
|
||||||
log.error(null, "Failed to move '%s' to '%s'.",
|
log.error(null, "Failed to move '%1$s' to '%2$s'.",
|
||||||
oldIniFile.getPath(), newIniFile.getPath());
|
oldIniFile.getPath(), newIniFile.getPath());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update avd info
|
// update AVD info
|
||||||
AvdInfo info = new AvdInfo(newName, avdInfo.getPath(), avdInfo.getTarget(),
|
AvdInfo info = new AvdInfo(newName, avdInfo.getPath(), avdInfo.getTarget(),
|
||||||
avdInfo.getProperties());
|
avdInfo.getProperties());
|
||||||
mAvdList.remove(avdInfo);
|
mAvdList.remove(avdInfo);
|
||||||
mAvdList.add(info);
|
mAvdList.add(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.printf("AVD '%1$s' moved.", avdInfo.getName());
|
||||||
|
|
||||||
} catch (AndroidLocationException e) {
|
} catch (AndroidLocationException e) {
|
||||||
log.error(e, null);
|
log.error(e, null);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -686,7 +709,8 @@ public final class AvdManager {
|
|||||||
// ensure folder validity.
|
// ensure folder validity.
|
||||||
File folder = new File(avdRoot);
|
File folder = new File(avdRoot);
|
||||||
if (folder.isFile()) {
|
if (folder.isFile()) {
|
||||||
throw new AndroidLocationException(String.format("%s is not a valid folder.", avdRoot));
|
throw new AndroidLocationException(
|
||||||
|
String.format("%1$s is not a valid folder.", avdRoot));
|
||||||
} else if (folder.exists() == false) {
|
} else if (folder.exists() == false) {
|
||||||
// folder is not there, we create it and return
|
// folder is not there, we create it and return
|
||||||
folder.mkdirs();
|
folder.mkdirs();
|
||||||
@@ -727,7 +751,21 @@ public final class AvdManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AvdInfo> getUnavailableAvdList() throws AndroidLocationException {
|
/**
|
||||||
|
* Computes the internal list of <em>not</em> available AVDs.
|
||||||
|
* <p/>
|
||||||
|
* These are the AVDs that failed to load for some reason or another.
|
||||||
|
* You can retrieve the load error using {@link AvdInfo#getError()}.
|
||||||
|
* <p/>
|
||||||
|
* These {@link AvdInfo} must not be used for usual operations (e.g. instanciating
|
||||||
|
* an emulator) or trying to use them for anything else but {@link #deleteAvd(AvdInfo, ISdkLog)}
|
||||||
|
* will have unpredictable results -- that is most likely the operation will fail.
|
||||||
|
*
|
||||||
|
* @return A list of unavailable AVDs, all with errors. The list can be null or empty if there
|
||||||
|
* are no AVDs to return.
|
||||||
|
* @throws AndroidLocationException if there's a problem getting android root directory.
|
||||||
|
*/
|
||||||
|
public List<AvdInfo> getUnavailableAvds() throws AndroidLocationException {
|
||||||
AvdInfo[] avds = getAvds();
|
AvdInfo[] avds = getAvds();
|
||||||
File[] allAvds = buildAvdFilesList();
|
File[] allAvds = buildAvdFilesList();
|
||||||
if (allAvds == null || allAvds.length == 0) {
|
if (allAvds == null || allAvds.length == 0) {
|
||||||
@@ -776,7 +814,7 @@ public final class AvdManager {
|
|||||||
target = mSdk.getTargetFromHashString(targetHash);
|
target = mSdk.getTargetFromHashString(targetHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load the avd properties.
|
// load the AVD properties.
|
||||||
if (avdPath != null) {
|
if (avdPath != null) {
|
||||||
configIniFile = new File(avdPath, CONFIG_INI);
|
configIniFile = new File(avdPath, CONFIG_INI);
|
||||||
}
|
}
|
||||||
@@ -806,7 +844,7 @@ public final class AvdManager {
|
|||||||
} else if (targetHash == null) {
|
} else if (targetHash == null) {
|
||||||
error = String.format("Missing 'target' property in %1$s", name);
|
error = String.format("Missing 'target' property in %1$s", name);
|
||||||
} else if (target == null) {
|
} else if (target == null) {
|
||||||
error = String.format("Unknown 'target=%2$s' property in %1$s", name, targetHash);
|
error = String.format("Unknown target '%2$s' in %1$s", name, targetHash);
|
||||||
} else if (properties == null) {
|
} else if (properties == null) {
|
||||||
error = String.format("Failed to parse properties from %1$s", avdPath);
|
error = String.format("Failed to parse properties from %1$s", avdPath);
|
||||||
}
|
}
|
||||||
@@ -834,7 +872,7 @@ public final class AvdManager {
|
|||||||
FileWriter writer = new FileWriter(iniFile);
|
FileWriter writer = new FileWriter(iniFile);
|
||||||
|
|
||||||
for (Entry<String, String> entry : values.entrySet()) {
|
for (Entry<String, String> entry : values.entrySet()) {
|
||||||
writer.write(String.format("%s=%s\n", entry.getKey(), entry.getValue()));
|
writer.write(String.format("%1$s=%2$s\n", entry.getKey(), entry.getValue()));
|
||||||
}
|
}
|
||||||
writer.close();
|
writer.close();
|
||||||
|
|
||||||
@@ -861,26 +899,25 @@ public final class AvdManager {
|
|||||||
ArrayList<String> stdOutput = new ArrayList<String>();
|
ArrayList<String> stdOutput = new ArrayList<String>();
|
||||||
int status = grabProcessOutput(process, errorOutput, stdOutput,
|
int status = grabProcessOutput(process, errorOutput, stdOutput,
|
||||||
true /* waitForReaders */);
|
true /* waitForReaders */);
|
||||||
|
|
||||||
if (status != 0) {
|
if (status == 0) {
|
||||||
log.error(null, "Failed to create the SD card.");
|
return true;
|
||||||
|
} else {
|
||||||
for (String error : errorOutput) {
|
for (String error : errorOutput) {
|
||||||
log.error(null, error);
|
log.error(null, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
log.error(null, "Failed to create the SD card.");
|
// pass, print error below
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(null, "Failed to create the SD card.");
|
// pass, print error below
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.error(null, "Failed to create the SD card.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the stderr/stdout outputs of a process and returns when the process is done.
|
* Gets the stderr/stdout outputs of a process and returns when the process is done.
|
||||||
* Both <b>must</b> be read or the process will block on windows.
|
* Both <b>must</b> be read or the process will block on windows.
|
||||||
|
|||||||
Reference in New Issue
Block a user