From: Raphael Moll <> Date: Wed, 1 Apr 2009 00:24:12 +0000 (-0700) Subject: AI 143885: am: CL 143883 am: CL 143881 AVD #1703143: delete AVDs not loaded correctly. X-Git-Tag: android-x86-2.2~1097^2~70 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=eb65f483093ac998871afff416508a9c5035d701;p=android-x86%2Fsdk.git 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 --- diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java index ba0b56803..40b3f76ec 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java @@ -100,7 +100,7 @@ public class Sdk implements IProjectListener { ISdkLog log = new ISdkLog() { public void error(Throwable throwable, String errorFormat, Object... arg) { if (errorFormat != null) { - logMessages.add(String.format(errorFormat, arg)); + logMessages.add(String.format("Error: " + errorFormat, arg)); } if (throwable != null) { @@ -109,7 +109,7 @@ public class Sdk implements IProjectListener { } 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) { diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/com/android/sdkmanager/Main.java index 191aa9eda..738640214 100644 --- a/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -461,13 +461,13 @@ class Main { } // Are there some unused AVDs? - List badAvds = avdManager.getUnavailableAvdList(); + List badAvds = avdManager.getUnavailableAvds(); if (badAvds == null || badAvds.size() == 0) { 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; for (AvdInfo info : badAvds) { if (needSeparator) { @@ -592,7 +592,7 @@ class Main { File dir = new File(oldAvdInfo.getPath()); avdManager.recursiveDelete(dir); dir.delete(); - // Remove old avd info from manager + // Remove old AVD info from manager 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() { try { String avdName = mSdkCommandLine.getParamName(); AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog); AvdInfo info = avdManager.getAvd(avdName); + + if (info == null) { + // Look in unavailable AVDs + List badAvds = avdManager.getUnavailableAvds(); + if (badAvds != null) { + for (AvdInfo i : badAvds) { + if (i.getName().equals(avdName)) { + info = i; + break; + } + } + } + } if (info == null) { errorAndExit("There is no Android Virtual Device named '%s'.", avdName); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java index 489451746..163f7a950 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java @@ -26,8 +26,10 @@ public interface ISdkLog { /** * Prints a warning message on stdout. *

+ * 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. + *

* 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 * using a {@link Formatter} with the provided arguments. @@ -38,8 +40,10 @@ public interface ISdkLog { /** * Prints an error message on stderr. *

+ * 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. + *

* 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 * message will be printed out. diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java index 4342551ec..a6326630e 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java @@ -279,7 +279,7 @@ public final class AvdManager { // AVD shouldn't already exist if removePrevious is false. if (log != 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()); } return null; @@ -429,9 +429,9 @@ public final class AvdManager { if (log != null) { 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 { - 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()); } } @@ -563,29 +563,49 @@ public final class AvdManager { *

* This also remove it from the manager's list, The caller does not need to * call {@link #removeAvd(AvdInfo)} afterwards. + *

+ * 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 */ public void deleteAvd(AvdInfo avdInfo, ISdkLog log) { try { + boolean error = false; + File f = avdInfo.getIniFile(); - if (f.exists()) { - log.warning("Deleting file %s", f.getCanonicalPath()); + if (f != null && f.exists()) { + log.warning("Deleting file %1$s", f.getCanonicalPath()); 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()); - if (f.exists()) { - log.warning("Deleting folder %s", f.getCanonicalPath()); - recursiveDelete(f); - if (!f.delete()) { - log.error(null, "Failed to delete %s", f.getCanonicalPath()); + + String path = avdInfo.getPath(); + if (path != null) { + f = new File(path); + if (f.exists()) { + log.warning("Deleting folder %1$s", f.getCanonicalPath()); + recursiveDelete(f); + if (!f.delete()) { + log.error(null, "Failed to delete %1$s", f.getCanonicalPath()); + error = true; + } } } 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) { log.error(e, null); } catch (IOException e) { @@ -611,14 +631,14 @@ public final class AvdManager { try { if (paramFolderPath != null) { 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))) { - log.error(null, "Failed to move '%s' to '%s'.", + log.error(null, "Failed to move '%1$s' to '%2$s'.", avdInfo.getPath(), paramFolderPath); return false; } - // update avd info + // update AVD info AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath, avdInfo.getTarget(), avdInfo.getProperties()); mAvdList.remove(avdInfo); @@ -633,19 +653,22 @@ public final class AvdManager { File oldIniFile = avdInfo.getIniFile(); 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)) { - log.error(null, "Failed to move '%s' to '%s'.", + log.error(null, "Failed to move '%1$s' to '%2$s'.", oldIniFile.getPath(), newIniFile.getPath()); return false; } - // update avd info + // update AVD info AvdInfo info = new AvdInfo(newName, avdInfo.getPath(), avdInfo.getTarget(), avdInfo.getProperties()); mAvdList.remove(avdInfo); mAvdList.add(info); } + + log.printf("AVD '%1$s' moved.", avdInfo.getName()); + } catch (AndroidLocationException e) { log.error(e, null); } catch (IOException e) { @@ -686,7 +709,8 @@ public final class AvdManager { // ensure folder validity. File folder = new File(avdRoot); 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) { // folder is not there, we create it and return folder.mkdirs(); @@ -727,7 +751,21 @@ public final class AvdManager { } } - public List getUnavailableAvdList() throws AndroidLocationException { + /** + * Computes the internal list of not available AVDs. + *

+ * These are the AVDs that failed to load for some reason or another. + * You can retrieve the load error using {@link AvdInfo#getError()}. + *

+ * 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 getUnavailableAvds() throws AndroidLocationException { AvdInfo[] avds = getAvds(); File[] allAvds = buildAvdFilesList(); if (allAvds == null || allAvds.length == 0) { @@ -776,7 +814,7 @@ public final class AvdManager { target = mSdk.getTargetFromHashString(targetHash); } - // load the avd properties. + // load the AVD properties. if (avdPath != null) { configIniFile = new File(avdPath, CONFIG_INI); } @@ -806,7 +844,7 @@ public final class AvdManager { } 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); + error = String.format("Unknown target '%2$s' in %1$s", name, targetHash); } else if (properties == null) { error = String.format("Failed to parse properties from %1$s", avdPath); } @@ -834,7 +872,7 @@ public final class AvdManager { FileWriter writer = new FileWriter(iniFile); for (Entry 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(); @@ -861,26 +899,25 @@ public final class AvdManager { ArrayList stdOutput = new ArrayList(); int status = grabProcessOutput(process, errorOutput, stdOutput, true /* waitForReaders */); - - if (status != 0) { - log.error(null, "Failed to create the SD card."); + + if (status == 0) { + return true; + } else { for (String error : errorOutput) { log.error(null, error); } - - return false; } - return true; } catch (InterruptedException e) { - log.error(null, "Failed to create the SD card."); + // pass, print error below } 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; } - + /** * Gets the stderr/stdout outputs of a process and returns when the process is done. * Both must be read or the process will block on windows.