diff options
author | Xavier Ducrohet <xav@android.com> | 2010-07-15 17:10:32 -0700 |
---|---|---|
committer | Android Code Review <code-review@android.com> | 2010-07-15 17:10:32 -0700 |
commit | 3992e7f56fdb4a8ffded283c8589f0f505ae198d (patch) | |
tree | 30b8f2248c262d3a2b3a4d81142e600d3946632c | |
parent | 63442129aa2c3e4e5a3c83a79c66b00924957c20 (diff) | |
parent | a6e573c897b84f21802a7bccad817552c32364e7 (diff) | |
download | sdk-3992e7f56fdb4a8ffded283c8589f0f505ae198d.zip sdk-3992e7f56fdb4a8ffded283c8589f0f505ae198d.tar.gz sdk-3992e7f56fdb4a8ffded283c8589f0f505ae198d.tar.bz2 |
Merge "Add new exceptions to ddmlib."
12 files changed, 413 insertions, 170 deletions
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbCommandRejectedException.java b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbCommandRejectedException.java new file mode 100644 index 0000000..673acb5 --- /dev/null +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbCommandRejectedException.java @@ -0,0 +1,56 @@ +/* + * 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 adb refuses a command. + */ +public class AdbCommandRejectedException extends IOException { + private static final long serialVersionUID = 1L; + private final boolean mIsDeviceOffline; + private final boolean mErrorDuringDeviceSelection; + + AdbCommandRejectedException(String message) { + super(message); + mIsDeviceOffline = "device offline".equals(message); + mErrorDuringDeviceSelection = false; + } + + AdbCommandRejectedException(String message, boolean errorDuringDeviceSelection) { + super(message); + mErrorDuringDeviceSelection = errorDuringDeviceSelection; + mIsDeviceOffline = "device offline".equals(message); + } + + /** + * Returns true if the error is due to the device being offline. + */ + public boolean isDeviceOffline() { + return mIsDeviceOffline; + } + + /** + * Returns whether adb refused to target a given device for the command. + * <p/>If false, adb refused the command itself, if true, it refused to target the given + * device. + */ + public boolean wasErrorDuringDeviceSelection() { + return mErrorDuringDeviceSelection; + } +} diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java index f31e27f..5b5a41f 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java @@ -68,9 +68,11 @@ final class AdbHelper { * @param devicePort the port we're opening * @throws TimeoutException in case of timeout on the connection. * @throws IOException in case of I/O error on the connection. + * @throws AdbCommandRejectedException if adb rejects the command */ public static SocketChannel open(InetSocketAddress adbSockAddr, - Device device, int devicePort) throws IOException, TimeoutException { + Device device, int devicePort) + throws IOException, TimeoutException, AdbCommandRejectedException { SocketChannel adbChan = SocketChannel.open(adbSockAddr); try { @@ -87,8 +89,8 @@ final class AdbHelper { write(adbChan, req); AdbResponse resp = readAdbResponse(adbChan, false); - if (!resp.okay) { - throw new IOException("connection request rejected"); //$NON-NLS-1$ + if (resp.okay == false) { + throw new AdbCommandRejectedException(resp.message); } adbChan.configureBlocking(true); @@ -112,10 +114,12 @@ final class AdbHelper { * to the first available device. * @param pid the process pid to connect to. * @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. */ public static SocketChannel createPassThroughConnection(InetSocketAddress adbSockAddr, - Device device, int pid) throws TimeoutException, IOException { + Device device, int pid) + throws TimeoutException, AdbCommandRejectedException, IOException { SocketChannel adbChan = SocketChannel.open(adbSockAddr); try { @@ -132,8 +136,8 @@ final class AdbHelper { write(adbChan, req); AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); - if (!resp.okay) { - throw new IOException("connection request rejected: " + resp.message); //$NON-NLS-1$ + if (resp.okay == false) { + throw new AdbCommandRejectedException(resp.message); } adbChan.configureBlocking(true); @@ -258,10 +262,11 @@ final class AdbHelper { /** * Retrieve the frame buffer from the device. * @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. */ static RawImage getFrameBuffer(InetSocketAddress adbSockAddr, Device device) - throws TimeoutException, IOException { + throws TimeoutException, AdbCommandRejectedException, IOException { RawImage imageParams = new RawImage(); byte[] request = formAdbRequest("framebuffer:"); //$NON-NLS-1$ @@ -283,7 +288,7 @@ final class AdbHelper { AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (resp.okay == false) { - throw new IOException(resp.message); + throw new AdbCommandRejectedException(resp.message); } // first the protocol version. @@ -333,21 +338,28 @@ final class AdbHelper { /** * Executes a shell command on the device and retrieve the output. The output is * handed to <var>rcvr</var> as it arrives. + * * @param adbSockAddr the {@link InetSocketAddress} to adb. * @param command the shell command to execute * @param device the {@link IDevice} on which to execute the command. * @param rcvr the {@link IShellOutputReceiver} that will receives the output of the shell - * command - * @param timeout timeout value in ms for the connection. 0 means no timeout. This only affects - * the timeout for reading the command output. Execution setup uses the normal timeout. - * @throws TimeoutException in case of timeout on the connection. + * command + * @param maxTimeToOutputResponse max time between command output. If more time passes + * between command output, the method will throw + * {@link ShellCommandUnresponsiveException}. A value of 0 means the method will + * wait forever for command output and never throw. + * @throws TimeoutException in case of timeout on the connection when sending the command. + * @throws AdbCommandRejectedException if adb rejects the command + * @throws ShellCommandUnresponsiveException in case the shell command doesn't send any output + * for a period longer than <var>maxTimeToOutputResponse</var>. * @throws IOException in case of I/O error on the connection. * * @see DdmPreferences#getTimeOut() */ static void executeRemoteCommand(InetSocketAddress adbSockAddr, - String command, IDevice device, IShellOutputReceiver rcvr, int timeout) - throws TimeoutException, IOException { + String command, IDevice device, IShellOutputReceiver rcvr, int maxTimeToOutputResponse) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { Log.v("ddms", "execute: running " + command); SocketChannel adbChan = null; @@ -366,12 +378,12 @@ final class AdbHelper { AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (resp.okay == false) { Log.e("ddms", "ADB rejected shell command (" + command + "): " + resp.message); - throw new IOException("sad result from adb: " + resp.message); + throw new AdbCommandRejectedException(resp.message); } byte[] data = new byte[16384]; ByteBuffer buf = ByteBuffer.wrap(data); - int timeoutCount = 0; + int timeToResponseCount = 0; while (true) { int count; @@ -390,16 +402,17 @@ final class AdbHelper { } else if (count == 0) { try { int wait = WAIT_TIME * 5; - timeoutCount += wait; - if (timeout > 0 && timeoutCount > timeout) { - throw new TimeoutException(); + timeToResponseCount += wait; + if (maxTimeToOutputResponse > 0 && + timeToResponseCount > maxTimeToOutputResponse) { + throw new ShellCommandUnresponsiveException(); } Thread.sleep(wait); } catch (InterruptedException ie) { } } else { // reset timeout - timeoutCount = 0; + timeToResponseCount = 0; // send data to receiver if present if (rcvr != null) { @@ -424,10 +437,11 @@ final class AdbHelper { * @param device the Device on which to run the service * @param rcvr the {@link LogReceiver} to receive the log output * @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. */ public static void runEventLogService(InetSocketAddress adbSockAddr, Device device, - LogReceiver rcvr) throws TimeoutException, IOException { + LogReceiver rcvr) throws TimeoutException, AdbCommandRejectedException, IOException { runLogService(adbSockAddr, device, "events", rcvr); //$NON-NLS-1$ } @@ -439,10 +453,11 @@ final class AdbHelper { * @param logName the name of the log file to output * @param rcvr the {@link LogReceiver} to receive the log output * @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. */ public static void runLogService(InetSocketAddress adbSockAddr, Device device, String logName, - LogReceiver rcvr) throws TimeoutException, IOException { + LogReceiver rcvr) throws TimeoutException, AdbCommandRejectedException, IOException { SocketChannel adbChan = null; try { @@ -458,7 +473,7 @@ final class AdbHelper { AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (resp.okay == false) { - throw new IOException("Device rejected log command: " + resp.message); + throw new AdbCommandRejectedException(resp.message); } byte[] data = new byte[16384]; @@ -498,12 +513,12 @@ final class AdbHelper { * @param device the device on which to do the port fowarding * @param localPort the local port to forward * @param remotePort the remote port. - * @return <code>true</code> if success. * @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. */ - public static boolean createForward(InetSocketAddress adbSockAddr, Device device, int localPort, - int remotePort) throws TimeoutException, IOException { + public static void createForward(InetSocketAddress adbSockAddr, Device device, int localPort, + int remotePort) throws TimeoutException, AdbCommandRejectedException, IOException { SocketChannel adbChan = null; try { @@ -519,8 +534,8 @@ final class AdbHelper { AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (resp.okay == false) { Log.w("create-forward", "Error creating forward: " + resp.message); + throw new AdbCommandRejectedException(resp.message); } - return resp.okay; } finally { if (adbChan != null) { adbChan.close(); @@ -534,12 +549,12 @@ final class AdbHelper { * @param device the device on which to remove the port fowarding * @param localPort the local port of the forward * @param remotePort the remote port. - * @return <code>true</code> if success. * @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. */ - public static boolean removeForward(InetSocketAddress adbSockAddr, Device device, int localPort, - int remotePort) throws TimeoutException, IOException { + public static void removeForward(InetSocketAddress adbSockAddr, Device device, int localPort, + int remotePort) throws TimeoutException, AdbCommandRejectedException, IOException { SocketChannel adbChan = null; try { @@ -555,8 +570,8 @@ final class AdbHelper { AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (resp.okay == false) { Log.w("remove-forward", "Error creating forward: " + resp.message); + throw new AdbCommandRejectedException(resp.message); } - return resp.okay; } finally { if (adbChan != null) { adbChan.close(); @@ -703,10 +718,11 @@ final class AdbHelper { * @param adbChan the socket connection to adb * @param device The device to talk to. * @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. */ static void setDevice(SocketChannel adbChan, IDevice device) - throws TimeoutException, IOException { + throws TimeoutException, AdbCommandRejectedException, IOException { // if the device is not -1, then we first tell adb we're looking to talk // to a specific device if (device != null) { @@ -716,20 +732,23 @@ final class AdbHelper { write(adbChan, device_query); AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); - if (!resp.okay) - throw new IOException("device (" + device + - ") request rejected: " + resp.message); + if (resp.okay == false) { + throw new AdbCommandRejectedException(resp.message, + true/*errorDuringDeviceSelection*/); + } } - } /** * Reboot the device. * * @param into what to reboot into (recovery, bootloader). Or null to just reboot. + * @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. */ public static void reboot(String into, InetSocketAddress adbSockAddr, - Device device) throws TimeoutException, IOException { + Device device) throws TimeoutException, AdbCommandRejectedException, IOException { byte[] request; if (into == null) { request = formAdbRequest("reboot:"); //$NON-NLS-1$ diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java b/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java index 24c20b2..7eff98e 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java @@ -36,6 +36,8 @@ import java.util.regex.Pattern; */ final class Device implements IDevice { + private final static int INSTALL_TIMEOUT = 2*60*1000; //2min + /** Emulator Serial Number regexp. */ final static String RE_EMULATOR_SN = "emulator-(\\d+)"; //$NON-NLS-1$ @@ -246,7 +248,8 @@ final class Device implements IDevice { * (non-Javadoc) * @see com.android.ddmlib.IDevice#getSyncService() */ - public SyncService getSyncService() throws TimeoutException, IOException { + public SyncService getSyncService() + throws TimeoutException, AdbCommandRejectedException, IOException { SyncService syncService = new SyncService(AndroidDebugBridge.getSocketAddress(), this); if (syncService.openSync()) { return syncService; @@ -263,67 +266,44 @@ final class Device implements IDevice { return new FileListingService(this); } - /* - * (non-Javadoc) - * @see com.android.ddmlib.IDevice#getScreenshot() - */ - public RawImage getScreenshot() throws TimeoutException, IOException { + public RawImage getScreenshot() + throws TimeoutException, AdbCommandRejectedException, IOException { return AdbHelper.getFrameBuffer(AndroidDebugBridge.getSocketAddress(), this); } public void executeShellCommand(String command, IShellOutputReceiver receiver) - throws TimeoutException, IOException { + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this, receiver, DdmPreferences.getTimeOut()); } - public void executeShellCommand(String command, IShellOutputReceiver receiver, int timeout) - throws TimeoutException, IOException { + public void executeShellCommand(String command, IShellOutputReceiver receiver, + int maxTimeToOutputResponse) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { AdbHelper.executeRemoteCommand(AndroidDebugBridge.getSocketAddress(), command, this, - receiver, timeout); + receiver, maxTimeToOutputResponse); } - public void runEventLogService(LogReceiver receiver) throws TimeoutException, IOException { + public void runEventLogService(LogReceiver receiver) + throws TimeoutException, AdbCommandRejectedException, IOException { AdbHelper.runEventLogService(AndroidDebugBridge.getSocketAddress(), this, receiver); } public void runLogService(String logname, LogReceiver receiver) - throws TimeoutException, IOException { + throws TimeoutException, AdbCommandRejectedException, IOException { AdbHelper.runLogService(AndroidDebugBridge.getSocketAddress(), this, logname, receiver); } - /* - * (non-Javadoc) - * @see com.android.ddmlib.IDevice#createForward(int, int) - */ - public boolean createForward(int localPort, int remotePort) { - try { - return AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this, - localPort, remotePort); - } catch (TimeoutException e) { - Log.e("adb-forward", "timeout"); - return false; - } catch (IOException e) { - Log.e("adb-forward", e); //$NON-NLS-1$ - return false; - } + public void createForward(int localPort, int remotePort) + throws TimeoutException, AdbCommandRejectedException, IOException { + AdbHelper.createForward(AndroidDebugBridge.getSocketAddress(), this, localPort, remotePort); } - /* - * (non-Javadoc) - * @see com.android.ddmlib.IDevice#removeForward(int, int) - */ - public boolean removeForward(int localPort, int remotePort) { - try { - return AdbHelper.removeForward(AndroidDebugBridge.getSocketAddress(), this, - localPort, remotePort); - } catch (TimeoutException e) { - Log.e("adb-remove-forward", "timeout"); - return false; - } catch (IOException e) { - Log.e("adb-remove-forward", e); //$NON-NLS-1$ - return false; - } + public void removeForward(int localPort, int remotePort) + throws TimeoutException, AdbCommandRejectedException, IOException { + AdbHelper.removeForward(AndroidDebugBridge.getSocketAddress(), this, localPort, remotePort); } /* @@ -427,22 +407,17 @@ final class Device implements IDevice { mMountPoints.put(name, value); } - /** - * {@inheritDoc} - */ public String installPackage(String packageFilePath, boolean reinstall) - throws TimeoutException, IOException { + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { String remoteFilePath = syncPackageToDevice(packageFilePath); String result = installRemotePackage(remoteFilePath, reinstall); removeRemotePackage(remoteFilePath); return result; } - /** - * {@inheritDoc} - */ public String syncPackageToDevice(String localFilePath) - throws IOException, TimeoutException { + throws IOException, AdbCommandRejectedException, TimeoutException { try { String packageFileName = getFileName(localFilePath); String remoteFilePath = String.format("/data/local/tmp/%1$s", packageFileName); //$NON-NLS-1$ @@ -485,25 +460,25 @@ final class Device implements IDevice { return new File(filePath).getName(); } - /** - * {@inheritDoc} - */ public String installRemotePackage(String remoteFilePath, boolean reinstall) - throws TimeoutException, IOException { + 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); + executeShellCommand(cmd, receiver, INSTALL_TIMEOUT); return receiver.getErrorMessage(); } /** * {@inheritDoc} */ - public void removeRemotePackage(String remoteFilePath) throws TimeoutException, IOException { + public void removeRemotePackage(String remoteFilePath) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { // now we delete the app we sync'ed try { - executeShellCommand("rm " + remoteFilePath, new NullOutputReceiver()); + 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())); @@ -514,9 +489,11 @@ final class Device implements IDevice { /** * {@inheritDoc} */ - public String uninstallPackage(String packageName) throws TimeoutException, IOException { + public String uninstallPackage(String packageName) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { InstallReceiver receiver = new InstallReceiver(); - executeShellCommand("pm uninstall " + packageName, receiver); + executeShellCommand("pm uninstall " + packageName, receiver, INSTALL_TIMEOUT); return receiver.getErrorMessage(); } @@ -524,7 +501,8 @@ final class Device implements IDevice { * (non-Javadoc) * @see com.android.ddmlib.IDevice#reboot() */ - public void reboot(String into) throws TimeoutException, IOException { + public void reboot(String into) + throws TimeoutException, AdbCommandRejectedException, IOException { AdbHelper.reboot(into, AndroidDebugBridge.getSocketAddress(), this); } } diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/DeviceMonitor.java b/ddms/libs/ddmlib/src/com/android/ddmlib/DeviceMonitor.java index 82b3bc1..21869af 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/DeviceMonitor.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/DeviceMonitor.java @@ -447,15 +447,30 @@ final class DeviceMonitor { } } } catch (TimeoutException e) { - Log.w("DeviceMonitor", String.format("Timeout getting device %s info", + Log.w("DeviceMonitor", String.format("Connection timeout getting info for device %s", device.getSerialNumber())); + + } catch (AdbCommandRejectedException e) { + // This should never happen as we only do this once the device is online. + Log.w("DeviceMonitor", String.format( + "Adb rejected command to get device %1$s info: %2$s", + device.getSerialNumber(), e.getMessage())); + + } catch (ShellCommandUnresponsiveException e) { + Log.w("DeviceMonitor", String.format( + "Adb shell command took too long returning info for device %s", + device.getSerialNumber())); + } catch (IOException e) { - // if we can't get the build info, it doesn't matter too much + Log.w("DeviceMonitor", String.format( + "IO Error getting info for device %s", + device.getSerialNumber())); } } private void queryNewDeviceForMountingPoint(final Device device, final String name) - throws TimeoutException, IOException { + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { device.executeShellCommand("echo $" + name, new MultiLineReceiver() { //$NON-NLS-1$ public boolean isCancelled() { return false; @@ -514,6 +529,16 @@ final class DeviceMonitor { Log.d("DeviceMonitor", "Connection Failure when starting to monitor device '" + device + "' : timeout"); + } catch (AdbCommandRejectedException e) { + try { + // attempt to close the socket if needed. + socketChannel.close(); + } catch (IOException e1) { + // we can ignore that one. It may already have been closed. + } + Log.d("DeviceMonitor", + "Adb refused to start monitoring device '" + + device + "' : " + e.getMessage()); } catch (IOException e) { try { // attempt to close the socket if needed. @@ -636,7 +661,7 @@ final class DeviceMonitor { } private boolean sendDeviceMonitoringRequest(SocketChannel socket, Device device) - throws TimeoutException, IOException { + throws TimeoutException, AdbCommandRejectedException, IOException { try { AdbHelper.setDevice(socket, device); @@ -769,6 +794,11 @@ final class DeviceMonitor { Log.w("DeviceMonitor", "Failed to connect to client '" + pid + "': timeout"); return; + } catch (AdbCommandRejectedException e) { + Log.w("DeviceMonitor", + "Adb rejected connection to client '" + pid + "': " + e.getMessage()); + return; + } catch (IOException ioe) { Log.w("DeviceMonitor", "Failed to connect to client '" + pid + "': " + ioe.getMessage()); diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java b/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java index 59ae910..01814ac 100755 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java @@ -21,7 +21,6 @@ import com.android.ddmlib.log.LogReceiver; import java.io.IOException; import java.util.Map; - /** * A Device. It can be a physical device or an emulator. */ @@ -65,6 +64,7 @@ public interface IDevice { /** * Returns a {@link DeviceState} from the string returned by <code>adb devices</code>. + * * @param state the device state. * @return a {@link DeviceState} object or <code>null</code> if the state is unknown. */ @@ -88,6 +88,7 @@ public interface IDevice { * <p/>This is only valid if {@link #isEmulator()} returns true. * <p/>If the emulator is not running any AVD (for instance it's running from an Android source * tree build), this method will return "<code><build></code>". + * * @return the name of the AVD or <code>null</code> if there isn't any. */ public String getAvdName(); @@ -109,6 +110,7 @@ public interface IDevice { /** * Returns a property value. + * * @param name the name of the value to return. * @return the value or <code>null</code> if the property does not exist. */ @@ -116,6 +118,7 @@ public interface IDevice { /** * Returns a mount point. + * * @param name the name of the mount point to return * * @see #MNT_EXTERNAL_STORAGE @@ -126,6 +129,7 @@ public interface IDevice { /** * Returns if the device is ready. + * * @return <code>true</code> if {@link #getState()} returns {@link DeviceState#ONLINE}. */ public boolean isOnline(); @@ -137,12 +141,14 @@ public interface IDevice { /** * Returns if the device is offline. + * * @return <code>true</code> if {@link #getState()} returns {@link DeviceState#OFFLINE}. */ public boolean isOffline(); /** * Returns if the device is in bootloader mode. + * * @return <code>true</code> if {@link #getState()} returns {@link DeviceState#BOOTLOADER}. */ public boolean isBootLoader(); @@ -159,6 +165,7 @@ public interface IDevice { /** * Returns a {@link Client} by its application name. + * * @param applicationName the name of the application * @return the <code>Client</code> object or <code>null</code> if no match was found. */ @@ -166,12 +173,16 @@ public interface IDevice { /** * Returns a {@link SyncService} object to push / pull files to and from the device. + * * @return <code>null</code> if the SyncService couldn't be created. This can happen if adb - * refuse to open the connection because the {@link IDevice} is invalid (or got disconnected). + * refuse to open the connection because the {@link IDevice} is invalid + * (or got disconnected). * @throws TimeoutException in case of timeout on the connection. + * @throws AdbCommandRejectedException if adb rejects the command * @throws IOException if the connection with adb failed. */ - public SyncService getSyncService() throws TimeoutException, IOException; + public SyncService getSyncService() + throws TimeoutException, AdbCommandRejectedException, IOException; /** * Returns a {@link FileListingService} for this device. @@ -180,55 +191,68 @@ public interface IDevice { /** * Takes a screen shot of the device and returns it as a {@link RawImage}. - * @return the screenshot as a <code>RawImage</code> or <code>null</code> if - * something went wrong. + * + * @return the screenshot as a <code>RawImage</code> or <code>null</code> if something + * went wrong. * @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. */ - public RawImage getScreenshot() throws TimeoutException, IOException; + public RawImage getScreenshot() throws TimeoutException, AdbCommandRejectedException, + IOException; /** * Executes a shell command on the device, and sends the result to a <var>receiver</var> - * <p/>This use the default timeout value returned by {@link DdmPreferences#getTimeOut()}. + * <p/>This is similar to calling + * <code>executeShellCommand(command, receiver, DdmPreferences.getTimeOut())</code>. + * * @param command the shell command to execute * @param receiver the {@link IShellOutputReceiver} that will receives the output of the shell - * command + * command * @throws TimeoutException in case of timeout on the connection. + * @throws AdbCommandRejectedException if adb rejects the command + * @throws ShellCommandUnresponsiveException in case the shell command doesn't send output + * for a given time. * @throws IOException in case of I/O error on the connection. * * @see #executeShellCommand(String, IShellOutputReceiver, int) + * @see DdmPreferences#getTimeOut() */ - public void executeShellCommand(String command, - IShellOutputReceiver receiver) throws TimeoutException, IOException; + public void executeShellCommand(String command, IShellOutputReceiver receiver) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException; /** * Executes a shell command on the device, and sends the result to a <var>receiver</var>. - * <p/>The timeout value is used as a maximum waiting time when expecting the command - * output from the device.<br> - * If the shell command takes a long time to run before outputting anything, this may be - * impacted by the timeout. For instance, if the command outputs one line every 10sec but the - * timeout is set to 5sec (default value) then the method will timeout. - * <p/>For commands like log output, a timeout value of 0 (no timeout, always blocking till the - * receiver's {@link IShellOutputReceiver#isCancelled()} return <code>true</code> should be + * <p/><var>maxTimeToOutputResponse</var> is used as a maximum waiting time when expecting the + * command output from the device.<br> + * At any time, if the shell command does not output anything for a period longer than + * <var>maxTimeToOutputResponse</var>, then the method will throw + * {@link ShellCommandUnresponsiveException}. + * <p/>For commands like log output, a <var>maxTimeToOutputResponse</var> value of 0, meaning + * that the method will never throw and will block until the receiver's + * {@link IShellOutputReceiver#isCancelled()} returns <code>true</code>, should be * used. - * <p/>When setting up the shell command to run, the normal timeout value is used while - * communicating with adb. * * @param command the shell command to execute * @param receiver the {@link IShellOutputReceiver} that will receives the output of the shell - * command - * @param timeout timeout value in ms for the connection. - * @param timeout the timeout. timeout value in ms for the connection.If 0, there is no timeout. - * @throws TimeoutException in case of timeout on the connection. Even with a timeout parameter - * of 0, timeout can happen during the setup of the shell command. Once command has launched, - * no timeout will occur as it's not possible to detect a difference between no output and - * no timeout. + * command + * @param maxTimeToOutputResponse the maximum amount of time during which the command is allowed + * to not output any response. A value of 0 means the method will wait forever + * (until the <var>receiver</var> cancels the execution) for command output and + * never throw. + * @throws TimeoutException in case of timeout on the connection when sending the command. + * @throws AdbCommandRejectedException if adb rejects the command. + * @throws ShellCommandUnresponsiveException in case the shell command doesn't send any output + * for a period longer than <var>maxTimeToOutputResponse</var>. * @throws IOException in case of I/O error on the connection. * * @see DdmPreferences#getTimeOut() */ - public void executeShellCommand(String command, - IShellOutputReceiver receiver, int timeout) throws TimeoutException, IOException; + public void executeShellCommand(String command, IShellOutputReceiver receiver, + int maxTimeToOutputResponse) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException; /** * Runs the event log service and outputs the event log to the {@link LogReceiver}. @@ -237,38 +261,52 @@ public interface IDevice { * @throws TimeoutException in case of timeout on the connection. This can only be thrown if the * timeout happens during setup. Once logs start being received, no timeout will occur as it's * not possible to detect a difference between no log and timeout. + * @throws AdbCommandRejectedException if adb rejects the command * @throws IOException in case of I/O error on the connection. */ - public void runEventLogService(LogReceiver receiver) throws TimeoutException, IOException; + public void runEventLogService(LogReceiver receiver) + throws TimeoutException, AdbCommandRejectedException, IOException; /** * Runs the log service for the given log and outputs the log to the {@link LogReceiver}. * <p/>This call is blocking until {@link LogReceiver#isCancelled()} returns true. + * * @param logname the logname of the log to read from. * @param receiver the receiver to receive the event log entries. * @throws TimeoutException in case of timeout on the connection. This can only be thrown if the - * timeout happens during setup. Once logs start being received, no timeout will occur as it's - * not possible to detect a difference between no log and timeout. + * timeout happens during setup. Once logs start being received, no timeout will + * occur as it's not possible to detect a difference between no log and timeout. + * @throws AdbCommandRejectedException if adb rejects the command * @throws IOException in case of I/O error on the connection. */ public void runLogService(String logname, LogReceiver receiver) - throws TimeoutException, IOException; + throws TimeoutException, AdbCommandRejectedException, IOException; /** * Creates a port forwarding between a local and a remote port. + * * @param localPort the local port to forward * @param remotePort the remote port. * @return <code>true</code> if success. + * @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. */ - public boolean createForward(int localPort, int remotePort); + public void createForward(int localPort, int remotePort) + throws TimeoutException, AdbCommandRejectedException, IOException; /** * Removes a port forwarding between a local and a remote port. + * * @param localPort the local port to forward * @param remotePort the remote port. * @return <code>true</code> if success. + * @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. */ - public boolean removeForward(int localPort, int remotePort); + public void removeForward(int localPort, int remotePort) + throws TimeoutException, AdbCommandRejectedException, IOException; /** * Returns the name of the client by pid or <code>null</code> if pid is unknown @@ -280,57 +318,84 @@ public interface IDevice { * Installs an Android application on device. * This is a helper method that combines the syncPackageToDevice, installRemotePackage, * and removePackage steps + * * @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. */ public String installPackage(String packageFilePath, boolean reinstall) - throws TimeoutException, IOException; + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException; /** * Pushes a file to device + * * @param localFilePath the absolute path to file on local host * @return {@link String} destination path on device for file * @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. */ public String syncPackageToDevice(String localFilePath) - throws TimeoutException, IOException; + throws TimeoutException, AdbCommandRejectedException, IOException; /** * 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 */ public String installRemotePackage(String remoteFilePath, boolean reinstall) - throws TimeoutException, IOException; + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException; /** - * Remove a file from device + * 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 */ - public void removeRemotePackage(String remoteFilePath) throws TimeoutException, IOException; + public void removeRemotePackage(String remoteFilePath) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException; /** - * Uninstall an package from the device. + * 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 */ - public String uninstallPackage(String packageName) throws TimeoutException, IOException; + public String uninstallPackage(String packageName) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException; /** * Reboot the device. * * @param into the bootloader name to reboot into, or null to just reboot the device. + * @throws TimeoutException in case of timeout on the connection. + * @throws AdbCommandRejectedException if adb rejects the command * @throws IOException */ - public void reboot(String into) throws TimeoutException, IOException; + public void reboot(String into) + throws TimeoutException, AdbCommandRejectedException, IOException; } diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/ShellCommandUnresponsiveException.java b/ddms/libs/ddmlib/src/com/android/ddmlib/ShellCommandUnresponsiveException.java new file mode 100644 index 0000000..2dc5d3a --- /dev/null +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/ShellCommandUnresponsiveException.java @@ -0,0 +1,28 @@ +/* + * 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 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 { + private static final long serialVersionUID = 1L; +} diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java b/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java index e4740d0..d2b8af3 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java @@ -214,9 +214,10 @@ public final class SyncService { * @return true if the connection opened, false if adb refuse the connection. This can happen * if the {@link Device} is invalid. * @throws TimeoutException in case of timeout on the connection. + * @throws AdbCommandRejectedException if adb rejects the command * @throws IOException If the connection to adb failed. */ - boolean openSync() throws TimeoutException, IOException { + boolean openSync() throws TimeoutException, AdbCommandRejectedException, IOException { try { mChannel = SocketChannel.open(mAddress); mChannel.configureBlocking(false); diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java index a478216..7cb6557 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java @@ -17,6 +17,8 @@ package com.android.ddmlib.testrunner; import com.android.ddmlib.IDevice; +import com.android.ddmlib.AdbCommandRejectedException; +import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; import java.io.IOException; @@ -171,13 +173,17 @@ public interface IRemoteAndroidTestRunner { public void setCoverage(boolean coverage); /** - * Sets the timeout to use for the adb shell command issued. + * Sets the maximum time allowed between output of the shell command running the tests on + * the devices. + * <p/> + * This allows setting a timeout in case the tests can become stuck and never finish. This is + * different from the normal timeout on the connection. * <p/> * By default no timeout will be specified. * * @see {@link IDevice#executeShellCommand(String, com.android.ddmlib.IShellOutputReceiver, int)} */ - public void setTimeout(int timeout); + public void setMaxtimeToOutputResponse(int maxTimeToOutputResponse); /** * Execute this test run. @@ -186,18 +192,32 @@ public interface IRemoteAndroidTestRunner { * * @param listeners listens for test results * @throws TimeoutException in case of a timeout on the connection. + * @throws AdbCommandRejectedException if adb rejects the command + * @throws ShellCommandUnresponsiveException if the device did not output any test result for + * a period longer than the max time to output. * @throws IOException if connection to device was lost. + * + * @see #setMaxtimeToOutputResponse(int) */ - public void run(ITestRunListener... listeners) throws TimeoutException, IOException; + public void run(ITestRunListener... listeners) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException; /** * Execute this test run. * * @param listeners collection of listeners for test results * @throws TimeoutException in case of a timeout on the connection. + * @throws AdbCommandRejectedException if adb rejects the command + * @throws ShellCommandUnresponsiveException if the device did not output any test result for + * a period longer than the max time to output. * @throws IOException if connection to device was lost. + * + * @see #setMaxtimeToOutputResponse(int) */ - public void run(Collection<ITestRunListener> listeners) throws TimeoutException, IOException; + public void run(Collection<ITestRunListener> listeners) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException; /** * Requests cancellation of this test run. diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java index 9fd3fbf..681c214 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java @@ -19,6 +19,8 @@ package com.android.ddmlib.testrunner; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; +import com.android.ddmlib.AdbCommandRejectedException; +import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; import java.io.IOException; @@ -37,7 +39,7 @@ public class RemoteAndroidTestRunner implements IRemoteAndroidTestRunner { private final String mRunnerName; private IDevice mRemoteDevice; // default to no timeout - private int mAdbTimeout = 0; + private int mMaxTimeToOutputResponse = 0; /** map of name-value instrumentation argument pairs */ private Map<String, String> mArgMap; @@ -205,28 +207,32 @@ public class RemoteAndroidTestRunner implements IRemoteAndroidTestRunner { /** * {@inheritDoc} */ - public void setTimeout(int timeout) { - mAdbTimeout = timeout; + public void setMaxtimeToOutputResponse(int maxTimeToOutputResponse) { + mMaxTimeToOutputResponse = maxTimeToOutputResponse; } /** * {@inheritDoc} */ - public void run(ITestRunListener... listeners) throws IOException, TimeoutException { + public void run(ITestRunListener... listeners) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { run(Arrays.asList(listeners)); } /** * {@inheritDoc} */ - public void run(Collection<ITestRunListener> listeners) throws TimeoutException, IOException { + public void run(Collection<ITestRunListener> listeners) + throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, + IOException { final String runCaseCommandStr = String.format("am instrument -w -r %s %s", getArgsCommand(), getRunnerPath()); Log.i(LOG_TAG, String.format("Running %s on %s", runCaseCommandStr, mRemoteDevice.getSerialNumber())); mParser = new InstrumentationResultParser(listeners); - mRemoteDevice.executeShellCommand(runCaseCommandStr, mParser, mAdbTimeout); + mRemoteDevice.executeShellCommand(runCaseCommandStr, mParser, mMaxTimeToOutputResponse); } /** 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 a884c3b..85b57aa 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 @@ -144,7 +144,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase { return mLastShellCommand; } - public boolean createForward(int localPort, int remotePort) { + public void createForward(int localPort, int remotePort) { throw new UnsupportedOperationException(); } @@ -216,7 +216,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase { throw new UnsupportedOperationException(); } - public boolean removeForward(int localPort, int remotePort) { + public void removeForward(int localPort, int remotePort) { throw new UnsupportedOperationException(); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/ActivityLaunchAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/ActivityLaunchAction.java index d1502d3..0a6257f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/ActivityLaunchAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/ActivityLaunchAction.java @@ -16,7 +16,10 @@ package com.android.ide.eclipse.adt.internal.launch; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.IDevice; +import com.android.ddmlib.ShellCommandUnresponsiveException; +import com.android.ddmlib.TimeoutException; import com.android.ide.eclipse.adt.AdtPlugin; import java.io.IOException; @@ -49,8 +52,16 @@ public class ActivityLaunchAction implements IAndroidLaunchAction { * @see IAndroidLaunchAction#doLaunchAction(DelayedLaunchInfo, IDevice) */ public boolean doLaunchAction(DelayedLaunchInfo info, IDevice device) { + String command = "am start" //$NON-NLS-1$ + + (info.isDebugMode() ? " -D" //$NON-NLS-1$ + : "") //$NON-NLS-1$ + + " -n " //$NON-NLS-1$ + + info.getPackageName() + "/" //$NON-NLS-1$ + + mActivity.replaceAll("\\$", "\\\\\\$") //$NON-NLS-1$ //$NON-NLS-2$ + + " -a android.intent.action.MAIN" //$NON-NLS-1$ + + " -c android.intent.category.LAUNCHER"; try { - String msg = String.format("Starting activity %1$s on device ", mActivity, + String msg = String.format("Starting activity %1$s on device %2$s", mActivity, device); AdtPlugin.printToConsole(info.getProject(), msg); @@ -60,15 +71,7 @@ public class ActivityLaunchAction implements IAndroidLaunchAction { info.incrementAttemptCount(); // now we actually launch the app. - device.executeShellCommand("am start" //$NON-NLS-1$ - + (info.isDebugMode() ? " -D" //$NON-NLS-1$ - : "") //$NON-NLS-1$ - + " -n " //$NON-NLS-1$ - + info.getPackageName() + "/" //$NON-NLS-1$ - + mActivity.replaceAll("\\$", "\\\\\\$") //$NON-NLS-1$ //$NON-NLS-2$ - + " -a android.intent.action.MAIN" //$NON-NLS-1$ - + " -c android.intent.category.LAUNCHER", //$NON-NLS-1$ - new AMReceiver(info, device, mLaunchController)); + device.executeShellCommand(command, new AMReceiver(info, device, mLaunchController)); // if the app is not a debug app, we need to do some clean up, as // the process is done! @@ -77,6 +80,17 @@ public class ActivityLaunchAction implements IAndroidLaunchAction { // provide any control over the app return false; } + } catch (TimeoutException e) { + AdtPlugin.printErrorToConsole(info.getProject(), "Launch error: timeout"); + return false; + } catch (AdbCommandRejectedException e) { + AdtPlugin.printErrorToConsole(info.getProject(), String.format( + "Launch error: adb rejected command: %1$s", e.getMessage())); + return false; + } catch (ShellCommandUnresponsiveException e) { + // we didn't get the output but that's ok, just log it + AdtPlugin.log(e, "No command output when running: '%1$s' on device %2$s", command, + device); } catch (IOException e) { // something went wrong trying to launch the app. // lets stop the Launch diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java b/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java index 0f60be6..209577d 100644 --- a/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java +++ b/hierarchyviewer/src/com/android/hierarchyviewer/device/DeviceBridge.java @@ -16,10 +16,12 @@ package com.android.hierarchyviewer.device; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; import com.android.ddmlib.MultiLineReceiver; +import com.android.ddmlib.TimeoutException; import java.io.IOException; import java.io.File; @@ -120,8 +122,20 @@ public class DeviceBridge { synchronized (devicePortMap) { if (device.getState() == IDevice.DeviceState.ONLINE) { int localPort = nextLocalPort++; - device.createForward(localPort, Configuration.DEFAULT_SERVER_PORT); - devicePortMap.put(device, localPort); + try { + device.createForward(localPort, Configuration.DEFAULT_SERVER_PORT); + devicePortMap.put(device, localPort); + } catch (TimeoutException e) { + Log.e("hierarchy", "Timeout setting up port forwarding for " + device); + } catch (AdbCommandRejectedException e) { + Log.e("hierarchy", String.format( + "Adb rejected forward command for device %1$s: %2$s", + device, e.getMessage())); + } catch (IOException e) { + Log.e("hierarchy", String.format( + "Failed to create forward for device %1$s: %2$s", + device, e.getMessage())); + } } } } @@ -130,8 +144,20 @@ public class DeviceBridge { synchronized (devicePortMap) { final Integer localPort = devicePortMap.get(device); if (localPort != null) { - device.removeForward(localPort, Configuration.DEFAULT_SERVER_PORT); - devicePortMap.remove(device); + try { + device.removeForward(localPort, Configuration.DEFAULT_SERVER_PORT); + devicePortMap.remove(device); + } catch (TimeoutException e) { + Log.e("hierarchy", "Timeout removing port forwarding for " + device); + } catch (AdbCommandRejectedException e) { + Log.e("hierarchy", String.format( + "Adb rejected remove-forward command for device %1$s: %2$s", + device, e.getMessage())); + } catch (IOException e) { + Log.e("hierarchy", String.format( + "Failed to remove forward for device %1$s: %2$s", + device, e.getMessage())); + } } } } |