diff options
33 files changed, 848 insertions, 545 deletions
diff --git a/ddms/app/src/com/android/ddms/DeviceCommandDialog.java b/ddms/app/src/com/android/ddms/DeviceCommandDialog.java index 6145733..ce6865d 100644 --- a/ddms/app/src/com/android/ddms/DeviceCommandDialog.java +++ b/ddms/app/src/com/android/ddms/DeviceCommandDialog.java @@ -17,9 +17,12 @@ package com.android.ddms; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.IDevice; import com.android.ddmlib.IShellOutputReceiver; import com.android.ddmlib.Log; +import com.android.ddmlib.ShellCommandUnresponsiveException; +import com.android.ddmlib.TimeoutException; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; @@ -256,6 +259,15 @@ public class DeviceCommandDialog extends Dialog { catch (IOException ioe) { Log.w("ddms", "Remote exec failed: " + ioe.getMessage()); mResult = RESULT_FAILURE; + } catch (TimeoutException e) { + Log.w("ddms", "Remote exec failed: " + e.getMessage()); + mResult = RESULT_FAILURE; + } catch (AdbCommandRejectedException e) { + Log.w("ddms", "Remote exec failed: " + e.getMessage()); + mResult = RESULT_FAILURE; + } catch (ShellCommandUnresponsiveException e) { + Log.w("ddms", "Remote exec failed: " + e.getMessage()); + mResult = RESULT_FAILURE; } } diff --git a/ddms/app/src/com/android/ddms/UIThread.java b/ddms/app/src/com/android/ddms/UIThread.java index 723442d..9ba1ea0 100644 --- a/ddms/app/src/com/android/ddms/UIThread.java +++ b/ddms/app/src/com/android/ddms/UIThread.java @@ -21,13 +21,13 @@ import com.android.ddmlib.Client; import com.android.ddmlib.ClientData; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; +import com.android.ddmlib.SyncException; import com.android.ddmlib.SyncService; import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; import com.android.ddmlib.ClientData.IHprofDumpHandler; import com.android.ddmlib.ClientData.MethodProfilingStatus; import com.android.ddmlib.Log.ILogOutput; import com.android.ddmlib.Log.LogLevel; -import com.android.ddmlib.SyncService.SyncResult; import com.android.ddmuilib.AllocationPanel; import com.android.ddmuilib.DevicePanel; import com.android.ddmuilib.EmulatorControlPanel; @@ -328,18 +328,20 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener { // get the sync service to pull the HPROF file final SyncService sync = client.getDevice().getSyncService(); if (sync != null) { - SyncResult result = promptAndPull(sync, + promptAndPull(sync, client.getClientData().getClientDescription() + ".hprof", remoteFilePath, "Save HPROF file"); - if (result != null && result.getCode() != SyncService.RESULT_OK) { - displayErrorFromUiThread( - "Unable to download HPROF file from device '%1$s'.\n\n%2$s", - device.getSerialNumber(), result.getMessage()); - } } else { - displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.", + displayErrorFromUiThread( + "Unable to download HPROF file from device '%1$s'.", device.getSerialNumber()); } + } catch (SyncException e) { + if (e.wasCanceled() == false) { + displayErrorFromUiThread( + "Unable to download HPROF file from device '%1$s'.\n\n%2$s", + device.getSerialNumber(), e.getMessage()); + } } catch (Exception e) { displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.", device.getSerialNumber()); diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbCommandRejectedException.java b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbCommandRejectedException.java index 673acb5..ae7d014 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbCommandRejectedException.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbCommandRejectedException.java @@ -16,12 +16,11 @@ package com.android.ddmlib; -import java.io.IOException; /** * Exception thrown when adb refuses a command. */ -public class AdbCommandRejectedException extends IOException { +public class AdbCommandRejectedException extends Exception { private static final long serialVersionUID = 1L; private final boolean mIsDeviceOffline; private final boolean mErrorDuringDeviceSelection; diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/CanceledException.java b/ddms/libs/ddmlib/src/com/android/ddmlib/CanceledException.java new file mode 100644 index 0000000..84eda03 --- /dev/null +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/CanceledException.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 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.ddmlib; + +/** + * Abstract exception for exception that can be thrown when a user input cancels the action. + * <p/> + * {@link #wasCanceled()} returns whether the action was canceled because of user input. + * + */ +public abstract class CanceledException extends Exception { + private static final long serialVersionUID = 1L; + + CanceledException(String message) { + super(message); + } + + CanceledException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Returns true if the action was canceled by user input. + */ + public abstract boolean wasCanceled(); +} diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java b/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java index 7eff98e..bb61e5f 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java @@ -16,7 +16,6 @@ package com.android.ddmlib; -import com.android.ddmlib.SyncService.SyncResult; import com.android.ddmlib.log.LogReceiver; import java.io.File; @@ -408,16 +407,25 @@ final class Device implements IDevice { } public String installPackage(String packageFilePath, boolean reinstall) - throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, - IOException { - String remoteFilePath = syncPackageToDevice(packageFilePath); - String result = installRemotePackage(remoteFilePath, reinstall); - removeRemotePackage(remoteFilePath); - return result; + throws InstallException { + try { + String remoteFilePath = syncPackageToDevice(packageFilePath); + String result = installRemotePackage(remoteFilePath, reinstall); + removeRemotePackage(remoteFilePath); + return result; + } catch (IOException e) { + throw new InstallException(e); + } catch (AdbCommandRejectedException e) { + throw new InstallException(e); + } catch (TimeoutException e) { + throw new InstallException(e); + } catch (SyncException e) { + throw new InstallException(e); + } } public String syncPackageToDevice(String localFilePath) - throws IOException, AdbCommandRejectedException, TimeoutException { + throws IOException, AdbCommandRejectedException, TimeoutException, SyncException { try { String packageFileName = getFileName(localFilePath); String remoteFilePath = String.format("/data/local/tmp/%1$s", packageFileName); //$NON-NLS-1$ @@ -430,24 +438,23 @@ final class Device implements IDevice { String message = String.format("Uploading file onto device '%1$s'", getSerialNumber()); Log.d(LOG_TAG, message); - SyncResult result = sync.pushFile(localFilePath, remoteFilePath, - SyncService.getNullProgressMonitor()); - - if (result.getCode() != SyncService.RESULT_OK) { - throw new IOException(String.format("Unable to upload file: %1$s", - result.getMessage())); - } + sync.pushFile(localFilePath, remoteFilePath, SyncService.getNullProgressMonitor()); } else { throw new IOException("Unable to open sync connection!"); } return remoteFilePath; } catch (TimeoutException e) { - Log.e(LOG_TAG, "Unable to open sync connection! Timeout."); + Log.e(LOG_TAG, "Error during Sync: timeout."); + throw e; + + } catch (SyncException e) { + Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage())); throw e; + } catch (IOException e) { - Log.e(LOG_TAG, String.format("Unable to open sync connection! reason: %1$s", - e.getMessage())); + Log.e(LOG_TAG, String.format("Error during Sync: %1$s", e.getMessage())); throw e; + } } @@ -461,40 +468,52 @@ final class Device implements IDevice { } public String installRemotePackage(String remoteFilePath, boolean reinstall) - throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, - IOException { - InstallReceiver receiver = new InstallReceiver(); - String cmd = String.format(reinstall ? "pm install -r \"%1$s\"" : "pm install \"%1$s\"", - remoteFilePath); - executeShellCommand(cmd, receiver, INSTALL_TIMEOUT); - return receiver.getErrorMessage(); + throws InstallException { + try { + InstallReceiver receiver = new InstallReceiver(); + String cmd = String.format(reinstall ? "pm install -r \"%1$s\"" : "pm install \"%1$s\"", + remoteFilePath); + executeShellCommand(cmd, receiver, INSTALL_TIMEOUT); + return receiver.getErrorMessage(); + } catch (TimeoutException e) { + throw new InstallException(e); + } catch (AdbCommandRejectedException e) { + throw new InstallException(e); + } catch (ShellCommandUnresponsiveException e) { + throw new InstallException(e); + } catch (IOException e) { + throw new InstallException(e); + } } - /** - * {@inheritDoc} - */ - public void removeRemotePackage(String remoteFilePath) - throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, - IOException { - // now we delete the app we sync'ed + public void removeRemotePackage(String remoteFilePath) throws InstallException { try { executeShellCommand("rm " + remoteFilePath, new NullOutputReceiver(), INSTALL_TIMEOUT); } catch (IOException e) { - Log.e(LOG_TAG, String.format("Failed to delete temporary package: %1$s", - e.getMessage())); - throw e; + throw new InstallException(e); + } catch (TimeoutException e) { + throw new InstallException(e); + } catch (AdbCommandRejectedException e) { + throw new InstallException(e); + } catch (ShellCommandUnresponsiveException e) { + throw new InstallException(e); } } - /** - * {@inheritDoc} - */ - public String uninstallPackage(String packageName) - throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, - IOException { - InstallReceiver receiver = new InstallReceiver(); - executeShellCommand("pm uninstall " + packageName, receiver, INSTALL_TIMEOUT); - return receiver.getErrorMessage(); + public String uninstallPackage(String packageName) throws InstallException { + try { + InstallReceiver receiver = new InstallReceiver(); + executeShellCommand("pm uninstall " + packageName, receiver, INSTALL_TIMEOUT); + return receiver.getErrorMessage(); + } catch (TimeoutException e) { + throw new InstallException(e); + } catch (AdbCommandRejectedException e) { + throw new InstallException(e); + } catch (ShellCommandUnresponsiveException e) { + throw new InstallException(e); + } catch (IOException e) { + throw new InstallException(e); + } } /* diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java b/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java index 01814ac..c2e2c16 100755 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java @@ -322,15 +322,10 @@ public interface IDevice { * @param packageFilePath the absolute file system path to file on local host to install * @param reinstall set to <code>true</code> if re-install of app should be performed * @return a {@link String} with an error code, or <code>null</code> if success. - * @throws TimeoutException in case of timeout on the connection. - * @throws AdbCommandRejectedException if adb rejects the command - * @throws ShellCommandUnresponsiveException if the device didn't respond for long time when - * performing the action. - * @throws IOException in case of I/O error on the connection. + * @throws InstallException if the installation fails. */ public String installPackage(String packageFilePath, boolean reinstall) - throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, - IOException; + throws InstallException; /** * Pushes a file to device @@ -340,53 +335,37 @@ public interface IDevice { * @throws TimeoutException in case of timeout on the connection. * @throws AdbCommandRejectedException if adb rejects the command * @throws IOException in case of I/O error on the connection. + * @throws SyncException if an error happens during the push of the package on the device. */ public String syncPackageToDevice(String localFilePath) - throws TimeoutException, AdbCommandRejectedException, IOException; + throws TimeoutException, AdbCommandRejectedException, IOException, SyncException; /** * Installs the application package that was pushed to a temporary location on the device. * * @param remoteFilePath absolute file path to package file on device * @param reinstall set to <code>true</code> if re-install of app should be performed - * @throws TimeoutException in case of timeout on the connection. - * @throws AdbCommandRejectedException if adb rejects the command - * @throws ShellCommandUnresponsiveException if the device didn't respond for long time when - * performing the action. - * @throws IOException if installation failed + * @throws InstallException if the installation fails. */ public String installRemotePackage(String remoteFilePath, boolean reinstall) - throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, - IOException; + throws InstallException; /** * Removes a file from device. * * @param remoteFilePath path on device of file to remove - * @throws TimeoutException in case of timeout on the connection. - * @throws AdbCommandRejectedException if adb rejects the command - * @throws ShellCommandUnresponsiveException if the device didn't respond for long time when - * performing the action. - * @throws IOException if file removal failed + * @throws InstallException if the installation fails. */ - public void removeRemotePackage(String remoteFilePath) - throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, - IOException; + public void removeRemotePackage(String remoteFilePath) throws InstallException; /** * Uninstalls an package from the device. * * @param packageName the Android application package name to uninstall * @return a {@link String} with an error code, or <code>null</code> if success. - * @throws TimeoutException in case of timeout on the connection. - * @throws AdbCommandRejectedException if adb rejects the command - * @throws ShellCommandUnresponsiveException if the device didn't respond for long time when - * performing the action. - * @throws IOException + * @throws InstallException if the uninstallation fails. */ - public String uninstallPackage(String packageName) - throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, - IOException; + public String uninstallPackage(String packageName) throws InstallException; /** * Reboot the device. diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/InstallException.java b/ddms/libs/ddmlib/src/com/android/ddmlib/InstallException.java new file mode 100644 index 0000000..7aa718f --- /dev/null +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/InstallException.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 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.ddmlib; + +/** + * Thrown if installation or uninstallation of application fails. + */ +public class InstallException extends CanceledException { + private static final long serialVersionUID = 1L; + + public InstallException(Throwable cause) { + super(cause.getMessage(), cause); + } + + public InstallException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Returns true if the installation was canceled by user input. This can typically only + * happen in the sync phase. + */ + @Override + public boolean wasCanceled() { + Throwable cause = getCause(); + return cause instanceof SyncException && ((SyncException)cause).wasCanceled(); + } +} diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/ShellCommandUnresponsiveException.java b/ddms/libs/ddmlib/src/com/android/ddmlib/ShellCommandUnresponsiveException.java index 2dc5d3a..09823c4 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/ShellCommandUnresponsiveException.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/ShellCommandUnresponsiveException.java @@ -16,13 +16,12 @@ package com.android.ddmlib; -import java.io.IOException; /** * Exception thrown when a shell command executed on a device takes too long to send its output. * <p/>The command may not actually be unresponsive, it just has spent too much time not outputting * any thing to the console. */ -public class ShellCommandUnresponsiveException extends IOException { +public class ShellCommandUnresponsiveException extends Exception { private static final long serialVersionUID = 1L; } diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/SyncException.java b/ddms/libs/ddmlib/src/com/android/ddmlib/SyncException.java new file mode 100644 index 0000000..1e9b692 --- /dev/null +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/SyncException.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 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.ddmlib; + +import java.io.IOException; + +/** + * Exception thrown when a transfer using {@link SyncService} doesn't complete. + * <p/>This is different from an {@link IOException} because it's not the underlying connection + * that triggered the error, but the adb transfer protocol that didn't work somehow, or that the + * targets (local and/or remote) were wrong. + */ +public class SyncException extends CanceledException { + private static final long serialVersionUID = 1L; + + public enum SyncError { + /** canceled transfer */ + CANCELED("Operation was canceled by the user."), + /** Transfer error */ + TRANSFER_PROTOCOL_ERROR("Adb Transfer Protocol Error."), + /** unknown remote object during a pull */ + NO_REMOTE_OBJECT("Remote object doesn't exist!"), + /** Result code when attempting to pull multiple files into a file */ + TARGET_IS_FILE("Target object is a file."), + /** Result code when attempting to pull multiple into a directory that does not exist. */ + NO_DIR_TARGET("Target directory doesn't exist."), + /** wrong encoding on the remote path. */ + REMOTE_PATH_ENCODING("Remote Path encoding is not supported."), + /** remote path that is too long. */ + REMOTE_PATH_LENGTH("Remote path is too long."), + /** error while reading local file. */ + FILE_READ_ERROR("Reading local file failed!"), + /** attempting to push a directory. */ + LOCAL_IS_DIRECTORY("Local path is a directory."), + /** when the target path of a multi file push is a file. */ + REMOTE_IS_FILE("Remote path is a file."), + /** receiving too much data from the remove device at once */ + BUFFER_OVERRUN("Receiving too much data."); + + private final String mMessage; + + private SyncError(String message) { + mMessage = message; + } + + public String getMessage() { + return mMessage; + } + } + + private final SyncError mError; + + public SyncException(SyncError error) { + super(error.getMessage()); + mError = error; + } + + public SyncException(SyncError error, String message) { + super(message); + mError = error; + } + + public SyncException(SyncError error, Throwable cause) { + super(error.getMessage(), cause); + mError = error; + } + + public SyncError getErrorCode() { + return mError; + } + + /** + * Returns true if the sync was canceled by user input. + */ + @Override + public boolean wasCanceled() { + return mError == SyncError.CANCELED; + } +} diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java b/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java index d2b8af3..0303a03 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java @@ -18,6 +18,7 @@ package com.android.ddmlib; import com.android.ddmlib.AdbHelper.AdbResponse; import com.android.ddmlib.FileListingService.FileEntry; +import com.android.ddmlib.SyncException.SyncError; import com.android.ddmlib.utils.ArrayHelper; import java.io.File; @@ -78,69 +79,6 @@ public final class SyncService { private final static int SYNC_DATA_MAX = 64*1024; private final static int REMOTE_PATH_MAX_LENGTH = 1024; - /** Result code for transfer success. */ - public static final int RESULT_OK = 0; - /** Result code for canceled transfer */ - public static final int RESULT_CANCELED = 1; - /** Result code for unknown error */ - public static final int RESULT_UNKNOWN_ERROR = 2; - /** Result code for network connection error */ - public static final int RESULT_CONNECTION_ERROR = 3; - /** Result code for unknown remote object during a pull */ - public static final int RESULT_NO_REMOTE_OBJECT = 4; - /** Result code when attempting to pull multiple files into a file */ - public static final int RESULT_TARGET_IS_FILE = 5; - /** Result code when attempting to pull multiple into a directory that does not exist. */ - public static final int RESULT_NO_DIR_TARGET = 6; - /** Result code for wrong encoding on the remote path. */ - public static final int RESULT_REMOTE_PATH_ENCODING = 7; - /** Result code for remote path that is too long. */ - public static final int RESULT_REMOTE_PATH_LENGTH = 8; - /** Result code for error while writing local file. */ - public static final int RESULT_FILE_WRITE_ERROR = 9; - /** Result code for error while reading local file. */ - public static final int RESULT_FILE_READ_ERROR = 10; - /** Result code for attempting to push a file that does not exist. */ - public static final int RESULT_NO_LOCAL_FILE = 11; - /** Result code for attempting to push a directory. */ - public static final int RESULT_LOCAL_IS_DIRECTORY = 12; - /** Result code for when the target path of a multi file push is a file. */ - public static final int RESULT_REMOTE_IS_FILE = 13; - /** Result code for receiving too much data from the remove device at once */ - public static final int RESULT_BUFFER_OVERRUN = 14; - /** Result code for network connection timeout */ - public static final int RESULT_CONNECTION_TIMEOUT = 15; - - /** - * A file transfer result. - * <p/> - * This contains a code, and an optional string - */ - public static class SyncResult { - private int mCode; - private String mMessage; - SyncResult(int code, String message) { - mCode = code; - mMessage = message; - } - - SyncResult(int code, Exception e) { - this(code, e.getMessage()); - } - - SyncResult(int code) { - this(code, errorCodeToString(code)); - } - - public int getCode() { - return mCode; - } - - public String getMessage() { - return mMessage; - } - } - /** * Classes which implement this interface provide methods that deal * with displaying transfer progress. @@ -287,68 +225,30 @@ public final class SyncService { } /** - * Converts an error code into a non-localized string - * @param code the error code; - */ - private static String errorCodeToString(int code) { - switch (code) { - case RESULT_OK: - return "Success."; - case RESULT_CANCELED: - return "Tranfert canceled by the user."; - case RESULT_UNKNOWN_ERROR: - return "Unknown Error."; - case RESULT_CONNECTION_ERROR: - return "Adb Connection Error."; - case RESULT_NO_REMOTE_OBJECT: - return "Remote object doesn't exist!"; - case RESULT_TARGET_IS_FILE: - return "Target object is a file."; - case RESULT_NO_DIR_TARGET: - return "Target directory doesn't exist."; - case RESULT_REMOTE_PATH_ENCODING: - return "Remote Path encoding is not supported."; - case RESULT_REMOTE_PATH_LENGTH: - return "Remove path is too long."; - case RESULT_FILE_WRITE_ERROR: - return "Writing local file failed!"; - case RESULT_FILE_READ_ERROR: - return "Reading local file failed!"; - case RESULT_NO_LOCAL_FILE: - return "Local file doesn't exist."; - case RESULT_LOCAL_IS_DIRECTORY: - return "Local path is a directory."; - case RESULT_REMOTE_IS_FILE: - return "Remote path is a file."; - case RESULT_BUFFER_OVERRUN: - return "Receiving too much data."; - case RESULT_CONNECTION_TIMEOUT: - return "timeout"; - } - - throw new RuntimeException(); - } - - /** * Pulls file(s) or folder(s). * @param entries the remote item(s) to pull * @param localPath The local destination. If the entries count is > 1 or * if the unique entry is a folder, this should be a folder. * @param monitor The progress monitor. Cannot be null. - * @return a {@link SyncResult} object with a code and an optional message. + * @throws SyncException + * @throws FileNotFoundException if the file exists but is a directory, does not exist but + * cannot be created, or cannot be opened for any other reason. + * @throws IOException + * @throws TimeoutException * * @see FileListingService.FileEntry * @see #getNullProgressMonitor() */ - public SyncResult pull(FileEntry[] entries, String localPath, ISyncProgressMonitor monitor) { + public void pull(FileEntry[] entries, String localPath, ISyncProgressMonitor monitor) + throws SyncException, FileNotFoundException, IOException, TimeoutException { // first we check the destination is a directory and exists File f = new File(localPath); if (f.exists() == false) { - return new SyncResult(RESULT_NO_DIR_TARGET); + throw new SyncException(SyncError.NO_DIR_TARGET); } if (f.isDirectory() == false) { - return new SyncResult(RESULT_TARGET_IS_FILE); + throw new SyncException(SyncError.TARGET_IS_FILE); } // get a FileListingService object @@ -360,11 +260,9 @@ public final class SyncService { // start the monitor monitor.start(total); - SyncResult result = doPull(entries, localPath, fls, monitor); + doPull(entries, localPath, fls, monitor); monitor.stop(); - - return result; } /** @@ -372,20 +270,23 @@ public final class SyncService { * @param remote the remote file * @param localFilename The local destination. * @param monitor The progress monitor. Cannot be null. - * @return a {@link SyncResult} object with a code and an optional message. + * + * @throws SyncException + * @throws IOException + * @throws FileNotFoundException + * @throws TimeoutException * * @see FileListingService.FileEntry * @see #getNullProgressMonitor() */ - public SyncResult pullFile(FileEntry remote, String localFilename, - ISyncProgressMonitor monitor) { + public void pullFile(FileEntry remote, String localFilename, ISyncProgressMonitor monitor) + throws FileNotFoundException, IOException, SyncException, TimeoutException { int total = remote.getSizeValue(); monitor.start(total); - SyncResult result = doPullFile(remote.getFullPath(), localFilename, monitor); + doPullFile(remote.getFullPath(), localFilename, monitor); monitor.stop(); - return result; } /** @@ -396,19 +297,28 @@ public final class SyncService { * @param remoteFilepath the full path to the remote file * @param localFilename The local destination. * @param monitor The progress monitor. Cannot be null. - * @return a {@link SyncResult} object with a code and an optional message. + * + * @throws IOException in case of an IO exception. + * @throws TimeoutException in case of a timeout reading responses from the device. + * @throws SyncException in case of a sync exception. * * @see #getNullProgressMonitor() */ - public SyncResult pullFile(String remoteFilepath, String localFilename, - ISyncProgressMonitor monitor) { + public void pullFile(String remoteFilepath, String localFilename, + ISyncProgressMonitor monitor) throws TimeoutException, IOException, SyncException { + Integer mode = readMode(remoteFilepath); + if (mode == null) { + // attempts to download anyway + } else if (mode == 0) { + throw new SyncException(SyncError.NO_REMOTE_OBJECT); + } + monitor.start(0); //TODO: use the {@link FileListingService} to get the file size. - SyncResult result = doPullFile(remoteFilepath, localFilename, monitor); + doPullFile(remoteFilepath, localFilename, monitor); monitor.stop(); - return result; } /** @@ -416,11 +326,16 @@ public final class SyncService { * @param local An array of loca files to push * @param remote the remote {@link FileEntry} representing a directory. * @param monitor The progress monitor. Cannot be null. - * @return a {@link SyncResult} object with a code and an optional message. + * @throws SyncException + * @throws FileNotFoundException if the file exists but is a directory, does not exist but + * cannot be created, or cannot be opened for any other reason. + * @throws IOException + * @throws TimeoutException */ - public SyncResult push(String[] local, FileEntry remote, ISyncProgressMonitor monitor) { + public void push(String[] local, FileEntry remote, ISyncProgressMonitor monitor) + throws SyncException, FileNotFoundException, IOException, TimeoutException { if (remote.isDirectory() == false) { - return new SyncResult(RESULT_REMOTE_IS_FILE); + throw new SyncException(SyncError.REMOTE_IS_FILE); } // make a list of File from the list of String @@ -435,11 +350,9 @@ public final class SyncService { monitor.start(total); - SyncResult result = doPush(fileArray, remote.getFullPath(), monitor); + doPush(fileArray, remote.getFullPath(), monitor); monitor.stop(); - - return result; } /** @@ -447,25 +360,30 @@ public final class SyncService { * @param local the local filepath. * @param remote The remote filepath. * @param monitor The progress monitor. Cannot be null. - * @return a {@link SyncResult} object with a code and an optional message. + * + * @throws SyncException + * @throws FileNotFoundException if the file exists but is a directory, does not exist but + * cannot be created, or cannot be opened for any other reason. + * @throws IOException + * @throws TimeoutException + * */ - public SyncResult pushFile(String local, String remote, ISyncProgressMonitor monitor) { + public void pushFile(String local, String remote, ISyncProgressMonitor monitor) + throws SyncException, FileNotFoundException, IOException, TimeoutException { File f = new File(local); if (f.exists() == false) { - return new SyncResult(RESULT_NO_LOCAL_FILE); + throw new FileNotFoundException(); } if (f.isDirectory()) { - return new SyncResult(RESULT_LOCAL_IS_DIRECTORY); + throw new SyncException(SyncError.LOCAL_IS_DIRECTORY); } monitor.start((int)f.length()); - SyncResult result = doPushFile(local, remote, monitor); + doPushFile(local, remote, monitor); monitor.stop(); - - return result; } /** @@ -520,16 +438,22 @@ public final class SyncService { * @param localPath the localpath to a directory * @param fileListingService a FileListingService object to browse through remote directories. * @param monitor the progress monitor. Must be started already. - * @return a {@link SyncResult} object with a code and an optional message. + * + * @throws FileNotFoundException if the file exists but is a directory, does not exist but + * cannot be created, or cannot be opened for any other reason. + * @throws IOException + * @throws SyncException + * @throws TimeoutException */ - private SyncResult doPull(FileEntry[] entries, String localPath, + private void doPull(FileEntry[] entries, String localPath, FileListingService fileListingService, - ISyncProgressMonitor monitor) { + ISyncProgressMonitor monitor) throws SyncException, FileNotFoundException, IOException, + TimeoutException { for (FileEntry e : entries) { // check if we're cancelled if (monitor.isCanceled() == true) { - return new SyncResult(RESULT_CANCELED); + throw new SyncException(SyncError.CANCELED); } // get type (we only pull directory and files for now) @@ -545,22 +469,14 @@ public final class SyncService { // then recursively call the content. Since we did a ls command // to get the number of files, we can use the cache FileEntry[] children = fileListingService.getChildren(e, true, null); - SyncResult result = doPull(children, dest, fileListingService, monitor); - if (result.mCode != RESULT_OK) { - return result; - } + doPull(children, dest, fileListingService, monitor); monitor.advance(1); } else if (type == FileListingService.TYPE_FILE) { monitor.startSubTask(e.getFullPath()); String dest = localPath + File.separator + e.getName(); - SyncResult result = doPullFile(e.getFullPath(), dest, monitor); - if (result.mCode != RESULT_OK) { - return result; - } + doPullFile(e.getFullPath(), dest, monitor); } } - - return new SyncResult(RESULT_OK); } /** @@ -568,10 +484,15 @@ public final class SyncService { * @param remotePath the remote file (length max is 1024) * @param localPath the local destination * @param monitor the monitor. The monitor must be started already. - * @return a {@link SyncResult} object with a code and an optional message. + * @throws FileNotFoundException if the file exists but is a directory, does not exist but + * cannot be created, or cannot be opened for any other reason. + * @throws IOException + * @throws SyncException + * @throws TimeoutException */ - private SyncResult doPullFile(String remotePath, String localPath, - ISyncProgressMonitor monitor) { + private void doPullFile(String remotePath, String localPath, + ISyncProgressMonitor monitor) throws FileNotFoundException, IOException, SyncException, + TimeoutException { byte[] msg = null; byte[] pullResult = new byte[8]; @@ -581,7 +502,7 @@ public final class SyncService { byte[] remotePathContent = remotePath.getBytes(AdbHelper.DEFAULT_ENCODING); if (remotePathContent.length > REMOTE_PATH_MAX_LENGTH) { - return new SyncResult(RESULT_REMOTE_PATH_LENGTH); + throw new SyncException(SyncError.REMOTE_PATH_LENGTH); } // create the full request message @@ -597,14 +518,11 @@ public final class SyncService { // check we have the proper data back if (checkResult(pullResult, ID_DATA) == false && checkResult(pullResult, ID_DONE) == false) { - return new SyncResult(RESULT_CONNECTION_ERROR); + throw new SyncException(SyncError.TRANSFER_PROTOCOL_ERROR, + readErrorMessage(pullResult, timeOut)); } } catch (UnsupportedEncodingException e) { - return new SyncResult(RESULT_REMOTE_PATH_ENCODING, e); - } catch (TimeoutException e) { - return new SyncResult(RESULT_CONNECTION_TIMEOUT, e); - } catch (IOException e) { - return new SyncResult(RESULT_CONNECTION_ERROR, e); + throw new SyncException(SyncError.REMOTE_PATH_ENCODING, e); } // access the destination file @@ -613,11 +531,7 @@ public final class SyncService { // create the stream to write in the file. We use a new try/catch block to differentiate // between file and network io exceptions. FileOutputStream fos = null; - try { - fos = new FileOutputStream(f); - } catch (FileNotFoundException e) { - return new SyncResult(RESULT_FILE_WRITE_ERROR, e); - } + fos = new FileOutputStream(f); // the buffer to read the data byte[] data = new byte[SYNC_DATA_MAX]; @@ -626,7 +540,7 @@ public final class SyncService { while (true) { // check if we're cancelled if (monitor.isCanceled() == true) { - return new SyncResult(RESULT_CANCELED); + throw new SyncException(SyncError.CANCELED); } // if we're done, we stop the loop @@ -635,43 +549,29 @@ public final class SyncService { } if (checkResult(pullResult, ID_DATA) == false) { // hmm there's an error - return new SyncResult(RESULT_CONNECTION_ERROR); + throw new SyncException(SyncError.TRANSFER_PROTOCOL_ERROR, + readErrorMessage(pullResult, timeOut)); } int length = ArrayHelper.swap32bitFromArray(pullResult, 4); if (length > SYNC_DATA_MAX) { // buffer overrun! // error and exit - return new SyncResult(RESULT_BUFFER_OVERRUN); + throw new SyncException(SyncError.BUFFER_OVERRUN); } - try { - // now read the length we received - AdbHelper.read(mChannel, data, length, timeOut); + // now read the length we received + AdbHelper.read(mChannel, data, length, timeOut); - // get the header for the next packet. - AdbHelper.read(mChannel, pullResult, -1, timeOut); - } catch (TimeoutException e) { - return new SyncResult(RESULT_CONNECTION_TIMEOUT, e); - } catch (IOException e) { - return new SyncResult(RESULT_CONNECTION_ERROR, e); - } + // get the header for the next packet. + AdbHelper.read(mChannel, pullResult, -1, timeOut); // write the content in the file - try { - fos.write(data, 0, length); - } catch (IOException e) { - return new SyncResult(RESULT_FILE_WRITE_ERROR, e); - } + fos.write(data, 0, length); monitor.advance(length); } - try { - fos.flush(); - } catch (IOException e) { - return new SyncResult(RESULT_FILE_WRITE_ERROR, e); - } - return new SyncResult(RESULT_OK); + fos.flush(); } @@ -680,39 +580,36 @@ public final class SyncService { * @param fileArray * @param remotePath * @param monitor - * @return a {@link SyncResult} object with a code and an optional message. + * + * @throws SyncException + * @throws FileNotFoundException if the file exists but is a directory, does not exist but + * cannot be created, or cannot be opened for any other reason. + * @throws IOException + * @throws TimeoutException */ - private SyncResult doPush(File[] fileArray, String remotePath, ISyncProgressMonitor monitor) { + private void doPush(File[] fileArray, String remotePath, ISyncProgressMonitor monitor) + throws SyncException, FileNotFoundException, IOException, TimeoutException { for (File f : fileArray) { // check if we're canceled if (monitor.isCanceled() == true) { - return new SyncResult(RESULT_CANCELED); + throw new SyncException(SyncError.CANCELED); } if (f.exists()) { if (f.isDirectory()) { // append the name of the directory to the remote path String dest = remotePath + "/" + f.getName(); // $NON-NLS-1S monitor.startSubTask(dest); - SyncResult result = doPush(f.listFiles(), dest, monitor); - - if (result.mCode != RESULT_OK) { - return result; - } + doPush(f.listFiles(), dest, monitor); monitor.advance(1); } else if (f.isFile()) { // append the name of the file to the remote path String remoteFile = remotePath + "/" + f.getName(); // $NON-NLS-1S monitor.startSubTask(remoteFile); - SyncResult result = doPushFile(f.getAbsolutePath(), remoteFile, monitor); - if (result.mCode != RESULT_OK) { - return result; - } + doPushFile(f.getAbsolutePath(), remoteFile, monitor); } } } - - return new SyncResult(RESULT_OK); } /** @@ -720,10 +617,16 @@ public final class SyncService { * @param localPath the local file to push * @param remotePath the remote file (length max is 1024) * @param monitor the monitor. The monitor must be started already. - * @return a {@link SyncResult} object with a code and an optional message. + * + * @throws SyncException + * @throws FileNotFoundException if the file exists but is a directory, does not exist but + * cannot be created, or cannot be opened for any other reason. + * @throws IOException + * @throws TimeoutException */ - private SyncResult doPushFile(String localPath, String remotePath, - ISyncProgressMonitor monitor) { + private void doPushFile(String localPath, String remotePath, + ISyncProgressMonitor monitor) throws SyncException, FileNotFoundException, IOException, + TimeoutException { FileInputStream fis = null; byte[] msg; @@ -733,36 +636,23 @@ public final class SyncService { byte[] remotePathContent = remotePath.getBytes(AdbHelper.DEFAULT_ENCODING); if (remotePathContent.length > REMOTE_PATH_MAX_LENGTH) { - return new SyncResult(RESULT_REMOTE_PATH_LENGTH); + throw new SyncException(SyncError.REMOTE_PATH_LENGTH); } File f = new File(localPath); - // this shouldn't happen but still... - if (f.exists() == false) { - return new SyncResult(RESULT_NO_LOCAL_FILE); - } - // create the stream to read the file fis = new FileInputStream(f); // create the header for the action msg = createSendFileReq(ID_SEND, remotePathContent, 0644); } catch (UnsupportedEncodingException e) { - return new SyncResult(RESULT_REMOTE_PATH_ENCODING, e); - } catch (FileNotFoundException e) { - return new SyncResult(RESULT_FILE_READ_ERROR, e); + throw new SyncException(SyncError.REMOTE_PATH_ENCODING, e); } // and send it. We use a custom try/catch block to make the difference between // file and network IO exceptions. - try { - AdbHelper.write(mChannel, msg, -1, timeOut); - } catch (TimeoutException e) { - return new SyncResult(RESULT_CONNECTION_TIMEOUT, e); - } catch (IOException e) { - return new SyncResult(RESULT_CONNECTION_ERROR, e); - } + AdbHelper.write(mChannel, msg, -1, timeOut); // create the buffer used to read. // we read max SYNC_DATA_MAX, but we need 2 4 bytes at the beginning. @@ -775,16 +665,11 @@ public final class SyncService { while (true) { // check if we're canceled if (monitor.isCanceled() == true) { - return new SyncResult(RESULT_CANCELED); + throw new SyncException(SyncError.CANCELED); } // read up to SYNC_DATA_MAX - int readCount = 0; - try { - readCount = fis.read(mBuffer, 8, SYNC_DATA_MAX); - } catch (IOException e) { - return new SyncResult(RESULT_FILE_READ_ERROR, e); - } + int readCount = fis.read(mBuffer, 8, SYNC_DATA_MAX); if (readCount == -1) { // we reached the end of the file @@ -796,65 +681,62 @@ public final class SyncService { ArrayHelper.swap32bitsToArray(readCount, mBuffer, 4); // now write it - try { - AdbHelper.write(mChannel, mBuffer, readCount+8, timeOut); - } catch (TimeoutException e) { - return new SyncResult(RESULT_CONNECTION_TIMEOUT, e); - } catch (IOException e) { - return new SyncResult(RESULT_CONNECTION_ERROR, e); - } + AdbHelper.write(mChannel, mBuffer, readCount+8, timeOut); // and advance the monitor monitor.advance(readCount); } // close the local file - try { - fis.close(); - } catch (IOException e) { - return new SyncResult(RESULT_FILE_READ_ERROR, e); - } + fis.close(); - try { - // create the DONE message - long time = System.currentTimeMillis() / 1000; - msg = createReq(ID_DONE, (int)time); + // create the DONE message + long time = System.currentTimeMillis() / 1000; + msg = createReq(ID_DONE, (int)time); - // and send it. - AdbHelper.write(mChannel, msg, -1, timeOut); + // and send it. + AdbHelper.write(mChannel, msg, -1, timeOut); - // read the result, in a byte array containing 2 ints - // (id, size) - byte[] result = new byte[8]; - AdbHelper.read(mChannel, result, -1 /* full length */, timeOut); + // read the result, in a byte array containing 2 ints + // (id, size) + byte[] result = new byte[8]; + AdbHelper.read(mChannel, result, -1 /* full length */, timeOut); + + if (checkResult(result, ID_OKAY) == false) { + throw new SyncException(SyncError.TRANSFER_PROTOCOL_ERROR, + readErrorMessage(result, timeOut)); + } + } - if (checkResult(result, ID_OKAY) == false) { - if (checkResult(result, ID_FAIL)) { - // read some error message... - int len = ArrayHelper.swap32bitFromArray(result, 4); + /** + * Reads an error message from the opened {@link #mChannel}. + * @param result the current adb result. Must contain both FAIL and the length of the message. + * @param timeOut + * @return + * @throws TimeoutException + * @throws IOException + */ + private String readErrorMessage(byte[] result, final int timeOut) throws TimeoutException, + IOException { + if (checkResult(result, ID_FAIL)) { + int len = ArrayHelper.swap32bitFromArray(result, 4); - AdbHelper.read(mChannel, mBuffer, len, timeOut); + if (len > 0) { + AdbHelper.read(mChannel, mBuffer, len, timeOut); - // output the result? - String message = new String(mBuffer, 0, len); - Log.e("ddms", "transfer error: " + message); - return new SyncResult(RESULT_UNKNOWN_ERROR, message); - } + String message = new String(mBuffer, 0, len); + Log.e("ddms", "transfer error: " + message); - return new SyncResult(RESULT_UNKNOWN_ERROR); + return message; } - } catch (TimeoutException e) { - return new SyncResult(RESULT_CONNECTION_TIMEOUT, e); - } catch (IOException e) { - return new SyncResult(RESULT_CONNECTION_ERROR, e); } - return new SyncResult(RESULT_OK); + return null; } /** * Returns the mode of the remote file. * @param path the remote file - * @return and Integer containing the mode if all went well or null + * @return an Integer containing the mode if all went well or null * otherwise * @throws IOException * @throws TimeoutException diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/TimeoutException.java b/ddms/libs/ddmlib/src/com/android/ddmlib/TimeoutException.java index 25be2f9..78f5db7 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/TimeoutException.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/TimeoutException.java @@ -16,12 +16,11 @@ package com.android.ddmlib; -import java.io.IOException; /** * Exception thrown when a connection to Adb failed with a timeout. * */ -public class TimeoutException extends IOException { +public class TimeoutException extends Exception { private static final long serialVersionUID = 1L; } diff --git a/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java b/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java index 9d4e77b..343efdc 100644 --- a/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java +++ b/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java @@ -16,12 +16,16 @@ package com.android.ddmlib.testrunner; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.Client; import com.android.ddmlib.FileListingService; import com.android.ddmlib.IDevice; import com.android.ddmlib.IShellOutputReceiver; +import com.android.ddmlib.InstallException; import com.android.ddmlib.RawImage; +import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.SyncService; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.log.LogReceiver; import java.io.IOException; @@ -51,8 +55,12 @@ public class RemoteAndroidTestRunnerTest extends TestCase { /** * Test the basic case building of the instrumentation runner command with no arguments. + * @throws ShellCommandUnresponsiveException + * @throws AdbCommandRejectedException + * @throws TimeoutException */ - public void testRun() throws IOException { + public void testRun() throws IOException, TimeoutException, AdbCommandRejectedException, + ShellCommandUnresponsiveException { mRunner.run(new EmptyListener()); assertStringsEquals(String.format("am instrument -w -r %s/%s", TEST_PACKAGE, TEST_RUNNER), mMockDevice.getLastShellCommand()); @@ -60,8 +68,12 @@ public class RemoteAndroidTestRunnerTest extends TestCase { /** * Test the building of the instrumentation runner command with log set. + * @throws ShellCommandUnresponsiveException + * @throws AdbCommandRejectedException + * @throws TimeoutException */ - public void testRunWithLog() throws IOException { + public void testRunWithLog() throws IOException, TimeoutException, AdbCommandRejectedException, + ShellCommandUnresponsiveException { mRunner.setLogOnly(true); mRunner.run(new EmptyListener()); assertStringsEquals(String.format("am instrument -w -r -e log true %s/%s", TEST_PACKAGE, @@ -70,8 +82,12 @@ public class RemoteAndroidTestRunnerTest extends TestCase { /** * Test the building of the instrumentation runner command with method set. + * @throws ShellCommandUnresponsiveException + * @throws AdbCommandRejectedException + * @throws TimeoutException */ - public void testRunWithMethod() throws IOException { + public void testRunWithMethod() throws IOException, TimeoutException, + AdbCommandRejectedException, ShellCommandUnresponsiveException { final String className = "FooTest"; final String testName = "fooTest"; mRunner.setMethodName(className, testName); @@ -82,8 +98,12 @@ public class RemoteAndroidTestRunnerTest extends TestCase { /** * Test the building of the instrumentation runner command with test package set. + * @throws ShellCommandUnresponsiveException + * @throws AdbCommandRejectedException + * @throws TimeoutException */ - public void testRunWithPackage() throws IOException { + public void testRunWithPackage() throws IOException, TimeoutException, + AdbCommandRejectedException, ShellCommandUnresponsiveException { final String packageName = "foo.test"; mRunner.setTestPackageName(packageName); mRunner.run(new EmptyListener()); @@ -93,8 +113,12 @@ public class RemoteAndroidTestRunnerTest extends TestCase { /** * Test the building of the instrumentation runner command with extra argument added. + * @throws ShellCommandUnresponsiveException + * @throws AdbCommandRejectedException + * @throws TimeoutException */ - public void testRunWithAddInstrumentationArg() throws IOException { + public void testRunWithAddInstrumentationArg() throws IOException, TimeoutException, + AdbCommandRejectedException, ShellCommandUnresponsiveException { final String extraArgName = "blah"; final String extraArgValue = "blahValue"; mRunner.addInstrumentationArg(extraArgName, extraArgValue); @@ -103,7 +127,6 @@ public class RemoteAndroidTestRunnerTest extends TestCase { extraArgValue, TEST_PACKAGE, TEST_RUNNER), mMockDevice.getLastShellCommand()); } - /** * Assert two strings are equal ignoring whitespace. */ @@ -233,21 +256,21 @@ public class RemoteAndroidTestRunnerTest extends TestCase { } public String installPackage(String packageFilePath, boolean reinstall) - throws IOException { + throws InstallException { throw new UnsupportedOperationException(); } - public String uninstallPackage(String packageName) throws IOException { + public String uninstallPackage(String packageName) throws InstallException { throw new UnsupportedOperationException(); } - public String installRemotePackage(String remoteFilePath, - boolean reinstall) throws IOException { + public String installRemotePackage(String remoteFilePath, boolean reinstall) + throws InstallException { throw new UnsupportedOperationException(); } public void removeRemotePackage(String remoteFilePath) - throws IOException { + throws InstallException { throw new UnsupportedOperationException(); } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java index 99bca99..a0e9cbd 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/ScreenShotDialog.java @@ -16,9 +16,11 @@ package com.android.ddmuilib; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; import com.android.ddmlib.RawImage; +import com.android.ddmlib.TimeoutException; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; @@ -265,6 +267,12 @@ public class ScreenShotDialog extends Dialog { catch (IOException ioe) { Log.w("ddms", "Unable to get frame buffer: " + ioe.getMessage()); return null; + } catch (TimeoutException e) { + Log.w("ddms", "Unable to get frame buffer: timeout "); + return null; + } catch (AdbCommandRejectedException e) { + Log.w("ddms", "Unable to get frame buffer: " + e.getMessage()); + return null; } } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressHelper.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressHelper.java new file mode 100644 index 0000000..23b749e --- /dev/null +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SyncProgressHelper.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010 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.ddmuilib; + +import com.android.ddmlib.SyncException; +import com.android.ddmlib.SyncService; +import com.android.ddmlib.TimeoutException; +import com.android.ddmlib.SyncService.ISyncProgressMonitor; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.swt.widgets.Shell; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +/** + * Helper class to run a Sync in a {@link ProgressMonitorDialog}. + */ +public class SyncProgressHelper { + + /** + * a runnable class run with an {@link ISyncProgressMonitor}. + */ + public interface SyncRunnable { + /** Runs the sync action */ + void run(ISyncProgressMonitor monitor) throws SyncException, IOException, TimeoutException; + /** close the {@link SyncService} */ + void close(); + } + + /** + * Runs a {@link SyncRunnable} in a {@link ProgressMonitorDialog}. + * @param runnable The {@link SyncRunnable} to run. + * @param progressMessage the message to display in the progress dialog + * @param parentShell the parent shell for the progress dialog. + * + * @throws InvocationTargetException + * @throws InterruptedException + * @throws SyncException if an error happens during the push of the package on the device. + * @throws IOException + * @throws TimeoutException + */ + public static void run(final SyncRunnable runnable, final String progressMessage, + final Shell parentShell) + throws InvocationTargetException, InterruptedException, SyncException, IOException, + TimeoutException { + + final Exception[] result = new Exception[1]; + new ProgressMonitorDialog(parentShell).run(true, true, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) { + try { + runnable.run(new SyncProgressMonitor(monitor, progressMessage)); + } catch (Exception e) { + result[0] = e; + } finally { + runnable.close(); + } + } + }); + + if (result[0] instanceof SyncException) { + SyncException se = (SyncException)result[0]; + if (se.wasCanceled()) { + // no need to throw this + return; + } + throw se; + } + + // just do some casting so that the method declaration matches what's thrown. + if (result[0] instanceof TimeoutException) { + throw (TimeoutException)result[0]; + } + + if (result[0] instanceof IOException) { + throw (IOException)result[0]; + } + + if (result[0] instanceof RuntimeException) { + throw (RuntimeException)result[0]; + } + } +} diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java index 8ef237c..6727fcb 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java @@ -16,9 +16,12 @@ package com.android.ddmuilib; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.Client; import com.android.ddmlib.IShellOutputReceiver; import com.android.ddmlib.Log; +import com.android.ddmlib.ShellCommandUnresponsiveException; +import com.android.ddmlib.TimeoutException; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; @@ -157,6 +160,12 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver { DUMP_COMMAND[mMode], this); } catch (IOException e) { Log.e("DDMS", e); + } catch (TimeoutException e) { + Log.e("DDMS", e); + } catch (AdbCommandRejectedException e) { + Log.e("DDMS", e); + } catch (ShellCommandUnresponsiveException e) { + Log.e("DDMS", e); } } @@ -481,7 +490,7 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver { Pattern valuePattern = Pattern.compile("(\\d+) kB"); long total = 0; long other = 0; - mLabel.setText("PSS in kB"); + mLabel.setText("PSS in kB"); // Scan meminfo while (true) { diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java index 77a5e57..a44bd1a 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/explorer/DeviceExplorer.java @@ -16,24 +16,25 @@ package com.android.ddmuilib.explorer; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.FileListingService; import com.android.ddmlib.IDevice; import com.android.ddmlib.IShellOutputReceiver; +import com.android.ddmlib.ShellCommandUnresponsiveException; +import com.android.ddmlib.SyncException; import com.android.ddmlib.SyncService; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.FileListingService.FileEntry; import com.android.ddmlib.SyncService.ISyncProgressMonitor; -import com.android.ddmlib.SyncService.SyncResult; import com.android.ddmuilib.DdmUiPreferences; import com.android.ddmuilib.ImageLoader; import com.android.ddmuilib.Panel; -import com.android.ddmuilib.SyncProgressMonitor; +import com.android.ddmuilib.SyncProgressHelper; import com.android.ddmuilib.TableHelper; +import com.android.ddmuilib.SyncProgressHelper.SyncRunnable; import com.android.ddmuilib.actions.ICommonAction; import com.android.ddmuilib.console.DdmConsole; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jface.dialogs.ProgressMonitorDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; @@ -62,7 +63,6 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -407,19 +407,8 @@ public class DeviceExplorer extends Panel { SyncService sync = mCurrentDevice.getSyncService(); if (sync != null) { ISyncProgressMonitor monitor = SyncService.getNullProgressMonitor(); - SyncResult result = sync.pullFile(keyEntry, keyFile.getAbsolutePath(), monitor); - if (result.getCode() != SyncService.RESULT_OK) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull %1$s: %2$s", keyEntry.getName(), result.getMessage())); - return; - } - - result = sync.pullFile(dataEntry, dataFile.getAbsolutePath(), monitor); - if (result.getCode() != SyncService.RESULT_OK) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull %1$s: %2$s", dataEntry.getName(), result.getMessage())); - return; - } + sync.pullFile(keyEntry, keyFile.getAbsolutePath(), monitor); + sync.pullFile(dataEntry, dataFile.getAbsolutePath(), monitor); // now that we have the file, we need to launch traceview String[] command = new String[2]; @@ -464,6 +453,18 @@ public class DeviceExplorer extends Panel { DdmConsole.printErrorToConsole(String.format( "Failed to pull %1$s: %2$s", keyEntry.getName(), e.getMessage())); return; + } catch (SyncException e) { + if (e.wasCanceled() == false) { + DdmConsole.printErrorToConsole(String.format( + "Failed to pull %1$s: %2$s", keyEntry.getName(), e.getMessage())); + return; + } + } catch (TimeoutException e) { + DdmConsole.printErrorToConsole(String.format( + "Failed to pull %1$s: timeout", keyEntry.getName())); + } catch (AdbCommandRejectedException e) { + DdmConsole.printErrorToConsole(String.format( + "Failed to pull %1$s: %2$s", keyEntry.getName(), e.getMessage())); } } @@ -602,6 +603,15 @@ public class DeviceExplorer extends Panel { } catch (IOException e) { // adb failed somehow, we do nothing. We should be displaying the error from the output // of the shell command. + } catch (TimeoutException e) { + // adb failed somehow, we do nothing. We should be displaying the error from the output + // of the shell command. + } catch (AdbCommandRejectedException e) { + // adb failed somehow, we do nothing. We should be displaying the error from the output + // of the shell command. + } catch (ShellCommandUnresponsiveException e) { + // adb failed somehow, we do nothing. We should be displaying the error from the output + // of the shell command. } } @@ -672,24 +682,21 @@ public class DeviceExplorer extends Panel { final FileEntry[] entryArray = entries.toArray( new FileEntry[entries.size()]); - // get a progressdialog - new ProgressMonitorDialog(mParent.getShell()).run(true, true, - new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) - throws InvocationTargetException, - InterruptedException { - // create a monitor wrapper around the jface monitor - SyncResult result = sync.pull(entryArray, localDirectory, - new SyncProgressMonitor(monitor, - "Pulling file(s) from the device")); - - if (result.getCode() != SyncService.RESULT_OK) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull selection: %1$s", result.getMessage())); - } + SyncProgressHelper.run(new SyncRunnable() { + public void run(ISyncProgressMonitor monitor) + throws SyncException, IOException, TimeoutException { + sync.pull(entryArray, localDirectory, monitor); + } + + public void close() { sync.close(); } - }); + }, "Pulling file(s) from the device", mParent.getShell()); + } + } catch (SyncException e) { + if (e.wasCanceled() == false) { + DdmConsole.printErrorToConsole(String.format( + "Failed to pull selection: %1$s", e.getMessage())); } } catch (Exception e) { DdmConsole.printErrorToConsole( "Failed to pull selection"); @@ -706,22 +713,22 @@ public class DeviceExplorer extends Panel { try { final SyncService sync = mCurrentDevice.getSyncService(); if (sync != null) { - new ProgressMonitorDialog(mParent.getShell()).run(true, true, - new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) - throws InvocationTargetException, - InterruptedException { - SyncResult result = sync.pullFile(remote, local, new SyncProgressMonitor( - monitor, String.format("Pulling %1$s from the device", - remote.getName()))); - if (result.getCode() != SyncService.RESULT_OK) { - DdmConsole.printErrorToConsole(String.format( - "Failed to pull %1$s: %2$s", remote, result.getMessage())); + SyncProgressHelper.run(new SyncRunnable() { + public void run(ISyncProgressMonitor monitor) + throws SyncException, IOException, TimeoutException { + sync.pullFile(remote, local, monitor); } - sync.close(); - } - }); + public void close() { + sync.close(); + } + }, String.format("Pulling %1$s from the device", remote.getName()), + mParent.getShell()); + } + } catch (SyncException e) { + if (e.wasCanceled() == false) { + DdmConsole.printErrorToConsole(String.format( + "Failed to pull selection: %1$s", e.getMessage())); } } catch (Exception e) { DdmConsole.printErrorToConsole( "Failed to pull selection"); @@ -738,22 +745,21 @@ public class DeviceExplorer extends Panel { try { final SyncService sync = mCurrentDevice.getSyncService(); if (sync != null) { - new ProgressMonitorDialog(mParent.getShell()).run(true, true, - new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) - throws InvocationTargetException, - InterruptedException { - SyncResult result = sync.push(localFiles, remoteDirectory, - new SyncProgressMonitor(monitor, - "Pushing file(s) to the device")); - if (result.getCode() != SyncService.RESULT_OK) { - DdmConsole.printErrorToConsole(String.format( - "Failed to push the items: %1$s", result.getMessage())); + SyncProgressHelper.run(new SyncRunnable() { + public void run(ISyncProgressMonitor monitor) + throws SyncException, IOException, TimeoutException { + sync.push(localFiles, remoteDirectory, monitor); } - sync.close(); - } - }); + public void close() { + sync.close(); + } + }, "Pushing file(s) to the device", mParent.getShell()); + } + } catch (SyncException e) { + if (e.wasCanceled() == false) { + DdmConsole.printErrorToConsole(String.format( + "Failed to push selection: %1$s", e.getMessage())); } } catch (Exception e) { DdmConsole.printErrorToConsole("Failed to push the items"); @@ -770,29 +776,27 @@ public class DeviceExplorer extends Panel { try { final SyncService sync = mCurrentDevice.getSyncService(); if (sync != null) { - new ProgressMonitorDialog(mParent.getShell()).run(true, true, - new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) - throws InvocationTargetException, - InterruptedException { - // get the file name - String[] segs = local.split(Pattern.quote(File.separator)); - String name = segs[segs.length-1]; - String remoteFile = remoteDirectory + FileListingService.FILE_SEPARATOR - + name; - - SyncResult result = sync.pushFile(local, remoteFile, - new SyncProgressMonitor(monitor, - String.format("Pushing %1$s to the device.", name))); - if (result.getCode() != SyncService.RESULT_OK) { - DdmConsole.printErrorToConsole(String.format( - "Failed to push %1$s on %2$s: %3$s", - name, mCurrentDevice.getSerialNumber(), result.getMessage())); + // get the file name + String[] segs = local.split(Pattern.quote(File.separator)); + String name = segs[segs.length-1]; + final String remoteFile = remoteDirectory + FileListingService.FILE_SEPARATOR + + name; + + SyncProgressHelper.run(new SyncRunnable() { + public void run(ISyncProgressMonitor monitor) + throws SyncException, IOException, TimeoutException { + sync.pushFile(local, remoteFile, monitor); } - sync.close(); - } - }); + public void close() { + sync.close(); + } + }, String.format("Pushing %1$s to the device.", name), mParent.getShell()); + } + } catch (SyncException e) { + if (e.wasCanceled() == false) { + DdmConsole.printErrorToConsole(String.format( + "Failed to push selection: %1$s", e.getMessage())); } } catch (Exception e) { DdmConsole.printErrorToConsole("Failed to push the item(s)."); diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java index 6c086db..7ecf7b9 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/BaseFileHandler.java @@ -16,16 +16,16 @@ package com.android.ddmuilib.handler; +import com.android.ddmlib.SyncException; import com.android.ddmlib.SyncService; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.ClientData.IHprofDumpHandler; import com.android.ddmlib.ClientData.IMethodProfilingHandler; -import com.android.ddmlib.SyncService.SyncResult; -import com.android.ddmuilib.SyncProgressMonitor; +import com.android.ddmlib.SyncService.ISyncProgressMonitor; +import com.android.ddmuilib.SyncProgressHelper; +import com.android.ddmuilib.SyncProgressHelper.SyncRunnable; -import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.dialogs.ProgressMonitorDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; @@ -63,21 +63,32 @@ public abstract class BaseFileHandler { * didn't happen (canceled by the user). * @throws InvocationTargetException * @throws InterruptedException + * @throws SyncException if an error happens during the push of the package on the device. + * @throws IOException */ - protected SyncResult promptAndPull(SyncService sync, - String localFileName, String remoteFilePath, String title) - throws InvocationTargetException, InterruptedException { + protected void promptAndPull(final SyncService sync, + String localFileName, final String remoteFilePath, String title) + throws InvocationTargetException, InterruptedException, SyncException, TimeoutException, + IOException { FileDialog fileDialog = new FileDialog(mParentShell, SWT.SAVE); fileDialog.setText(title); fileDialog.setFileName(localFileName); - String localFilePath = fileDialog.open(); + final String localFilePath = fileDialog.open(); if (localFilePath != null) { - return pull(sync, localFilePath, remoteFilePath); - } + SyncProgressHelper.run(new SyncRunnable() { + public void run(ISyncProgressMonitor monitor) throws SyncException, IOException, + TimeoutException { + sync.pullFile(remoteFilePath, localFilePath, monitor); + } - return null; + public void close() { + sync.close(); + } + }, + String.format("Pulling %1$s from the device", remoteFilePath), mParentShell); + } } /** @@ -112,35 +123,6 @@ public abstract class BaseFileHandler { } /** - * Pulls a file off of a device. This displays a {@link ProgressMonitorDialog} and therefore - * must be run from the UI Thread. - * @param sync the {@link SyncService} to use to pull the file. - * @param localFilePath the path of the local file to create - * @param remoteFilePath the path of the remote file to pull - * @return the result of the sync as an instance of {@link SyncResult} - * @throws InvocationTargetException - * @throws InterruptedException - */ - protected SyncResult pull(final SyncService sync, final String localFilePath, - final String remoteFilePath) - throws InvocationTargetException, InterruptedException { - final SyncResult[] res = new SyncResult[1]; - new ProgressMonitorDialog(mParentShell).run(true, true, new IRunnableWithProgress() { - public void run(IProgressMonitor monitor) { - try { - res[0] = sync.pullFile(remoteFilePath, localFilePath, - new SyncProgressMonitor(monitor, String.format( - "Pulling %1$s from the device", remoteFilePath))); - } finally { - sync.close(); - } - } - }); - - return res[0]; - } - - /** * Display an error message. * <p/>This will call about to {@link Display} to run this in an async {@link Runnable} in the * UI Thread. This is safe to be called from a non-UI Thread. diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java index b1d7f2a..f1d0135 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/handler/MethodProfilingHandler.java @@ -19,10 +19,14 @@ package com.android.ddmuilib.handler; import com.android.ddmlib.Client; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; +import com.android.ddmlib.SyncException; import com.android.ddmlib.SyncService; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.ClientData.IMethodProfilingHandler; -import com.android.ddmlib.SyncService.SyncResult; +import com.android.ddmlib.SyncService.ISyncProgressMonitor; import com.android.ddmuilib.DdmUiPreferences; +import com.android.ddmuilib.SyncProgressHelper; +import com.android.ddmuilib.SyncProgressHelper.SyncRunnable; import com.android.ddmuilib.console.DdmConsole; import org.eclipse.swt.widgets.Shell; @@ -82,7 +86,8 @@ public class MethodProfilingHandler extends BaseFileHandler if (sync != null) { pullAndOpen(sync, remoteFilePath); } else { - displayErrorFromUiThread("Unable to download trace file from device '%1$s'.", + displayErrorFromUiThread( + "Unable to download trace file from device '%1$s'.", device.getSerialNumber()); } } catch (Exception e) { @@ -109,25 +114,34 @@ public class MethodProfilingHandler extends BaseFileHandler /** * pulls and open a file. This is run from the UI thread. */ - private void pullAndOpen(SyncService sync, String remoteFilePath) + private void pullAndOpen(final SyncService sync, final String remoteFilePath) throws InvocationTargetException, InterruptedException, IOException { // get a temp file File temp = File.createTempFile("android", ".trace"); //$NON-NLS-1$ //$NON-NLS-2$ - String tempPath = temp.getAbsolutePath(); + final String tempPath = temp.getAbsolutePath(); // pull the file - SyncResult result = pull(sync, tempPath, remoteFilePath); - if (result != null) { - if (result.getCode() == SyncService.RESULT_OK) { - // open the temp file in traceview - openInTraceview(tempPath); - } else { - displayErrorFromUiThread("Unable to download trace file:\n\n%1$s", - result.getMessage()); + try { + SyncProgressHelper.run(new SyncRunnable() { + public void run(ISyncProgressMonitor monitor) + throws SyncException, IOException, TimeoutException { + sync.pullFile(tempPath, remoteFilePath, monitor); + } + + public void close() { + sync.close(); + } + }, + String.format("Pulling %1$s from the device", remoteFilePath), mParentShell); + + // open the temp file in traceview + openInTraceview(tempPath); + } catch (SyncException e) { + if (e.wasCanceled() == false) { + displayErrorFromUiThread("Unable to download trace file:\n\n%1$s", e.getMessage()); } - } else { - // this really shouldn't happen. - displayErrorFromUiThread("Unable to download trace file."); + } catch (TimeoutException e) { + displayErrorFromUiThread("Unable to download trace file:\n\ntimeout"); } } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java index 710d7eb..180af4c 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java @@ -16,9 +16,12 @@ package com.android.ddmuilib.logcat; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; import com.android.ddmlib.MultiLineReceiver; +import com.android.ddmlib.ShellCommandUnresponsiveException; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.Log.LogLevel; import com.android.ddmuilib.DdmUiPreferences; import com.android.ddmuilib.ITableFocusListener; @@ -1310,7 +1313,13 @@ public class LogPanel extends SelectionDependentPanel { try { mCurrentLoggedDevice.executeShellCommand("ps", psor); //$NON-NLS-1$ } catch (IOException e) { - // hmm... + // Ignore + } catch (TimeoutException e) { + // Ignore + } catch (AdbCommandRejectedException e) { + // Ignore + } catch (ShellCommandUnresponsiveException e) { + // Ignore } } }.start(); diff --git a/dumpeventlog/src/com/android/dumpeventlog/DumpEventLog.java b/dumpeventlog/src/com/android/dumpeventlog/DumpEventLog.java index 695573c..0669e33 100644 --- a/dumpeventlog/src/com/android/dumpeventlog/DumpEventLog.java +++ b/dumpeventlog/src/com/android/dumpeventlog/DumpEventLog.java @@ -16,9 +16,11 @@ package com.android.dumpeventlog; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.Log.ILogOutput; import com.android.ddmlib.Log.LogLevel; import com.android.ddmlib.log.LogReceiver; @@ -120,7 +122,7 @@ public class DumpEventLog { grabLogFrom(device, args[1]); } catch (FileNotFoundException e) { e.printStackTrace(); - } catch (IOException e) { + } catch (Exception e) { e.printStackTrace(); } return; @@ -133,7 +135,8 @@ public class DumpEventLog { } } - private static void grabLogFrom(IDevice device, String filePath) throws IOException { + private static void grabLogFrom(IDevice device, String filePath) throws IOException, + TimeoutException, AdbCommandRejectedException { LogWriter writer = new LogWriter(filePath); LogReceiver receiver = new LogReceiver(writer); writer.setReceiver(receiver); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java index f122e1a..575502a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java @@ -16,11 +16,15 @@ package com.android.ide.eclipse.adt.internal.launch; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.CanceledException; import com.android.ddmlib.Client; import com.android.ddmlib.ClientData; import com.android.ddmlib.IDevice; +import com.android.ddmlib.InstallException; import com.android.ddmlib.Log; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener; import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; @@ -892,10 +896,29 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener return installResult; } catch (IOException e) { - String msg = String.format("Failed to upload %1$s on device '%2$s'", fileName, + String msg = String.format("Failed to install %1$s on device '%2$s': %3$s", fileName, + device.getSerialNumber(), e.getMessage()); + AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg, e); + } catch (TimeoutException e) { + String msg = String.format("Failed to install %1$s on device '%2$s': timeout", fileName, device.getSerialNumber()); + AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg); + } catch (AdbCommandRejectedException e) { + String msg = String.format( + "Failed to install %1$s on device '%2$s': adb rejected install command with: %3$s", + fileName, device.getSerialNumber(), e.getMessage()); AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg, e); + } catch (CanceledException e) { + if (e.wasCanceled()) { + AdtPlugin.printToConsole(launchInfo.getProject(), + String.format("Install of %1$s canceled", fileName)); + } else { + String msg = String.format("Failed to install %1$s on device '%2$s': %3$s", + fileName, device.getSerialNumber(), e.getMessage()); + AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg, e); + } } + return false; } @@ -987,7 +1010,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener */ return checkInstallResult(result, device, launchInfo, remotePath, InstallRetryMode.ALWAYS); - } catch (IOException e) { + } catch (Exception e) { String msg = String.format( "Failed to install %1$s on device '%2$s!", launchInfo.getPackageFile().getName(), device.getSerialNumber()); @@ -1005,10 +1028,10 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener * @param remotePath the temporary path of the package on the device * @param retryMode indicates what to do in case, a package already exists. * @return <code>true<code> if success, <code>false</code> otherwise. - * @throws IOException + * @throws InstallException */ private boolean checkInstallResult(String result, IDevice device, DelayedLaunchInfo launchInfo, - String remotePath, InstallRetryMode retryMode) throws IOException { + String remotePath, InstallRetryMode retryMode) throws InstallException { if (result == null) { AdtPlugin.printToConsole(launchInfo.getProject(), "Success!"); return true; @@ -1086,13 +1109,14 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener * @param device the device on which to install the application. * @param launchInfo the {@link DelayedLaunchInfo}. * @return a {@link String} with an error code, or <code>null</code> if success. - * @throws IOException + * @throws InstallException if the installation failed. */ @SuppressWarnings("unused") - private String doUninstall(IDevice device, DelayedLaunchInfo launchInfo) throws IOException { + private String doUninstall(IDevice device, DelayedLaunchInfo launchInfo) + throws InstallException { try { return device.uninstallPackage(launchInfo.getPackageName()); - } catch (IOException e) { + } catch (InstallException e) { String msg = String.format( "Failed to uninstall %1$s: %2$s", launchInfo.getPackageName(), e.getMessage()); AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg); @@ -1108,10 +1132,10 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener * @param device the device on which to install the application. * @param reinstall * @return a {@link String} with an error code, or <code>null</code> if success. - * @throws IOException + * @throws InstallException if the uninstallation failed. */ private String doInstall(DelayedLaunchInfo launchInfo, final String remotePath, - final IDevice device, boolean reinstall) throws IOException { + final IDevice device, boolean reinstall) throws InstallException { return device.installRemotePackage(remotePath, reinstall); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java index b2772f7..24111b6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java @@ -45,6 +45,8 @@ public class LaunchMessages extends NLS { public static String RemoteAdtTestRunner_RunIOException_s; public static String RemoteAdtTestRunner_RunTimeoutException; + public static String RemoteAdtTestRunner_RunAdbCommandRejectedException_s; + public static String RemoteAdtTestRunner_RunShellCommandUnresponsiveException; public static String RemoteAdtTestRunner_RunStoppedMsg; static { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java index 3484252..64e93b8 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.launch.junit.runtime; +import com.android.ddmlib.AdbCommandRejectedException; +import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; import com.android.ddmlib.testrunner.ITestRunListener; import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; @@ -132,6 +134,12 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { } catch (IOException e) { reportError(String.format(LaunchMessages.RemoteAdtTestRunner_RunIOException_s, e.getMessage())); + } catch (AdbCommandRejectedException e) { + reportError(String.format( + LaunchMessages.RemoteAdtTestRunner_RunAdbCommandRejectedException_s, + e.getMessage())); + } catch (ShellCommandUnresponsiveException e) { + reportError(LaunchMessages.RemoteAdtTestRunner_RunTimeoutException); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties index 1ac7fb2..2670316 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties @@ -38,3 +38,5 @@ RemoteAdtTestRunner_RunFailedMsg_s=Test run failed: %1$s RemoteAdtTestRunner_RunTimeoutException=Connection with device timed out. RemoteAdtTestRunner_RunIOException_s=Lost connection with device: %s RemoteAdtTestRunner_RunStoppedMsg=Test run stopped +RemoteAdtTestRunner_RunAdbCommandRejectedException_s=Adb rejected command: %s +RemoteAdtTestRunner_RunShellCommandUnresponsiveException=Device stopped sending output diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ApkInstallManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ApkInstallManager.java index 48a433a..19d20d8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ApkInstallManager.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ApkInstallManager.java @@ -27,7 +27,6 @@ import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonit import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; -import java.io.IOException; import java.util.HashSet; import java.util.Iterator; @@ -152,7 +151,7 @@ public final class ApkInstallManager { } return receiver.foundPackage; - } catch (IOException e) { + } catch (Exception e) { // failed to query pm? force reinstall. return false; } diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java index 079feb7..f7728f5 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java +++ b/eclipse/plugins/com.android.ide.eclipse.ddms/src/com/android/ide/eclipse/ddms/views/DeviceView.java @@ -21,17 +21,21 @@ import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.Client; import com.android.ddmlib.ClientData; import com.android.ddmlib.IDevice; +import com.android.ddmlib.SyncException; import com.android.ddmlib.SyncService; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; import com.android.ddmlib.ClientData.IHprofDumpHandler; import com.android.ddmlib.ClientData.MethodProfilingStatus; -import com.android.ddmlib.SyncService.SyncResult; -import com.android.ddmuilib.handler.BaseFileHandler; -import com.android.ddmuilib.handler.MethodProfilingHandler; +import com.android.ddmlib.SyncService.ISyncProgressMonitor; import com.android.ddmuilib.DevicePanel; import com.android.ddmuilib.ImageLoader; import com.android.ddmuilib.ScreenShotDialog; +import com.android.ddmuilib.SyncProgressHelper; import com.android.ddmuilib.DevicePanel.IUiSelectionListener; +import com.android.ddmuilib.SyncProgressHelper.SyncRunnable; +import com.android.ddmuilib.handler.BaseFileHandler; +import com.android.ddmuilib.handler.MethodProfilingHandler; import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.ide.eclipse.ddms.DdmsPlugin.IDebugLauncher; import com.android.ide.eclipse.ddms.preferences.PreferenceInitializer; @@ -132,31 +136,43 @@ public class DeviceView extends ViewPart implements IUiSelectionListener, IClien IPreferenceStore store = DdmsPlugin.getDefault().getPreferenceStore(); String value = store.getString(PreferenceInitializer.ATTR_HPROF_ACTION); - SyncResult result = null; if (ACTION_OPEN.equals(value)) { File temp = File.createTempFile("android", DOT_HPROF); //$NON-NLS-1$ - String tempPath = temp.getAbsolutePath(); - result = pull(sync, tempPath, remoteFilePath); - if (result != null && result.getCode() == SyncService.RESULT_OK) { - open(tempPath); - } + final String tempPath = temp.getAbsolutePath(); + SyncProgressHelper.run(new SyncRunnable() { + + public void run(ISyncProgressMonitor monitor) + throws SyncException, IOException, + TimeoutException { + sync.pullFile(remoteFilePath, tempPath, monitor); + } + + public void close() { + sync.close(); + } + }, + String.format("Pulling %1$s from the device", remoteFilePath), + mParentShell); + + open(tempPath); } else { // default action is ACTION_SAVE - result = promptAndPull(sync, + promptAndPull(sync, client.getClientData().getClientDescription() + DOT_HPROF, remoteFilePath, "Save HPROF file"); } - - if (result != null && result.getCode() != SyncService.RESULT_OK) { - displayErrorFromUiThread( - "Unable to download HPROF file from device '%1$s'.\n\n%2$s", - device.getSerialNumber(), result.getMessage()); - } } else { - displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.", + displayErrorFromUiThread( + "Unable to download HPROF file from device '%1$s'.", device.getSerialNumber()); } + } catch (SyncException e) { + if (e.wasCanceled() == false) { + displayErrorFromUiThread( + "Unable to download HPROF file from device '%1$s'.\n\n%2$s", + device.getSerialNumber(), e.getMessage()); + } } catch (Exception e) { displayErrorFromUiThread("Unable to download HPROF file from device '%1$s'.", device.getSerialNumber()); diff --git a/eclipse/plugins/com.android.ide.eclipse.hierarchyviewer/libs/.gitignore b/eclipse/plugins/com.android.ide.eclipse.hierarchyviewer/libs/.gitignore new file mode 100644 index 0000000..f23b948 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.hierarchyviewer/libs/.gitignore @@ -0,0 +1 @@ +*.jar
\ No newline at end of file diff --git a/eventanalyzer/src/com/android/eventanalyzer/EventAnalyzer.java b/eventanalyzer/src/com/android/eventanalyzer/EventAnalyzer.java index 11444ec..691bf0c 100644 --- a/eventanalyzer/src/com/android/eventanalyzer/EventAnalyzer.java +++ b/eventanalyzer/src/com/android/eventanalyzer/EventAnalyzer.java @@ -16,9 +16,11 @@ package com.android.eventanalyzer; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.Log.ILogOutput; import com.android.ddmlib.Log.LogLevel; import com.android.ddmlib.log.EventContainer; @@ -159,7 +161,7 @@ public class EventAnalyzer implements ILogListener { // analyze the data gathered by the parser methods analyzeData(); - } catch (IOException e) { + } catch (Exception e) { e.printStackTrace(); } } @@ -227,7 +229,8 @@ public class EventAnalyzer implements ILogListener { } } - private void parseLogFromDevice() throws IOException { + private void parseLogFromDevice() throws IOException, TimeoutException, + AdbCommandRejectedException { // init the lib AndroidDebugBridge.init(false /* debugger support */); @@ -300,7 +303,8 @@ public class EventAnalyzer implements ILogListener { } } - private void grabLogFrom(IDevice device) throws IOException { + private void grabLogFrom(IDevice device) throws IOException, TimeoutException, + AdbCommandRejectedException { mParser = new EventLogParser(); if (mParser.init(device) == false) { printAndExit("Failed to get event-log-tags from " + device.getSerialNumber(), diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java b/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java index 209577d..2d2cea1 100644 --- a/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java +++ b/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java @@ -21,6 +21,7 @@ import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; import com.android.ddmlib.MultiLineReceiver; +import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; import java.io.IOException; @@ -73,6 +74,12 @@ public class DeviceBridge { } } catch (IOException e) { e.printStackTrace(); + } catch (TimeoutException e) { + e.printStackTrace(); + } catch (AdbCommandRejectedException e) { + e.printStackTrace(); + } catch (ShellCommandUnresponsiveException e) { + e.printStackTrace(); } return result[0]; } @@ -91,6 +98,12 @@ public class DeviceBridge { } } catch (IOException e) { e.printStackTrace(); + } catch (TimeoutException e) { + e.printStackTrace(); + } catch (AdbCommandRejectedException e) { + e.printStackTrace(); + } catch (ShellCommandUnresponsiveException e) { + e.printStackTrace(); } return result[0]; } @@ -105,6 +118,12 @@ public class DeviceBridge { } } catch (IOException e) { e.printStackTrace(); + } catch (TimeoutException e) { + e.printStackTrace(); + } catch (AdbCommandRejectedException e) { + e.printStackTrace(); + } catch (ShellCommandUnresponsiveException e) { + e.printStackTrace(); } return result[0]; } diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/device/Window.java b/hierarchyviewer/src/com/android/hierarchyviewer/device/Window.java index 0417df6..5c87d33 100644 --- a/hierarchyviewer/src/com/android/hierarchyviewer/device/Window.java +++ b/hierarchyviewer/src/com/android/hierarchyviewer/device/Window.java @@ -39,6 +39,7 @@ public class Window { return Integer.toHexString(hashCode); } + @Override public String toString() { return title; } diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/laf/UnifiedContentBorder.java b/hierarchyviewer/src/com/android/hierarchyviewer/laf/UnifiedContentBorder.java index 401fb3e..873b275 100644 --- a/hierarchyviewer/src/com/android/hierarchyviewer/laf/UnifiedContentBorder.java +++ b/hierarchyviewer/src/com/android/hierarchyviewer/laf/UnifiedContentBorder.java @@ -24,6 +24,7 @@ public class UnifiedContentBorder extends AbstractBorder { private static final Color BORDER_BOTTOM_COLOR1 = new Color(0x404040); private static final Color BORDER_BOTTOM_COLOR2 = new Color(0xd8d8d8); + @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { g.setColor(BORDER_TOP_COLOR1); g.drawLine(x, y, x + width, y); @@ -33,10 +34,12 @@ public class UnifiedContentBorder extends AbstractBorder { g.drawLine(x, y + height - 1, x + width, y + height - 1); } + @Override public Insets getBorderInsets(Component component) { return new Insets(1, 0, 2, 0); } + @Override public boolean isBorderOpaque() { return true; } diff --git a/hierarchyviewer2/.gitignore b/hierarchyviewer2/.gitignore new file mode 100644 index 0000000..89a196a --- /dev/null +++ b/hierarchyviewer2/.gitignore @@ -0,0 +1,4 @@ +app/bin +libs/hierarchyviewerlib/bin +libs/hierarchyvieweruilib/bin + diff --git a/screenshot/src/com/android/screenshot/Screenshot.java b/screenshot/src/com/android/screenshot/Screenshot.java index a3fe520..930ea8e 100644 --- a/screenshot/src/com/android/screenshot/Screenshot.java +++ b/screenshot/src/com/android/screenshot/Screenshot.java @@ -20,6 +20,7 @@ import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; import com.android.ddmlib.RawImage; +import com.android.ddmlib.TimeoutException; import com.android.ddmlib.Log.ILogOutput; import com.android.ddmlib.Log.LogLevel; @@ -198,8 +199,10 @@ public class Screenshot { try { rawImage = device.getScreenshot(); - } - catch (IOException ioe) { + } catch (TimeoutException e) { + printAndExit("Unable to get frame buffer: timeout", true /* terminate */); + return; + } catch (Exception ioe) { printAndExit("Unable to get frame buffer: " + ioe.getMessage(), true /* terminate */); return; } |