diff options
author | Raphael <raphael@google.com> | 2012-03-09 15:57:22 -0800 |
---|---|---|
committer | Raphael <raphael@google.com> | 2012-03-12 12:50:28 -0700 |
commit | 02d654b5bebc2ea00bffbedfbe650cc2a59fc9d9 (patch) | |
tree | 96d3f18687ddd8c9016d9645c66947baf2d1f458 /sdkmanager/libs/sdkuilib/src | |
parent | 9c0840643be805bec471e655f458f4a622124778 (diff) | |
download | sdk-02d654b5bebc2ea00bffbedfbe650cc2a59fc9d9.zip sdk-02d654b5bebc2ea00bffbedfbe650cc2a59fc9d9.tar.gz sdk-02d654b5bebc2ea00bffbedfbe650cc2a59fc9d9.tar.bz2 |
AVD Manager: don't auto-close 'start emulator' when there's an error.
In the AVD Manager, don't automatically close the
'start emulator' progress dialog if the emulator
has output an error.
A few emulator messages are output to stderr which are
not errors and a few others are sent to stdout which are
not worth printing or an actually errors, so this tries
to adjust the severity accordingly and guess when the
window should be kept open to read these messages.
SDK Bug: 26564
Change-Id: I98c63b38773f395f2f0c0b6112b81b65c10c82f6
Diffstat (limited to 'sdkmanager/libs/sdkuilib/src')
3 files changed, 128 insertions, 92 deletions
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTask.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTask.java index 42d5558..2563a5f 100755 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTask.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTask.java @@ -27,21 +27,48 @@ import org.eclipse.swt.widgets.Shell; */
public final class ProgressTask extends TaskMonitorImpl {
+ private final String mTitle;
private final ProgressTaskDialog mDialog;
- private boolean mAutomaticallyCloseOnTaskCompletion = true;
+ private volatile boolean mAutoClose = true;
/**
* Creates a new {@link ProgressTask} with the given title.
- * The given task will execute in a separate thread (not the UI thread).
- *
- * This blocks till the thread ends.
+ * This does NOT start the task. The caller must invoke {@link #start(ITask)}.
*/
- public ProgressTask(Shell parent, String title, ITask task) {
+ public ProgressTask(Shell parent, String title) {
super(new ProgressTaskDialog(parent));
+ mTitle = title;
mDialog = (ProgressTaskDialog) getUiProvider();
- mDialog.setText(title);
- mDialog.open(createTaskThread(title, task));
+ mDialog.setText(mTitle);
+ }
+
+ /**
+ * Execute the given task in a separate thread (not the UI thread).
+ * This blocks till the thread ends.
+ * <p/>
+ * The {@link ProgressTask} must not be reused after this call.
+ */
+ public void start(ITask task) {
+ assert mDialog != null;
+ mDialog.open(createTaskThread(mTitle, task));
+ }
+
+ /**
+ * Changes the auto-close behavior of the dialog on task completion.
+ *
+ * @param autoClose True if the dialog should be closed automatically when the task
+ * has completed.
+ */
+ public void setAutoClose(boolean autoClose) {
+ if (autoClose != mAutoClose) {
+ if (autoClose) {
+ mDialog.setAutoCloseRequested();
+ } else {
+ mDialog.setManualCloseRequested();
+ }
+ mAutoClose = autoClose;
+ }
}
/**
@@ -56,7 +83,7 @@ public final class ProgressTask extends TaskMonitorImpl { @Override
public void run() {
task.run(ProgressTask.this);
- if (mAutomaticallyCloseOnTaskCompletion) {
+ if (mAutoClose) {
mDialog.setAutoCloseRequested();
} else {
mDialog.setManualCloseRequested();
@@ -68,12 +95,14 @@ public final class ProgressTask extends TaskMonitorImpl { }
/**
- * Sets the dialog to not auto-close since we want the user to see the error.
* {@inheritDoc}
+ * <p/>
+ * Sets the dialog to not auto-close since we want the user to see the error
+ * (this is equivalent to calling {@code setAutoClose(false)}).
*/
@Override
public void logError(String format, Object...args) {
- mAutomaticallyCloseOnTaskCompletion = false;
+ setAutoClose(false);
super.logError(format, args);
}
}
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskFactory.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskFactory.java index ac0bc30..bd2cc14 100755 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskFactory.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskFactory.java @@ -43,8 +43,8 @@ public final class ProgressTaskFactory implements ITaskFactory { public void start(String title, ITaskMonitor parentMonitor, ITask task) {
if (parentMonitor == null) {
- new ProgressTask(mShell, title, task);
-
+ ProgressTask p = new ProgressTask(mShell, title);
+ p.start(task);
} else {
// Use all the reminder of the parent monitor.
if (parentMonitor.getProgressMax() == 0) {
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java index e2e148b..8c0057b 100644 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java @@ -26,6 +26,9 @@ import com.android.sdklib.internal.avd.AvdInfo.AvdStatus; import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.repository.ITask; import com.android.sdklib.internal.repository.ITaskMonitor; +import com.android.sdklib.util.GrabProcessOutput; +import com.android.sdklib.util.GrabProcessOutput.IProcessOutput; +import com.android.sdklib.util.GrabProcessOutput.Wait; import com.android.sdkuilib.internal.repository.SettingsController; import com.android.sdkuilib.internal.repository.icons.ImageFactory; import com.android.sdkuilib.internal.tasks.ProgressTask; @@ -55,10 +58,8 @@ import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -1081,93 +1082,99 @@ public final class AvdSelector { final String[] command = list.toArray(new String[list.size()]); // launch the emulator - new ProgressTask(mTable.getShell(), - "Starting Android Emulator", - new ITask() { - @Override - public void run(ITaskMonitor monitor) { - try { - monitor.setDescription( - "Starting emulator for AVD '%1$s'", - avdName); - int n = 10; - monitor.setProgressMax(n); - Process process = Runtime.getRuntime().exec(command); - grabEmulatorOutput(process, monitor); - - // This small wait prevents the dialog from closing too fast: - // When it works, the emulator returns immediately, even if - // no UI is shown yet. And when it fails (because the AVD is - // locked/running) - // if we don't have a wait we don't capture the error for - // some reason. - for (int i = 0; i < n; i++) { - try { - Thread.sleep(100); - monitor.incProgress(1); - } catch (InterruptedException e) { - // ignore + final ProgressTask progress = new ProgressTask(mTable.getShell(), + "Starting Android Emulator"); + progress.start(new ITask() { + ITaskMonitor mMonitor = null; + + @Override + public void run(final ITaskMonitor monitor) { + mMonitor = monitor; + try { + monitor.setDescription( + "Starting emulator for AVD '%1$s'", + avdName); + monitor.log("Starting emulator for AVD '%1$s'", avdName); + + // we'll wait 100ms*100 = 10s. The emulator sometimes seem to + // start mostly OK just to crash a few seconds later. 10 seconds + // seems a good wait for that case. + int n = 100; + monitor.setProgressMax(n); + + Process process = Runtime.getRuntime().exec(command); + GrabProcessOutput.grabProcessOutput( + process, + Wait.ASYNC, + new IProcessOutput() { + @Override + public void out(String line) { + if (line != null) { + filterStdOut(line); + } } - } - } catch (IOException e) { - monitor.logError("Failed to start emulator: %1$s", - e.getMessage()); + + @Override + public void err(String line) { + if (line != null) { + filterStdErr(line); + } + } + }); + + // This small wait prevents the dialog from closing too fast: + // When it works, the emulator returns immediately, even if + // no UI is shown yet. And when it fails (because the AVD is + // locked/running) this allows us to have time to capture the + // error and display it. + for (int i = 0; i < n; i++) { + try { + Thread.sleep(100); + monitor.incProgress(1); + } catch (InterruptedException e) { + // ignore } } - }); - } - } + } catch (Exception e) { + monitor.logError("Failed to start emulator: %1$s", + e.getMessage()); + } finally { + mMonitor = null; + } + } - /** - * Get the stderr/stdout outputs of a process and return when the process is done. - * Both <b>must</b> be read or the process will block on windows. - * @param process The process to get the output from. - * @param monitor An {@link ITaskMonitor} to capture errors. Cannot be null. - */ - private void grabEmulatorOutput(final Process process, final ITaskMonitor monitor) { - // read the lines as they come. if null is returned, it's because the process finished - new Thread("emu-stderr") { //$NON-NLS-1$ - @Override - public void run() { - // create a buffer to read the stderr output - InputStreamReader is = new InputStreamReader(process.getErrorStream()); - BufferedReader errReader = new BufferedReader(is); - - try { - while (true) { - String line = errReader.readLine(); - if (line != null) { - monitor.logError("%1$s", line); //$NON-NLS-1$ - } else { - break; - } + private void filterStdOut(String line) { + // Skip some non-useful messages. + if (line.indexOf("NSQuickDrawView") != -1) { //$NON-NLS-1$ + // Discard the MacOS warning: + // "This application, or a library it uses, is using NSQuickDrawView, + // which has been deprecated. Apps should cease use of QuickDraw and move + // to Quartz." + return; + } + + if (line.toLowerCase().indexOf("error") != -1 || //$NON-NLS-1$ + line.indexOf("qemu: fatal") != -1) { //$NON-NLS-1$ + // Sometimes the emulator seems to output errors on stdout. Catch these. + mMonitor.logError("%1$s", line); //$NON-NLS-1$ + return; } - } catch (IOException e) { - // do nothing. + + mMonitor.log("%1$s", line); //$NON-NLS-1$ } - } - }.start(); - new Thread("emu-stdout") { //$NON-NLS-1$ - @Override - public void run() { - InputStreamReader is = new InputStreamReader(process.getInputStream()); - BufferedReader outReader = new BufferedReader(is); - - try { - while (true) { - String line = outReader.readLine(); - if (line != null) { - monitor.log("%1$s", line); //$NON-NLS-1$ - } else { - break; - } + private void filterStdErr(String line) { + if (line.indexOf("emulator: device") != -1 || //$NON-NLS-1$ + line.indexOf("HAX is working") != -1) { //$NON-NLS-1$ + // These are not errors. Output them as regular stdout messages. + mMonitor.log("%1$s", line); //$NON-NLS-1$ + return; } - } catch (IOException e) { - // do nothing. + + mMonitor.logError("%1$s", line); //$NON-NLS-1$ } - } - }.start(); + }); + } } private boolean isAvdRepairable(AvdStatus avdStatus) { |