Add ITestDevice methods waitForDeviceOnline and getExternalStoreFreeSpace.
Change-Id: I1ab3ec4c99889f71b22e52cd675ee32511cc689b
diff --git a/src/com/android/tradefed/device/DeviceFatalError.java b/src/com/android/tradefed/device/DeviceFatalError.java
index b66a93a..41bb8c4 100644
--- a/src/com/android/tradefed/device/DeviceFatalError.java
+++ b/src/com/android/tradefed/device/DeviceFatalError.java
@@ -31,7 +31,7 @@
*
* @param msg a descriptive error message of the error
*/
- DeviceFatalError(String msg) {
+ public DeviceFatalError(String msg) {
super(msg);
}
}
diff --git a/src/com/android/tradefed/device/DeviceStateMonitor.java b/src/com/android/tradefed/device/DeviceStateMonitor.java
index 8deebce..f1a72ef 100644
--- a/src/com/android/tradefed/device/DeviceStateMonitor.java
+++ b/src/com/android/tradefed/device/DeviceStateMonitor.java
@@ -41,7 +41,6 @@
private static final int FASTBOOT_POLL_ATTEMPTS = 5;
-
/** the ratio of time to wait for device to be online vs responsive in
* {@link DeviceManager#waitForDeviceAvailable(ITestDevice, long)}.
*/
@@ -49,7 +48,7 @@
/** The time in ms to wait for a device to boot. */
// TODO: make this configurable - or auto-scale according to device performance ?
- private static final int DEFAULT_BOOT_TIMEOUT = 4 * 60 * 1000;
+ private static final long DEFAULT_BOOT_TIMEOUT = 4 * 60 * 1000;
DeviceStateMonitor(IDevice device, IAndroidDebugBridge adbBridge) {
mDevice = device;
@@ -59,22 +58,29 @@
/**
* {@inheritDoc}
*/
- public boolean waitForDevice(long time) {
- return waitForDeviceState(TestDeviceState.ONLINE, time);
+ public boolean waitForDeviceOnline(long waitTime) {
+ return waitForDeviceState(TestDeviceState.ONLINE, waitTime);
}
/**
* {@inheritDoc}
*/
- public boolean waitForDeviceNotAvailable(long time) {
- return waitForDeviceState(TestDeviceState.NOT_AVAILABLE, time);
+ public boolean waitForDeviceOnline() {
+ return waitForDeviceOnline((long)(DEFAULT_BOOT_TIMEOUT*WAIT_DEVICE_RATIO));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean waitForDeviceNotAvailable(long waitTime) {
+ return waitForDeviceState(TestDeviceState.NOT_AVAILABLE, waitTime);
}
/**
* {@inheritDoc}
*/
public boolean waitForDeviceAvailable(final long waitTime) {
- if (waitForDevice((long)(waitTime*WAIT_DEVICE_RATIO))) {
+ if (waitForDeviceOnline((long)(waitTime*WAIT_DEVICE_RATIO))) {
return waitForPmResponsive((long)(waitTime*(1-WAIT_DEVICE_RATIO)));
}
return false;
diff --git a/src/com/android/tradefed/device/IDeviceStateMonitor.java b/src/com/android/tradefed/device/IDeviceStateMonitor.java
index 55a9cb4..c297258 100644
--- a/src/com/android/tradefed/device/IDeviceStateMonitor.java
+++ b/src/com/android/tradefed/device/IDeviceStateMonitor.java
@@ -33,7 +33,18 @@
*
* @return <code>true</code> if device becomes online before time expires
*/
- public boolean waitForDevice(long time);
+ public boolean waitForDeviceOnline(long time);
+
+ /**
+ * Waits for device to be online using standard boot timeout.
+ * <p/>
+ * Note: this method will return once device is visible via DDMS. It does not guarantee that the
+ * device is actually responsive to adb commands - use {@link #waitForDeviceAvailable()}
+ * instead.
+ *
+ * @return <code>true</code> if device becomes online before time expires
+ */
+ public boolean waitForDeviceOnline();
/**
* Waits for the device to be responsive and available for testing.
@@ -56,20 +67,20 @@
/**
* Waits for the device to be in bootloader.
*
- * @param time the maximum time in ms to wait
+ * @param waitTime the maximum time in ms to wait
*
* @return <code>true</code> if device is in bootloader before time expires
*/
- public boolean waitForDeviceBootloader(long time);
+ public boolean waitForDeviceBootloader(long waitTime);
/**
* Waits for the device to be not available
*
- * @param time the maximum time in ms to wait
+ * @param waitTime the maximum time in ms to wait
*
* @return <code>true</code> if device becomes unavailable
*/
- public boolean waitForDeviceNotAvailable(long time);
+ public boolean waitForDeviceNotAvailable(long waitTime);
/**
diff --git a/src/com/android/tradefed/device/ITestDevice.java b/src/com/android/tradefed/device/ITestDevice.java
index 78fc87b..b0a362d 100644
--- a/src/com/android/tradefed/device/ITestDevice.java
+++ b/src/com/android/tradefed/device/ITestDevice.java
@@ -146,6 +146,15 @@
public boolean doesFileExist(String deviceFilePath) throws DeviceNotAvailableException;
/**
+ * Helper method to determine amount of free space on device external storage.
+ *
+ * @return the amount of free space in KB
+ * @throws DeviceNotAvailableException if connection with device is lost and cannot be
+ * recovered.
+ */
+ public long getExternalStoreFreeSpace() throws DeviceNotAvailableException;
+
+ /**
* Grabs a snapshot stream of the logcat data.
*/
public InputStream getLogcat();
@@ -191,4 +200,13 @@
* recovered.
*/
public void waitForDeviceAvailable() throws DeviceNotAvailableException;
+
+ /**
+ * Waits for the device to be visible via adb. Note the device may not necessarily be
+ * responsive to commands.
+ *
+ * @throws DeviceNotAvailableException if connection with device is lost and cannot be
+ * recovered.
+ */
+ public void waitForDeviceOnline() throws DeviceNotAvailableException;
}
diff --git a/src/com/android/tradefed/device/TestDevice.java b/src/com/android/tradefed/device/TestDevice.java
index 50e6df2..3435c57 100644
--- a/src/com/android/tradefed/device/TestDevice.java
+++ b/src/com/android/tradefed/device/TestDevice.java
@@ -34,6 +34,8 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Default implementation of a {@link ITestDevice}
@@ -204,11 +206,7 @@
}
/**
- * Helper method to determine if file on device exists.
- *
- * @param destPath the absolute path of file on device to check
- * @return <code>true</code> if file exists, <code>false</code> otherwise.
- * @throws DeviceNotAvailableException if device communication is lost
+ * {@inheritDoc}
*/
public boolean doesFileExist(String destPath) throws DeviceNotAvailableException {
String lsGrep = executeShellCommand(String.format("ls \"%s\"", destPath));
@@ -218,6 +216,28 @@
/**
* {@inheritDoc}
*/
+ public long getExternalStoreFreeSpace() throws DeviceNotAvailableException {
+ String externalStorePath = getIDevice().getMountPoint(
+ IDevice.MNT_EXTERNAL_STORAGE);
+ String output = executeShellCommand(String.format("df %s", externalStorePath));
+ final Pattern freeSpacePattern = Pattern.compile("(\\d+)K available");
+ Matcher patternMatcher = freeSpacePattern.matcher(output);
+ if (patternMatcher.find()) {
+ String freeSpaceString = patternMatcher.group(1);
+ try {
+ return Long.parseLong(freeSpaceString);
+ } catch (NumberFormatException e) {
+ // fall through
+ }
+ }
+ Log.e(LOG_TAG, String.format(
+ "free space command output \"%s\" did not match expected pattern ", output));
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public String executeAdbCommand(String... cmdArgs) throws DeviceNotAvailableException {
final String[] fullCmd = buildAdbCommand(cmdArgs);
final String[] output = new String[1];
@@ -626,6 +646,16 @@
return true;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public void waitForDeviceOnline() throws DeviceNotAvailableException {
+ if (!mMonitor.waitForDeviceOnline()) {
+ recoverDevice();
+ }
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/com/android/tradefed/device/WaitDeviceRecovery.java b/src/com/android/tradefed/device/WaitDeviceRecovery.java
index 6551b35..1c70bdf 100644
--- a/src/com/android/tradefed/device/WaitDeviceRecovery.java
+++ b/src/com/android/tradefed/device/WaitDeviceRecovery.java
@@ -35,8 +35,6 @@
description="maximum time in ms to wait for a single device recovery command")
private long mWaitTime = 4 * 60 * 1000;
-
-
/**
* {@inheritDoc}
*/
@@ -50,7 +48,7 @@
RunUtil.sleep(INITIAL_PAUSE_TIME);
// wait for device online
- if (!monitor.waitForDevice(mWaitTime)) {
+ if (!monitor.waitForDeviceOnline(mWaitTime)) {
throw new DeviceNotAvailableException(String.format("Could not find device %s",
device.getSerialNumber()));
}
@@ -70,7 +68,7 @@
// wait for device in bootloader
if (!monitor.waitForDeviceBootloader(mWaitTime)) {
throw new DeviceNotAvailableException(String.format("Could not find device %s in" +
- "bootloader", device.getSerialNumber()));
+ "bootloader", device.getSerialNumber()));
}
}
}
diff --git a/tests/src/com/android/tradefed/device/StubTestDevice.java b/tests/src/com/android/tradefed/device/StubTestDevice.java
index f113f3e..71c05ac 100644
--- a/tests/src/com/android/tradefed/device/StubTestDevice.java
+++ b/tests/src/com/android/tradefed/device/StubTestDevice.java
@@ -157,6 +157,19 @@
*/
public void waitForDeviceAvailable() throws DeviceNotAvailableException {
// ignore
+ }
+ /**
+ * {@inheritDoc}
+ */
+ public void waitForDeviceOnline() throws DeviceNotAvailableException {
+ // ignore
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getExternalStoreFreeSpace() throws DeviceNotAvailableException {
+ return 0;
}
}
diff --git a/tests/src/com/android/tradefed/device/TestDeviceTest.java b/tests/src/com/android/tradefed/device/TestDeviceTest.java
index 18649a0..4e8be37 100644
--- a/tests/src/com/android/tradefed/device/TestDeviceTest.java
+++ b/tests/src/com/android/tradefed/device/TestDeviceTest.java
@@ -165,6 +165,62 @@
}
/**
+ * Unit test for {@link TestDevice#getExternalStoreFreeSpace()}.
+ * <p/>
+ * Verify that output of 'adb shell df' command is parsed correctly.
+ */
+ public void testGetExternalStoreFreeSpace() throws Exception {
+ final String mntPoint = "/mnt/sdcard";
+ final String expectedCmd = "df " + mntPoint;
+ final String dfOutput =
+ "/mnt/sdcard: 3864064K total, 1282880K used, 2581184K available (block size 32768)";
+
+ EasyMock.expect(mMockIDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).andReturn(
+ mntPoint);
+ // expect shell command to be called, and return the test df output
+ mMockIDevice.executeShellCommand(EasyMock.eq(expectedCmd), (IShellOutputReceiver)
+ EasyMock.anyObject());
+ EasyMock.expectLastCall().andDelegateTo(
+ new MockDevice() {
+ @Override
+ public void executeShellCommand(String cmd, IShellOutputReceiver receiver) {
+ byte[] inputData = dfOutput.getBytes();
+ receiver.addOutput(inputData, 0, inputData.length);
+ }
+ });
+ EasyMock.replay(mMockIDevice);
+ assertEquals(2581184, mTestDevice.getExternalStoreFreeSpace());
+ }
+
+ /**
+ * Unit test for {@link TestDevice#getExternalStoreFreeSpace()}.
+ * <p/>
+ * Verify behavior
+ */
+ public void testGetExternalStoreFreeSpace_badOutput() throws Exception {
+ final String mntPoint = "/mnt/sdcard";
+ final String expectedCmd = "df " + mntPoint;
+ final String dfOutput =
+ "/mnt/sdcard: blaH";
+
+ EasyMock.expect(mMockIDevice.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).andReturn(
+ mntPoint);
+ // expect shell command to be called, and return the test df output
+ mMockIDevice.executeShellCommand(EasyMock.eq(expectedCmd), (IShellOutputReceiver)
+ EasyMock.anyObject());
+ EasyMock.expectLastCall().andDelegateTo(
+ new MockDevice() {
+ @Override
+ public void executeShellCommand(String cmd, IShellOutputReceiver receiver) {
+ byte[] inputData = dfOutput.getBytes();
+ receiver.addOutput(inputData, 0, inputData.length);
+ }
+ });
+ EasyMock.replay(mMockIDevice);
+ assertEquals(0, mTestDevice.getExternalStoreFreeSpace());
+ }
+
+ /**
* Test {@link TestDevice#runInstrumentationTests(IRemoteAndroidTestRunner, Collection)}
* success case.
*/