diff options
author | Julien Desprez <jdesprez@google.com> | 2016-08-12 11:48:32 +0100 |
---|---|---|
committer | Julien Desprez <jdesprez@google.com> | 2016-08-22 10:19:18 +0100 |
commit | 07fe153f8db0a42254a9d9e8672a7b1bd426373b (patch) | |
tree | 82e62796436140bebc89beceec56d409983e3611 /src/com | |
parent | 5ada7dafccc3af427bb32d240e9bb3e16ee911d0 (diff) | |
download | tradefederation-07fe153f8db0a42254a9d9e8672a7b1bd426373b.tar.gz |
BuildError and TargetSetupError track Serial
Add tracking of device serial for these two exception to
target more precisely the origin for multi device.
Bug: 29043852
Change-Id: Ie9fc1541884b10d51f6822f7fe7cc57e2f9c13d1
Diffstat (limited to 'src/com')
40 files changed, 339 insertions, 171 deletions
diff --git a/src/com/android/tradefed/device/INativeDevice.java b/src/com/android/tradefed/device/INativeDevice.java index be6bf2bb9..70e7bf88e 100644 --- a/src/com/android/tradefed/device/INativeDevice.java +++ b/src/com/android/tradefed/device/INativeDevice.java @@ -20,6 +20,7 @@ import com.android.ddmlib.IShellOutputReceiver; import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; import com.android.ddmlib.testrunner.ITestRunListener; import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.command.remote.DeviceDescriptor; import com.android.tradefed.device.ITestDevice.MountPointInfo; import com.android.tradefed.device.ITestDevice.RecoveryMode; import com.android.tradefed.log.ITestLogger; @@ -1034,4 +1035,10 @@ public interface INativeDevice { * Return true if the device is headless (no screen), false otherwise. */ public boolean isHeadless() throws DeviceNotAvailableException; + + /** + * Return a {@link DeviceDescriptor} from the device information to get info on it without + * passing the actual device object. + */ + public DeviceDescriptor getDeviceDescriptor(); } diff --git a/src/com/android/tradefed/device/NativeDevice.java b/src/com/android/tradefed/device/NativeDevice.java index 5b76b6578..f2157b5fb 100644 --- a/src/com/android/tradefed/device/NativeDevice.java +++ b/src/com/android/tradefed/device/NativeDevice.java @@ -31,6 +31,7 @@ import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; import com.android.ddmlib.testrunner.ITestRunListener; import com.android.ddmlib.testrunner.RemoteAndroidTestRunner; import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.command.remote.DeviceDescriptor; import com.android.tradefed.log.ITestLogger; import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.result.ByteArrayInputStreamSource; @@ -3536,4 +3537,29 @@ public class NativeDevice implements IManagedTestDevice { throw new RuntimeException("Device became unavailable while checking API level", e); } } + + /** + * {@inheritDoc} + */ + @Override + public DeviceDescriptor getDeviceDescriptor() { + IDeviceSelection selector = new DeviceSelectionOptions(); + IDevice idevice = getIDevice(); + return new DeviceDescriptor(idevice.getSerialNumber(), + idevice instanceof StubDevice, + getAllocationState(), + getDisplayString(selector.getDeviceProductType(idevice)), + getDisplayString(selector.getDeviceProductVariant(idevice)), + getDisplayString(idevice.getProperty("ro.build.version.sdk")), + getDisplayString(idevice.getProperty("ro.build.id")), + getDisplayString(selector.getBatteryLevel(idevice)), + getDeviceClass()); + } + + /** + * Return the displayable string for given object + */ + private String getDisplayString(Object o) { + return o == null ? "unknown" : o.toString(); + } } diff --git a/src/com/android/tradefed/invoker/TestInvocation.java b/src/com/android/tradefed/invoker/TestInvocation.java index 8faec128d..6cba5783b 100644 --- a/src/com/android/tradefed/invoker/TestInvocation.java +++ b/src/com/android/tradefed/invoker/TestInvocation.java @@ -501,6 +501,7 @@ public class TestInvocation implements ITestInvocation { long elapsedTime = -1; Throwable exception = null; Throwable tearDownException = null; + ITestDevice badDevice = null; // TODO: Fix reporting on more than just first build info. IBuildInfo reportingBuildInfo = context.getBuildInfos().get(0); @@ -511,11 +512,16 @@ public class TestInvocation implements ITestInvocation { prepareAndRun(config, context, listener); } catch (BuildError e) { exception = e; - // TODO: be specific on which build and device. - CLog.w("Build failed on device. Reason: %s", e.toString()); + CLog.w("Build failed on device '%s'. Reason: %s", e.getDeviceDescriptor(), + e.toString()); bugreportName = BUILD_ERROR_BUGREPORT_NAME; + badDevice = context.getDeviceBySerial(e.getDeviceDescriptor().getSerial()); if (e instanceof DeviceFailedToBootError) { - context.setRecoveryModeForAllDevices(RecoveryMode.NONE); + if (badDevice == null) { + context.setRecoveryModeForAllDevices(RecoveryMode.NONE); + } else { + badDevice.setRecoveryMode(RecoveryMode.NONE); + } } reportFailure(e, listener, config, context, rescheduler); } catch (TargetSetupError e) { @@ -523,13 +529,14 @@ public class TestInvocation implements ITestInvocation { CLog.e("Caught exception while running invocation"); CLog.e(e); bugreportName = TARGET_SETUP_ERROR_BUGREPORT_NAME; + badDevice = context.getDeviceBySerial(e.getDeviceDescriptor().getSerial()); reportFailure(e, listener, config, context, rescheduler); } catch (DeviceNotAvailableException e) { exception = e; // log a warning here so its captured before reportLogs is called CLog.w("Invocation did not complete due to device %s becoming not available. " + "Reason: %s", e.getSerial(), e.getMessage()); - ITestDevice badDevice = context.getDeviceBySerial(e.getSerial()); + badDevice = context.getDeviceBySerial(e.getSerial()); if ((e instanceof DeviceUnresponsiveException) && badDevice != null && TestDeviceState.ONLINE.equals(badDevice.getDeviceState())) { // under certain cases it might still be possible to grab a bugreport @@ -543,7 +550,9 @@ public class TestInvocation implements ITestInvocation { } // Upon reaching here after an exception, it is safe to assume that recovery // has already been attempted so we disable it to avoid re-entry during clean up. - badDevice.setRecoveryMode(RecoveryMode.NONE); + if (badDevice != null) { + badDevice.setRecoveryMode(RecoveryMode.NONE); + } throw e; } catch (RunInterruptedException e) { CLog.w("Invocation interrupted"); @@ -570,9 +579,14 @@ public class TestInvocation implements ITestInvocation { } } if (bugreportName != null) { - // TODO: take bugreport only on the faulty device, or all in multi target preparer - // issues. - takeBugreport(context, listener, bugreportName); + if (badDevice == null) { + for (ITestDevice device : context.getDevices()) { + takeBugreport(device, listener, bugreportName); + } + } else { + // If we have identified a faulty device only take the bugreport on it. + takeBugreport(badDevice, listener, bugreportName); + } } mStatus = "tearing down"; try { @@ -838,28 +852,25 @@ public class TestInvocation implements ITestInvocation { globalLogSource.cancel(); } - private void takeBugreport(IInvocationContext context, ITestInvocationListener listener, + private void takeBugreport(ITestDevice device, ITestInvocationListener listener, String bugreportName) { - for (ITestDevice device : context.getDevices()) { - if (device == null) { - return; - } - if (device.getIDevice() instanceof StubDevice) { - return; - } - - InputStreamSource bugreport = device.getBugreport(); - try { - if (bugreport != null) { - listener.testLog(String.format("%s_%s", bugreportName, - device.getSerialNumber()), LogDataType.BUGREPORT, bugreport); - } else { - CLog.w("Error when collecting bugreport for device '%s'", - device.getSerialNumber()); - } - } finally { - StreamUtil.cancel(bugreport); + if (device == null) { + return; + } + if (device.getIDevice() instanceof StubDevice) { + return; + } + InputStreamSource bugreport = device.getBugreport(); + try { + if (bugreport != null) { + listener.testLog(String.format("%s_%s", bugreportName, + device.getSerialNumber()), LogDataType.BUGREPORT, bugreport); + } else { + CLog.w("Error when collecting bugreport for device '%s'", + device.getSerialNumber()); } + } finally { + StreamUtil.cancel(bugreport); } } diff --git a/src/com/android/tradefed/targetprep/AdditionalFilesInstaller.java b/src/com/android/tradefed/targetprep/AdditionalFilesInstaller.java index 8e098aef8..e48460eab 100644 --- a/src/com/android/tradefed/targetprep/AdditionalFilesInstaller.java +++ b/src/com/android/tradefed/targetprep/AdditionalFilesInstaller.java @@ -52,7 +52,7 @@ public class AdditionalFilesInstaller implements ITargetPreparer, ITargetCleaner CLog.d("Pushing %s to %s", file.getName(), remotePath); if (!device.pushFile(file, remotePath)) { throw new TargetSetupError(String.format("Failed to push %s to %s", - file.getName(), remotePath)); + file.getName(), remotePath), device.getDeviceDescriptor()); } } } @@ -87,7 +87,8 @@ public class AdditionalFilesInstaller implements ITargetPreparer, ITargetCleaner return; } } - throw new TargetSetupError(String.format("failed to remove files from %s", DEST_PATH)); + throw new TargetSetupError(String.format("failed to remove files from %s", DEST_PATH), + device.getDeviceDescriptor()); } } diff --git a/src/com/android/tradefed/targetprep/AllTestAppsInstallSetup.java b/src/com/android/tradefed/targetprep/AllTestAppsInstallSetup.java index d3e130f20..30210947e 100644 --- a/src/com/android/tradefed/targetprep/AllTestAppsInstallSetup.java +++ b/src/com/android/tradefed/targetprep/AllTestAppsInstallSetup.java @@ -73,12 +73,14 @@ public class AllTestAppsInstallSetup implements ITargetCleaner, IAbiReceiver { public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, DeviceNotAvailableException { if (!(buildInfo instanceof IDeviceBuildInfo)) { - throw new TargetSetupError("Invalid buildInfo, expecting an IDeviceBuildInfo"); + throw new TargetSetupError("Invalid buildInfo, expecting an IDeviceBuildInfo", + device.getDeviceDescriptor()); } // Locate test dir where the test zip file was unzip to. File testsDir = ((IDeviceBuildInfo) buildInfo).getTestsDir(); if (testsDir == null || !testsDir.exists()) { - throw new TargetSetupError("Failed to find a valid test zip directory."); + throw new TargetSetupError("Failed to find a valid test zip directory.", + device.getDeviceDescriptor()); } resolveAbi(device); installApksRecursively(testsDir, device); @@ -95,7 +97,7 @@ public class AllTestAppsInstallSetup implements ITargetCleaner, IAbiReceiver { void installApksRecursively(File directory, ITestDevice device) throws TargetSetupError, DeviceNotAvailableException { if (directory == null || !directory.isDirectory()) { - throw new TargetSetupError("Invalid test zip directory!"); + throw new TargetSetupError("Invalid test zip directory!", device.getDeviceDescriptor()); } CLog.d("Installing all apks found in dir %s ...", directory.getAbsolutePath()); File[] files = directory.listFiles(); @@ -129,14 +131,15 @@ public class AllTestAppsInstallSetup implements ITargetCleaner, IAbiReceiver { if (mCleanup) { AaptParser parser = AaptParser.parse(appFile); if (parser == null) { - throw new TargetSetupError("apk installed but AaptParser failed"); + throw new TargetSetupError("apk installed but AaptParser failed", + device.getDeviceDescriptor()); } mPackagesInstalled.add(parser.getPackageName()); } } else if (mStopInstallOnFailure) { // if flag is true, we stop the sequence for an exception. throw new TargetSetupError(String.format("Failed to install %s on %s. Reason: '%s'", - appFile, device.getSerialNumber(), result)); + appFile, device.getSerialNumber(), result), device.getDeviceDescriptor()); } else { CLog.e("Failed to install %s on %s. Reason: '%s'", appFile, device.getSerialNumber(), result); diff --git a/src/com/android/tradefed/targetprep/AppSetup.java b/src/com/android/tradefed/targetprep/AppSetup.java index 20e74dcfd..c2d27e527 100644 --- a/src/com/android/tradefed/targetprep/AppSetup.java +++ b/src/com/android/tradefed/targetprep/AppSetup.java @@ -108,7 +108,7 @@ public class AppSetup implements ITargetPreparer, ITargetCleaner { if (aaptParser == null) { throw new TargetSetupError( String.format("Failed to extract info from '%s' using aapt", - apkFile.toString())); + apkFile.toString()), device.getDeviceDescriptor()); } if (device.getApiLevel() < aaptParser.getSdkVersion()) { CLog.w("Skipping installing apk %s on device %s because " + @@ -126,10 +126,11 @@ public class AppSetup implements ITargetPreparer, ITargetCleaner { // devicenotavail depending on error code throw new BuildError(String.format( "Failed to install %s on %s. Reason: %s", - apkFile.getFile().getName(), device.getSerialNumber(), result)); + apkFile.getFile().getName(), device.getSerialNumber(), result), + device.getDeviceDescriptor()); } if (mUninstall && !mUninstallAll) { - addPackageNameToUninstall(apkFile.getFile()); + addPackageNameToUninstall(apkFile.getFile(), device); } } } @@ -145,15 +146,17 @@ public class AppSetup implements ITargetPreparer, ITargetCleaner { } } - private void addPackageNameToUninstall(File apkFile) throws TargetSetupError { + private void addPackageNameToUninstall(File apkFile, ITestDevice device) + throws TargetSetupError { AaptParser aaptParser = AaptParser.parse(apkFile); if (aaptParser == null) { throw new TargetSetupError(String.format("Failed to extract info from '%s' using aapt", - apkFile.getAbsolutePath())); + apkFile.getAbsolutePath()), device.getDeviceDescriptor()); } if (aaptParser.getPackageName() == null) { throw new TargetSetupError(String.format( - "Failed to find package name for '%s' using aapt", apkFile.getAbsolutePath())); + "Failed to find package name for '%s' using aapt", apkFile.getAbsolutePath()), + device.getDeviceDescriptor()); } mInstalledPkgs.add(aaptParser.getPackageName()); } diff --git a/src/com/android/tradefed/targetprep/BuildError.java b/src/com/android/tradefed/targetprep/BuildError.java index b2a4f75e0..55a3d0a10 100644 --- a/src/com/android/tradefed/targetprep/BuildError.java +++ b/src/com/android/tradefed/targetprep/BuildError.java @@ -15,18 +15,42 @@ */ package com.android.tradefed.targetprep; +import com.android.tradefed.command.remote.DeviceDescriptor; + /** * Thrown if the provided build fails to run. */ @SuppressWarnings("serial") public class BuildError extends Exception { + private DeviceDescriptor mDescriptor = null; + /** * Constructs a new (@link BuildError} with a detailed error message. * * @param reason an error message giving more details on the build error + * @param descriptor the descriptor of the device concerned */ + public BuildError(String reason, DeviceDescriptor descriptor) { + super(reason + " " + descriptor); + mDescriptor = descriptor; + } + + /** + * Constructs a new (@link BuildError} with a detailed error message. + * + * @param reason an error message giving more details on the build error + * @deprecated use {@link #BuildError(String, DeviceDescriptor)} instead. + */ + @Deprecated public BuildError(String reason) { super(reason); } + + /** + * Return the descriptor of the device associated with exception. + */ + public DeviceDescriptor getDeviceDescriptor() { + return mDescriptor; + } } diff --git a/src/com/android/tradefed/targetprep/CdmaDeviceFlasher.java b/src/com/android/tradefed/targetprep/CdmaDeviceFlasher.java index 47e2c6f07..db2d14663 100644 --- a/src/com/android/tradefed/targetprep/CdmaDeviceFlasher.java +++ b/src/com/android/tradefed/targetprep/CdmaDeviceFlasher.java @@ -165,7 +165,8 @@ public class CdmaDeviceFlasher extends FastbootDeviceFlasher { flashNamedPartition(device, updateDir, "recovery"); flashNamedPartition(device, updateDir, "system"); } catch (IOException e) { - throw new TargetSetupError(String.format("Got IOException: %s", e.getMessage())); + throw new TargetSetupError(String.format("Got IOException: %s", e.getMessage()), + device.getDeviceDescriptor()); } finally { if (updateDir != null) { FileUtil.recursiveDelete(updateDir); diff --git a/src/com/android/tradefed/targetprep/ConnectionChecker.java b/src/com/android/tradefed/targetprep/ConnectionChecker.java index 0a5095dba..44562ff7e 100644 --- a/src/com/android/tradefed/targetprep/ConnectionChecker.java +++ b/src/com/android/tradefed/targetprep/ConnectionChecker.java @@ -41,7 +41,8 @@ public class ConnectionChecker implements ITargetPreparer { long timeout = mTimeout * 1000; while (!device.checkConnectivity()) { if (System.currentTimeMillis() - startTime > timeout) { - throw new TargetSetupError("Device did not connect to the network"); + throw new TargetSetupError("Device did not connect to the network", + device.getDeviceDescriptor()); } RunUtil.getDefault().sleep(mInterval * 1000); } diff --git a/src/com/android/tradefed/targetprep/CpuThrottlingWaiter.java b/src/com/android/tradefed/targetprep/CpuThrottlingWaiter.java index a9aae9dfc..f370f9475 100644 --- a/src/com/android/tradefed/targetprep/CpuThrottlingWaiter.java +++ b/src/com/android/tradefed/targetprep/CpuThrottlingWaiter.java @@ -93,7 +93,8 @@ public class CpuThrottlingWaiter implements ITargetPreparer { "cat /sys/devices/system/cpu/*/cpufreq/cpuinfo_max_freq"); CLog.w("Current CPU frequencies:\n%s", result); if (mAbortOnTimeout) { - throw new TargetSetupError("cores are still throttled after wait timeout"); + throw new TargetSetupError("cores are still throttled after wait timeout", + device.getDeviceDescriptor()); } break; // while loop } diff --git a/src/com/android/tradefed/targetprep/DefaultTestsZipInstaller.java b/src/com/android/tradefed/targetprep/DefaultTestsZipInstaller.java index 96b4f1516..594bc813d 100644 --- a/src/com/android/tradefed/targetprep/DefaultTestsZipInstaller.java +++ b/src/com/android/tradefed/targetprep/DefaultTestsZipInstaller.java @@ -122,7 +122,7 @@ public class DefaultTestsZipInstaller implements ITestsZipInstaller { CLog.d("Syncing test files/apks"); File hostDir = new File(deviceBuild.getTestsDir(), "DATA"); - File[] hostDataFiles = getTestsZipDataFiles(hostDir); + File[] hostDataFiles = getTestsZipDataFiles(hostDir, device); for (File hostSubDir : hostDataFiles) { device.syncFiles(hostSubDir, DEVICE_DATA_PATH); } @@ -172,13 +172,14 @@ public class DefaultTestsZipInstaller implements ITestsZipInstaller { boolean yayTurtle = device.pushString("I like turtles", turtlePath); if (!yayTurtle) { throw new TargetSetupError(String.format("Failed userdata write check on device %s", - device.getSerialNumber())); + device.getSerialNumber()), device.getDeviceDescriptor()); } IFileEntry dataEntry = device.getFileEntry(FileListingService.DIRECTORY_DATA); if (dataEntry == null) { throw new TargetSetupError(String.format("Could not find %s folder on %s", - FileListingService.DIRECTORY_DATA, device.getSerialNumber())); + FileListingService.DIRECTORY_DATA, device.getSerialNumber()), + device.getDeviceDescriptor()); } for (IFileEntry dataSubDir : dataEntry.getChildren(false)) { if (!mDataWipeSkipList.contains(dataSubDir.getName())) { @@ -206,7 +207,7 @@ public class DefaultTestsZipInstaller implements ITestsZipInstaller { getRunUtil().sleep(1000 * i * i); } throw new TargetSetupError(String.format("Failed to delete dir %s. rm output: %s", - fullEscapedPath, result)); + fullEscapedPath, result), device.getDeviceDescriptor()); } /** @@ -235,14 +236,16 @@ public class DefaultTestsZipInstaller implements ITestsZipInstaller { * contents 'DATA' sub-folder * @return array of {@link File} */ - File[] getTestsZipDataFiles(File hostDir) throws TargetSetupError { + File[] getTestsZipDataFiles(File hostDir, ITestDevice device) throws TargetSetupError { if (!hostDir.isDirectory()) { - throw new TargetSetupError("Unrecognized tests.zip content: missing DATA folder"); + throw new TargetSetupError("Unrecognized tests.zip content: missing DATA folder", + device.getDeviceDescriptor()); } File[] childFiles = hostDir.listFiles(); if (childFiles == null || childFiles.length <= 0) { throw new TargetSetupError( - "Unrecognized tests.zip content: DATA folder has no content"); + "Unrecognized tests.zip content: DATA folder has no content", + device.getDeviceDescriptor()); } return childFiles; } diff --git a/src/com/android/tradefed/targetprep/DeviceFailedToBootError.java b/src/com/android/tradefed/targetprep/DeviceFailedToBootError.java index 284d719f0..9afa1724c 100644 --- a/src/com/android/tradefed/targetprep/DeviceFailedToBootError.java +++ b/src/com/android/tradefed/targetprep/DeviceFailedToBootError.java @@ -15,6 +15,8 @@ */ package com.android.tradefed.targetprep; +import com.android.tradefed.command.remote.DeviceDescriptor; + /** * Thrown if a device fails to boot after being flashed with a build. */ @@ -25,8 +27,9 @@ public class DeviceFailedToBootError extends BuildError { * Constructs a new (@link DeviceFailedToBootError} with a detailed error message. * * @param reason an error message giving more details about the boot failure + * @param descriptor the descriptor of the device concerned by the exception */ - public DeviceFailedToBootError(String reason) { - super(reason); + public DeviceFailedToBootError(String reason, DeviceDescriptor descriptor) { + super(reason, descriptor); } } diff --git a/src/com/android/tradefed/targetprep/DeviceFlashPreparer.java b/src/com/android/tradefed/targetprep/DeviceFlashPreparer.java index b4c35da0d..992daf344 100644 --- a/src/com/android/tradefed/targetprep/DeviceFlashPreparer.java +++ b/src/com/android/tradefed/targetprep/DeviceFlashPreparer.java @@ -258,7 +258,8 @@ public abstract class DeviceFlashPreparer implements ITargetCleaner { // assume this is a build problem throw new DeviceFailedToBootError(String.format( "Device %s did not become available after flashing %s", - device.getSerialNumber(), deviceBuild.getDeviceBuildId())); + device.getSerialNumber(), deviceBuild.getDeviceBuildId()), + device.getDeviceDescriptor()); } device.postBootSetup(); } finally { @@ -319,7 +320,8 @@ public abstract class DeviceFlashPreparer implements ITargetCleaner { return; case ENCRYPT: if (!device.isEncryptionSupported()) { - throw new TargetSetupError("Encryption is not supported"); + throw new TargetSetupError("Encryption is not supported", + device.getDeviceDescriptor()); } if (!device.isDeviceEncrypted()) { switch(flasher.getUserDataFlashOption()) { @@ -329,19 +331,23 @@ public abstract class DeviceFlashPreparer implements ITargetCleaner { // partition is expected to be cleared anyway, so we encrypt the device // with wipe if (!device.encryptDevice(false)) { - throw new TargetSetupError("Failed to encrypt device"); + throw new TargetSetupError("Failed to encrypt device", + device.getDeviceDescriptor()); } if (!device.unlockDevice()) { - throw new TargetSetupError("Failed to unlock device"); + throw new TargetSetupError("Failed to unlock device", + device.getDeviceDescriptor()); } break; case RETAIN: // original filesystem must be retained, so we encrypt in place if (!device.encryptDevice(true)) { - throw new TargetSetupError("Failed to encrypt device"); + throw new TargetSetupError("Failed to encrypt device", + device.getDeviceDescriptor()); } if (!device.unlockDevice()) { - throw new TargetSetupError("Failed to unlock device"); + throw new TargetSetupError("Failed to unlock device", + device.getDeviceDescriptor()); } break; default: @@ -374,26 +380,30 @@ public abstract class DeviceFlashPreparer implements ITargetCleaner { return; case ENCRYPT: if (!device.isEncryptionSupported()) { - throw new TargetSetupError("Encryption is not supported"); + throw new TargetSetupError("Encryption is not supported", + device.getDeviceDescriptor()); } switch(flasher.getUserDataFlashOption()) { case FLASH: if (!device.encryptDevice(true)) { - throw new TargetSetupError("Failed to encrypt device"); + throw new TargetSetupError("Failed to encrypt device", + device.getDeviceDescriptor()); } break; case WIPE: // Intentional fall through. case FORCE_WIPE: // since the device was just wiped, encrypt with wipe if (!device.encryptDevice(false)) { - throw new TargetSetupError("Failed to encrypt device"); + throw new TargetSetupError("Failed to encrypt device", + device.getDeviceDescriptor()); } break; default: // Do nothing, userdata was encrypted pre-flash. } if (!device.unlockDevice()) { - throw new TargetSetupError("Failed to unlock device"); + throw new TargetSetupError("Failed to unlock device", + device.getDeviceDescriptor()); } break; default: diff --git a/src/com/android/tradefed/targetprep/DeviceSetup.java b/src/com/android/tradefed/targetprep/DeviceSetup.java index 23d5ca79b..eda8b3672 100644 --- a/src/com/android/tradefed/targetprep/DeviceSetup.java +++ b/src/com/android/tradefed/targetprep/DeviceSetup.java @@ -372,11 +372,11 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { if (!device.enableAdbRoot()) { throw new TargetSetupError(String.format("Failed to enable adb root on %s", - device.getSerialNumber())); + device.getSerialNumber()), device.getDeviceDescriptor()); } // Convert deprecated options into current options - processDeprecatedOptions(); + processDeprecatedOptions(device); // Convert options into settings and run commands processOptions(device); // Change system props (will reboot device) @@ -438,11 +438,11 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { * </p> * @throws TargetSetupError if there is a conflict */ - public void processDeprecatedOptions() throws TargetSetupError { + public void processDeprecatedOptions(ITestDevice device) throws TargetSetupError { if (mDeprecatedMinExternalStoreSpace != DEFAULT_MIN_EXTERNAL_STORAGE_KB) { if (mMinExternalStorageKb != DEFAULT_MIN_EXTERNAL_STORAGE_KB) { throw new TargetSetupError("Deprecated option min-external-store-space conflicts " + - "with option min-external-storage-kb"); + "with option min-external-storage-kb", device.getDeviceDescriptor()); } mMinExternalStorageKb = mDeprecatedMinExternalStoreSpace; } @@ -450,7 +450,7 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { if (mDeprecatedSetAudioSilent != DEFAULT_DISABLE_AUDIO) { if (mDisableAudio != DEFAULT_DISABLE_AUDIO) { throw new TargetSetupError("Deprecated option audio-silent conflicts with " + - "option disable-audio"); + "option disable-audio", device.getDeviceDescriptor()); } mDisableAudio = mDeprecatedSetAudioSilent; } @@ -458,7 +458,7 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { if (!mDeprecatedSetProps.isEmpty()) { if (!mSetProps.isEmpty()) { throw new TargetSetupError("Deprecated option setprop conflicts with option " + - "set-property "); + "set-property ", device.getDeviceDescriptor()); } for (String prop : mDeprecatedSetProps) { String[] parts = prop.split("=", 2); @@ -502,7 +502,7 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { if (mScreenBrightness != null && BinaryState.ON.equals(mScreenAdaptiveBrightness)) { throw new TargetSetupError("Option screen-brightness cannot be set when " + - "screen-adaptive-brightness is set to ON"); + "screen-adaptive-brightness is set to ON", device.getDeviceDescriptor()); } setSettingForBinaryState(mScreenAdaptiveBrightness, mSystemSettings, @@ -633,7 +633,7 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { boolean result = device.pushString(sb.toString(), "/data/local.prop"); if (!result) { throw new TargetSetupError(String.format("Failed to push /data/local.prop to %s", - device.getSerialNumber())); + device.getSerialNumber()), device.getDeviceDescriptor()); } // Set reasonable permissions for /data/local.prop device.executeShellCommand("chmod 644 /data/local.prop"); @@ -695,7 +695,7 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { if (device.getApiLevel() < 22) { throw new TargetSetupError(String.format("Changing setting not supported on %s, " + - "must be API 22+", device.getSerialNumber())); + "must be API 22+", device.getSerialNumber()), device.getDeviceDescriptor()); } // Special case airplane mode since it needs to be set before other connectivity settings @@ -780,7 +780,7 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { if (!device.connectToWifiNetwork(mWifiSsid, mWifiPsk)) { throw new TargetSetupError(String.format( "Failed to connect to wifi network %s on %s", mWifiSsid, - device.getSerialNumber())); + device.getSerialNumber()), device.getDeviceDescriptor()); } } } @@ -800,12 +800,14 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { if (!mLocalDataFile.exists() || !mLocalDataFile.isDirectory()) { throw new TargetSetupError(String.format( - "local-data-path %s is not a directory", mLocalDataFile.getAbsolutePath())); + "local-data-path %s is not a directory", mLocalDataFile.getAbsolutePath()), + device.getDeviceDescriptor()); } String fullRemotePath = device.getIDevice().getMountPoint(IDevice.MNT_EXTERNAL_STORAGE); if (fullRemotePath == null) { throw new TargetSetupError(String.format( - "failed to get external storage path on device %s", device.getSerialNumber())); + "failed to get external storage path on device %s", device.getSerialNumber()), + device.getDeviceDescriptor()); } if (mRemoteDataPath != null) { fullRemotePath = String.format("%s/%s", fullRemotePath, mRemoteDataPath); @@ -815,7 +817,8 @@ public class DeviceSetup implements ITargetPreparer, ITargetCleaner { // TODO: get exact error code and respond accordingly throw new TargetSetupError(String.format( "failed to sync test data from local-data-path %s to %s on device %s", - mLocalDataFile.getAbsolutePath(), fullRemotePath, device.getSerialNumber())); + mLocalDataFile.getAbsolutePath(), fullRemotePath, device.getSerialNumber()), + device.getDeviceDescriptor()); } } diff --git a/src/com/android/tradefed/targetprep/DeviceWiper.java b/src/com/android/tradefed/targetprep/DeviceWiper.java index d916c364d..39957f649 100644 --- a/src/com/android/tradefed/targetprep/DeviceWiper.java +++ b/src/com/android/tradefed/targetprep/DeviceWiper.java @@ -59,7 +59,8 @@ public class DeviceWiper implements ITargetPreparer { CLog.d("Attempting fastboot wiping"); CommandResult r = device.executeLongFastbootCommand("-w"); if (r.getStatus() != CommandStatus.SUCCESS) { - throw new TargetSetupError(String.format("fastboot wiping failed: %s", r.getStderr())); + throw new TargetSetupError(String.format("fastboot wiping failed: %s", r.getStderr()), + device.getDeviceDescriptor()); } } @@ -74,7 +75,7 @@ public class DeviceWiper implements ITargetPreparer { CommandResult r = device.executeLongFastbootCommand(op, partition); if (r.getStatus() != CommandStatus.SUCCESS) { throw new TargetSetupError(String.format("%s %s failed: %s", op, partition, - r.getStderr())); + r.getStderr()), device.getDeviceDescriptor()); } } } diff --git a/src/com/android/tradefed/targetprep/FastbootDeviceFlasher.java b/src/com/android/tradefed/targetprep/FastbootDeviceFlasher.java index 96ec06979..ce0aa7019 100644 --- a/src/com/android/tradefed/targetprep/FastbootDeviceFlasher.java +++ b/src/com/android/tradefed/targetprep/FastbootDeviceFlasher.java @@ -17,6 +17,7 @@ package com.android.tradefed.targetprep; import com.android.tradefed.build.IDeviceBuildInfo; +import com.android.tradefed.command.remote.DeviceDescriptor; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.log.LogUtil.CLog; @@ -186,11 +187,12 @@ public class FastbootDeviceFlasher implements IDeviceFlasher { */ protected void downloadFlashingResources(ITestDevice device, IDeviceBuildInfo localBuild) throws TargetSetupError, DeviceNotAvailableException { - IFlashingResourcesParser resourceParser = createFlashingResourcesParser(localBuild); + IFlashingResourcesParser resourceParser = createFlashingResourcesParser(localBuild, + device.getDeviceDescriptor()); if (resourceParser.getRequiredBoards() == null) { throw new TargetSetupError(String.format("Build %s is missing required board info.", - localBuild.getDeviceBuildId())); + localBuild.getDeviceBuildId()), device.getDeviceDescriptor()); } String deviceProductType = device.getProductType(); if (deviceProductType == null) { @@ -234,7 +236,7 @@ public class FastbootDeviceFlasher implements IDeviceFlasher { if (!resourceParser.getRequiredBoards().contains(deviceProductType)) { throw new TargetSetupError(String.format("Device %s is %s. Expected %s", device.getSerialNumber(), deviceProductType, - resourceParser.getRequiredBoards())); + resourceParser.getRequiredBoards()), device.getDeviceDescriptor()); } } @@ -257,12 +259,18 @@ public class FastbootDeviceFlasher implements IDeviceFlasher { * Exposed for unit testing. * * @param localBuild the {@link IDeviceBuildInfo} to parse + * @param descriptor the descriptor of the device being flashed. * @return a {@link IFlashingResourcesParser} created by the factory method. * @throws TargetSetupError */ - protected IFlashingResourcesParser createFlashingResourcesParser(IDeviceBuildInfo localBuild) - throws TargetSetupError { - return new FlashingResourcesParser(localBuild.getDeviceImageFile()); + protected IFlashingResourcesParser createFlashingResourcesParser(IDeviceBuildInfo localBuild, + DeviceDescriptor descriptor) throws TargetSetupError { + try { + return new FlashingResourcesParser(localBuild.getDeviceImageFile()); + } catch (TargetSetupError e) { + // Rethrow with descriptor since FlashingResourceParser doesn't have it. + throw new TargetSetupError(e.getMessage(), e, descriptor); + } } /** @@ -458,7 +466,8 @@ public class FastbootDeviceFlasher implements IDeviceFlasher { userdataImg = ZipUtil.extractFileFromZip( new ZipFile(deviceBuild.getDeviceImageFile()), "userdata.img"); } catch (IOException ioe) { - throw new TargetSetupError("failed to extract userdata.img from image file", ioe); + throw new TargetSetupError("failed to extract userdata.img from image file", ioe, + device.getDeviceDescriptor()); } CLog.i("Flashing %s with userdata %s", device.getSerialNumber(), userdataImg); flashPartition(device, userdataImg, "userdata"); @@ -572,7 +581,8 @@ public class FastbootDeviceFlasher implements IDeviceFlasher { } } throw new TargetSetupError(String.format( - "Could not find version for '%s' after %d retry attempts", imageName, attempts)); + "Could not find version for '%s' after %d retry attempts", imageName, attempts), + device.getDeviceDescriptor()); } /** @@ -638,7 +648,8 @@ public class FastbootDeviceFlasher implements IDeviceFlasher { if (result.getStatus() != CommandStatus.SUCCESS || result.getStderr().contains("FAILED")) { throw new TargetSetupError(String.format( "fastboot command %s failed in device %s. stdout: %s, stderr: %s", cmdArgs[0], - device.getSerialNumber(), result.getStdout(), result.getStderr())); + device.getSerialNumber(), result.getStdout(), result.getStderr()), + device.getDeviceDescriptor()); } if (result.getStderr().length() > 0) { return result.getStderr(); diff --git a/src/com/android/tradefed/targetprep/FlashingResourcesParser.java b/src/com/android/tradefed/targetprep/FlashingResourcesParser.java index 0655959f3..318cf06bc 100644 --- a/src/com/android/tradefed/targetprep/FlashingResourcesParser.java +++ b/src/com/android/tradefed/targetprep/FlashingResourcesParser.java @@ -16,6 +16,7 @@ package com.android.tradefed.targetprep; +import com.android.tradefed.command.remote.DeviceDescriptor; import com.android.tradefed.util.MultiMap; import java.io.BufferedReader; @@ -261,8 +262,9 @@ public class FlashingResourcesParser implements IFlashingResourcesParser { deviceZip = new ZipFile(deviceImgZipFile); ZipEntry androidInfoEntry = deviceZip.getEntry(ANDROID_INFO_FILE_NAME); if (androidInfoEntry == null) { + DeviceDescriptor nullDescriptor = null; throw new TargetSetupError(String.format("Could not find %s in device image zip %s", - ANDROID_INFO_FILE_NAME, deviceImgZipFile.getName())); + ANDROID_INFO_FILE_NAME, deviceImgZipFile.getName()), nullDescriptor); } infoReader = new BufferedReader(new InputStreamReader( deviceZip.getInputStream(androidInfoEntry))); @@ -270,10 +272,10 @@ public class FlashingResourcesParser implements IFlashingResourcesParser { return parseAndroidInfo(infoReader, constraints); } catch (ZipException e) { throw new TargetSetupError(String.format("Could not read device image zip %s", - deviceImgZipFile.getName()), e); + deviceImgZipFile.getName()), e, null); } catch (IOException e) { throw new TargetSetupError(String.format("Could not read device image zip %s", - deviceImgZipFile.getName()), e); + deviceImgZipFile.getName()), e, null); } finally { if (deviceZip != null) { try { diff --git a/src/com/android/tradefed/targetprep/InstallApkSetup.java b/src/com/android/tradefed/targetprep/InstallApkSetup.java index 0fc09816a..e302587eb 100644 --- a/src/com/android/tradefed/targetprep/InstallApkSetup.java +++ b/src/com/android/tradefed/targetprep/InstallApkSetup.java @@ -81,7 +81,7 @@ public class InstallApkSetup implements ITargetPreparer { for (File apk : mApkPaths) { if (!apk.exists()) { throw new TargetSetupError(String.format("%s does not exist", - apk.getAbsolutePath())); + apk.getAbsolutePath()), device.getDeviceDescriptor()); } Log.i(LOG_TAG, String.format("Installing %s on %s", apk.getName(), device.getSerialNumber())); diff --git a/src/com/android/tradefed/targetprep/InstallBuildEnvApkSetup.java b/src/com/android/tradefed/targetprep/InstallBuildEnvApkSetup.java index b7608522c..e1e935288 100644 --- a/src/com/android/tradefed/targetprep/InstallBuildEnvApkSetup.java +++ b/src/com/android/tradefed/targetprep/InstallBuildEnvApkSetup.java @@ -48,7 +48,7 @@ public class InstallBuildEnvApkSetup implements ITargetPreparer { @Override public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, BuildError, DeviceNotAvailableException { - File testAppDir = getDataAppDirFromBuildEnv(); + File testAppDir = getDataAppDirFromBuildEnv(device); for (String apkName : mApkNames) { File apk = new File(testAppDir, apkName); CLog.i("Installing %s on %s", apk.getName(), device.getSerialNumber()); @@ -56,22 +56,21 @@ public class InstallBuildEnvApkSetup implements ITargetPreparer { if (result != null) { throw new TargetSetupError(String.format( "Failed to install %s on device %s. Reason: %s", apk.getAbsolutePath(), - device.getSerialNumber(), result)); + device.getSerialNumber(), result), device.getDeviceDescriptor()); } } } - private File getDataAppDirFromBuildEnv() throws TargetSetupError { + private File getDataAppDirFromBuildEnv(ITestDevice device) throws TargetSetupError { String buildRoot = System.getenv("ANDROID_PRODUCT_OUT"); if (buildRoot == null) { - throw new TargetSetupError( - "ANDROID_PRODUCT_OUT is not set. Are you in Android build env?"); + throw new TargetSetupError("ANDROID_PRODUCT_OUT is not set. Are you in Android " + + "build env?", device.getDeviceDescriptor()); } File testAppDir = new File(FileUtil.getPath(buildRoot, "data", "app")); if (!testAppDir.exists()) { - throw new TargetSetupError( - String.format("Could not find test app dir %s", testAppDir.getAbsolutePath())); - + throw new TargetSetupError(String.format("Could not find test app dir %s", + testAppDir.getAbsolutePath()),device.getDeviceDescriptor()); } return testAppDir; } diff --git a/src/com/android/tradefed/targetprep/InstrumentationPreparer.java b/src/com/android/tradefed/targetprep/InstrumentationPreparer.java index e9a1960a5..16a507d6b 100644 --- a/src/com/android/tradefed/targetprep/InstrumentationPreparer.java +++ b/src/com/android/tradefed/targetprep/InstrumentationPreparer.java @@ -98,7 +98,7 @@ public class InstrumentationPreparer implements ITargetPreparer { return; } - BuildError e = new BuildError("unknown error"); + BuildError e = new BuildError("unknown error", device.getDeviceDescriptor()); for (int i = 0; i < mAttempts; i++) { try { runInstrumentation(device); @@ -139,7 +139,7 @@ public class InstrumentationPreparer implements ITargetPreparer { String msg = String.format("Failed to run instrumentation %s on %s. failed tests = %s", mPackageName, device.getSerialNumber(), getFailedTestNames(listener)); CLog.w(msg); - throw new BuildError(msg); + throw new BuildError(msg, device.getDeviceDescriptor()); } } diff --git a/src/com/android/tradefed/targetprep/KernelFlashPreparer.java b/src/com/android/tradefed/targetprep/KernelFlashPreparer.java index 0f301a4bb..15de0d3e2 100644 --- a/src/com/android/tradefed/targetprep/KernelFlashPreparer.java +++ b/src/com/android/tradefed/targetprep/KernelFlashPreparer.java @@ -56,13 +56,13 @@ public class KernelFlashPreparer implements ITargetPreparer { device.getBuildId(), kernelBuildInfo.getSha1()); if (kernelBuildInfo.getRamdiskFile() == null) { - throw new TargetSetupError("Missing ramdisk file"); + throw new TargetSetupError("Missing ramdisk file", device.getDeviceDescriptor()); } if (kernelBuildInfo.getMkbootimgFile() == null) { - throw new TargetSetupError("Missing mkbootimg file"); + throw new TargetSetupError("Missing mkbootimg file", device.getDeviceDescriptor()); } if (kernelBuildInfo.getKernelFile() == null) { - throw new TargetSetupError("Missing kernel file"); + throw new TargetSetupError("Missing kernel file", device.getDeviceDescriptor()); } kernelBuildInfo.getMkbootimgFile().setExecutable(true); @@ -72,7 +72,8 @@ public class KernelFlashPreparer implements ITargetPreparer { boot = createBootImage(kernelBuildInfo.getMkbootimgFile(), kernelBuildInfo.getKernelFile(), kernelBuildInfo.getRamdiskFile()); } catch (IOException e) { - throw new TargetSetupError("Could not create boot image", e); + throw new TargetSetupError("Could not create boot image", e, + device.getDeviceDescriptor()); } try { @@ -88,7 +89,7 @@ public class KernelFlashPreparer implements ITargetPreparer { } catch (DeviceUnresponsiveException e) { // assume this is a build problem throw new BuildError(String.format("Device %s did not become available after " + - "flashing kernel", device.getSerialNumber())); + "flashing kernel", device.getSerialNumber()), device.getDeviceDescriptor()); } device.postBootSetup(); } diff --git a/src/com/android/tradefed/targetprep/KeyValueConfigPreparer.java b/src/com/android/tradefed/targetprep/KeyValueConfigPreparer.java index 6470a8111..b283e569f 100644 --- a/src/com/android/tradefed/targetprep/KeyValueConfigPreparer.java +++ b/src/com/android/tradefed/targetprep/KeyValueConfigPreparer.java @@ -54,7 +54,8 @@ public class KeyValueConfigPreparer implements ITargetPreparer { public void setUp(ITestDevice device, IBuildInfo buildInfo) throws DeviceNotAvailableException, TargetSetupError { if (mPath == null) { - throw new TargetSetupError("Option path must be specified"); + throw new TargetSetupError("Option path must be specified", + device.getDeviceDescriptor()); } StringBuilder config = new StringBuilder(); diff --git a/src/com/android/tradefed/targetprep/LocalSdkAvdPreparer.java b/src/com/android/tradefed/targetprep/LocalSdkAvdPreparer.java index 851ccab7c..72de43aa6 100644 --- a/src/com/android/tradefed/targetprep/LocalSdkAvdPreparer.java +++ b/src/com/android/tradefed/targetprep/LocalSdkAvdPreparer.java @@ -65,8 +65,8 @@ public class LocalSdkAvdPreparer extends SdkAvdPreparer { mSdkBuildInfo.setSdkDir(mLocalSdkPath); mSdkBuildInfo.setTestsDir(null); if (mLocalSdkPath == null) { - throw new TargetSetupError( - "Please set the path of the sdk using --local-sdk-path."); + throw new TargetSetupError("Please set the path of the sdk using --local-sdk-path.", + device.getDeviceDescriptor()); } launchEmulatorForAvd(mSdkBuildInfo, device, createAvd(mSdkBuildInfo)); } diff --git a/src/com/android/tradefed/targetprep/PushFilePreparer.java b/src/com/android/tradefed/targetprep/PushFilePreparer.java index eb101aea8..2d0d62ab3 100644 --- a/src/com/android/tradefed/targetprep/PushFilePreparer.java +++ b/src/com/android/tradefed/targetprep/PushFilePreparer.java @@ -93,9 +93,9 @@ public class PushFilePreparer implements ITargetCleaner { * Helper method to only throw if mAbortOnFailure is enabled. Callers should behave as if this * method may return. */ - private void fail(String message) throws TargetSetupError { + private void fail(String message, ITestDevice device) throws TargetSetupError { if (mAbortOnFailure) { - throw new TargetSetupError(message); + throw new TargetSetupError(message, device.getDeviceDescriptor()); } else { // Log the error and return Log.w(LOG_TAG, message); @@ -126,7 +126,7 @@ public class PushFilePreparer implements ITargetCleaner { for (String pushspec : mPushSpecs) { String[] pair = pushspec.split("->"); if (pair.length != 2) { - fail(String.format("Invalid pushspec: '%s'")); + fail(String.format("Invalid pushspec: '%s'"), device); continue; } Log.d(LOG_TAG, String.format("Trying to push local '%s' to remote '%s'", pair[0], @@ -137,13 +137,13 @@ public class PushFilePreparer implements ITargetCleaner { src = resolveRelativeFilePath(buildInfo, pair[0]); } if (src == null || !src.exists()) { - fail(String.format("Local source file '%s' does not exist", pair[0])); + fail(String.format("Local source file '%s' does not exist", pair[0]), device); continue; } if (src.isDirectory()) { if (!device.pushDir(src, pair[1])) { fail(String.format("Failed to push local '%s' to remote '%s'", pair[0], - pair[1])); + pair[1]), device); continue; } else { mFilesPushed.add(pair[1]); @@ -151,7 +151,7 @@ public class PushFilePreparer implements ITargetCleaner { } else { if (!device.pushFile(src, pair[1])) { fail(String.format("Failed to push local '%s' to remote '%s'", pair[0], - pair[1])); + pair[1]), device); continue; } else { mFilesPushed.add(pair[1]); diff --git a/src/com/android/tradefed/targetprep/PythonVirtualenvPreparer.java b/src/com/android/tradefed/targetprep/PythonVirtualenvPreparer.java index 731991cdb..504bf584d 100644 --- a/src/com/android/tradefed/targetprep/PythonVirtualenvPreparer.java +++ b/src/com/android/tradefed/targetprep/PythonVirtualenvPreparer.java @@ -60,11 +60,11 @@ public class PythonVirtualenvPreparer implements ITargetPreparer { @Override public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, BuildError, DeviceNotAvailableException { - startVirtualenv(buildInfo); - installDeps(buildInfo); + startVirtualenv(buildInfo, device); + installDeps(buildInfo, device); } - protected void installDeps(IBuildInfo buildInfo) throws TargetSetupError { + protected void installDeps(IBuildInfo buildInfo, ITestDevice device) throws TargetSetupError { boolean hasDependencies = false; if (mRequirementsFile != null) { CommandResult c = mRunUtil.runTimedCmd(BASE_TIMEOUT * 5, mPip, @@ -72,7 +72,8 @@ public class PythonVirtualenvPreparer implements ITargetPreparer { if (c.getStatus() != CommandStatus.SUCCESS) { CLog.e("Installing dependencies from %s failed", mRequirementsFile.getAbsolutePath()); - throw new TargetSetupError("Failed to install dependencies with pip"); + throw new TargetSetupError("Failed to install dependencies with pip", + device.getDeviceDescriptor()); } hasDependencies = true; } @@ -83,7 +84,8 @@ public class PythonVirtualenvPreparer implements ITargetPreparer { "install", dep); if (c.getStatus() != CommandStatus.SUCCESS) { CLog.e("Installing %s failed", dep); - throw new TargetSetupError("Failed to install dependencies with pip"); + throw new TargetSetupError("Failed to install dependencies with pip", + device.getDeviceDescriptor()); } hasDependencies = true; } @@ -99,7 +101,8 @@ public class PythonVirtualenvPreparer implements ITargetPreparer { } } - protected void startVirtualenv(IBuildInfo buildInfo) throws TargetSetupError { + protected void startVirtualenv(IBuildInfo buildInfo, ITestDevice device) + throws TargetSetupError { if (mVenvDir != null) { CLog.i("Using existing virtualenv based at %s", mVenvDir.getAbsolutePath()); activate(); @@ -111,7 +114,8 @@ public class PythonVirtualenvPreparer implements ITargetPreparer { activate(); } catch (IOException e) { CLog.e("Failed to create temp directory for virtualenv"); - throw new TargetSetupError("Error creating virtualenv", e); + throw new TargetSetupError("Error creating virtualenv", e, + device.getDeviceDescriptor()); } } diff --git a/src/com/android/tradefed/targetprep/SdkAvdPreparer.java b/src/com/android/tradefed/targetprep/SdkAvdPreparer.java index 50b40f818..bfce79674 100644 --- a/src/com/android/tradefed/targetprep/SdkAvdPreparer.java +++ b/src/com/android/tradefed/targetprep/SdkAvdPreparer.java @@ -120,6 +120,7 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { private final IRunUtil mRunUtil; private IDeviceManager mDeviceManager; + private ITestDevice mTestDevice; private File mSdkHome = null; @@ -149,6 +150,7 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { DeviceNotAvailableException, BuildError { Assert.assertTrue("Provided build is not a ISdkBuildInfo", buildInfo instanceof ISdkBuildInfo); + mTestDevice = device; ISdkBuildInfo sdkBuildInfo = (ISdkBuildInfo)buildInfo; launchEmulatorForAvd(sdkBuildInfo, device, createAvd(sdkBuildInfo)); } @@ -187,7 +189,8 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { CLog.w("Emulator %s is already running, killing", device.getSerialNumber()); getDeviceManager().killEmulator(device); } else if (!device.getIDevice().isEmulator()) { - throw new TargetSetupError("Invalid stub device, it is not of type emulator"); + throw new TargetSetupError("Invalid stub device, it is not of type emulator", + device.getDeviceDescriptor()); } mRunUtil.setEnvVariable("ANDROID_SDK_ROOT", sdkBuild.getSdkDir().getAbsolutePath()); @@ -204,7 +207,8 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { if (port == null) { // Serial number is not in expected format <type>-<consolePort> as defined by ddmlib throw new TargetSetupError(String.format( - "Failed to determine emulator port for %s", device.getSerialNumber())); + "Failed to determine emulator port for %s", device.getSerialNumber()), + device.getDeviceDescriptor()); } emulatorArgs.add("-port"); emulatorArgs.add(port.toString()); @@ -233,14 +237,14 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { emulatorArgs.add(tokens[0]); } else if (tokens.length == 2) { if (!tokens[0].startsWith("-")) { - throw new TargetSetupError(String.format( - "The emulator arg '%s' is invalid.", arg)); + throw new TargetSetupError(String.format("The emulator arg '%s' is invalid.", + arg), device.getDeviceDescriptor()); } emulatorArgs.add(tokens[0]); emulatorArgs.add(tokens[1]); } else { throw new TargetSetupError(String.format( - "The emulator arg '%s' is invalid.", arg)); + "The emulator arg '%s' is invalid.", arg), device.getDeviceDescriptor()); } } @@ -259,7 +263,7 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { // the wrong emulator launched. Treat as a BuildError throw new BuildError(String.format( "Emulator booted with incorrect avd name '%s'. Expected: '%s'.", - device.getIDevice().getAvdName(), avd)); + device.getIDevice().getAvdName(), avd), device.getDeviceDescriptor()); } } @@ -306,12 +310,12 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { throw new TargetSetupError(String.format( "Unable to get list of SDK targets using %s. Result %s. stdout: %s, err: %s", sdkBuild.getAndroidToolPath(), result.getStatus(), result.getStdout(), - result.getStderr())); + result.getStderr()), mTestDevice.getDeviceDescriptor()); } String[] targets = result.getStdout().split("\n"); if (result.getStdout().trim().isEmpty() || targets.length == 0) { throw new TargetSetupError(String.format("No targets found in SDK %s.", - sdkBuild.getSdkDir().getAbsolutePath())); + sdkBuild.getSdkDir().getAbsolutePath()), mTestDevice.getDeviceDescriptor()); } return targets; } @@ -333,7 +337,8 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { // store avds etc in tmp location, and clean up on teardown mRunUtil.setEnvVariable("ANDROID_SDK_HOME", mSdkHome.getAbsolutePath()); } catch (IOException e) { - throw new TargetSetupError("Failed to create sdk home"); + throw new TargetSetupError("Failed to create sdk home", + mTestDevice.getDeviceDescriptor()); } } @@ -355,7 +360,7 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { } } throw new TargetSetupError(String.format("Could not find target %s in sdk", - mTargetName)); + mTargetName), mTestDevice.getDeviceDescriptor()); } // just return last target return targets[targets.length - 1]; @@ -401,7 +406,7 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { // treat as BuildError throw new BuildError(String.format( "Unable to create avd for target '%s'. stderr: '%s'", target, - result.getStderr())); + result.getStderr()), mTestDevice.getDeviceDescriptor()); } // Further customise hardware options after AVD was created @@ -446,7 +451,8 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { result.getStdout()); // treat as TargetSetupError throw new TargetSetupError(String.format( - "Unable to add hardware option to AVD. stderr: '%s'", result.getStderr())); + "Unable to add hardware option to AVD. stderr: '%s'", result.getStderr()), + mTestDevice.getDeviceDescriptor()); } } } @@ -489,7 +495,8 @@ public class SdkAvdPreparer implements ITargetPreparer, IHostCleaner { } } throw new DeviceFailedToBootError( - String.format("Emulator for avd '%s' failed to boot.", avd)); + String.format("Emulator for avd '%s' failed to boot.", avd), + device.getDeviceDescriptor()); } /** diff --git a/src/com/android/tradefed/targetprep/SystemUpdaterDeviceFlasher.java b/src/com/android/tradefed/targetprep/SystemUpdaterDeviceFlasher.java index b328a3f40..c6d124e38 100644 --- a/src/com/android/tradefed/targetprep/SystemUpdaterDeviceFlasher.java +++ b/src/com/android/tradefed/targetprep/SystemUpdaterDeviceFlasher.java @@ -95,10 +95,11 @@ public class SystemUpdaterDeviceFlasher implements IDeviceFlasher { File otaPackageFile = deviceBuild.getOtaPackageFile(); if (otaPackageFile == null) { throw new TargetSetupError("No OTA package file present for build " - + deviceBuild.getDeviceBuildId()); + + deviceBuild.getDeviceBuildId(), device.getDeviceDescriptor()); } if (!device.pushFile(otaPackageFile, "/cache/update.zip")) { - throw new TargetSetupError("Could not push OTA file to the target."); + throw new TargetSetupError("Could not push OTA file to the target.", + device.getDeviceDescriptor()); } String commands = "echo --update_package > /cache/recovery/command &&" + diff --git a/src/com/android/tradefed/targetprep/TargetSetupError.java b/src/com/android/tradefed/targetprep/TargetSetupError.java index eb4f78290..2d005118f 100644 --- a/src/com/android/tradefed/targetprep/TargetSetupError.java +++ b/src/com/android/tradefed/targetprep/TargetSetupError.java @@ -15,6 +15,8 @@ */ package com.android.tradefed.targetprep; +import com.android.tradefed.command.remote.DeviceDescriptor; + /** * A fatal error occurred while preparing the target for testing. */ @@ -22,23 +24,59 @@ public class TargetSetupError extends Exception { private static final long serialVersionUID = 2202987086655357201L; + private DeviceDescriptor mDescriptor = null; + /** * Constructs a new (@link TargetSetupError} with a meaningful error message. * * @param reason a error message describing the cause of the error + * @deprecated use {@link #TargetSetupError(String, DeviceDescriptor)} instead. */ + @Deprecated public TargetSetupError(String reason) { super(reason); } /** + * Constructs a new (@link TargetSetupError} with a meaningful error message. + * + * @param reason a error message describing the cause of the error + * @param descriptor the descriptor of the device concerned + */ + public TargetSetupError(String reason, DeviceDescriptor descriptor) { + this(reason, null, descriptor); + } + + /** * Constructs a new (@link TargetSetupError} with a meaningful error message, and a * cause. * * @param reason a detailed error message. * @param cause a {@link Throwable} capturing the original cause of the TargetSetupError + * @deprecated use {@link #TargetSetupError(String, Throwable, DeviceDescriptor)} instead. */ + @Deprecated public TargetSetupError(String reason, Throwable cause) { super(reason, cause); } + + /** + * Constructs a new (@link TargetSetupError} with a meaningful error message, and a + * cause. + * + * @param reason a detailed error message. + * @param cause a {@link Throwable} capturing the original cause of the TargetSetupError + * @param descriptor the descriptor of the device concerned + */ + public TargetSetupError(String reason, Throwable cause, DeviceDescriptor descriptor) { + super(reason + " " + descriptor, cause); + mDescriptor = descriptor; + } + + /** + * Return the descriptor of the device associated with exception. + */ + public DeviceDescriptor getDeviceDescriptor() { + return mDescriptor; + } } diff --git a/src/com/android/tradefed/targetprep/TemperatureThrottlingWaiter.java b/src/com/android/tradefed/targetprep/TemperatureThrottlingWaiter.java index 0897d73f5..faaa85588 100644 --- a/src/com/android/tradefed/targetprep/TemperatureThrottlingWaiter.java +++ b/src/com/android/tradefed/targetprep/TemperatureThrottlingWaiter.java @@ -73,8 +73,8 @@ public class TemperatureThrottlingWaiter implements ITargetPreparer { CLog.d("Temperature is still high actual %d/expected %d", deviceTemperature, mTargetTemperature); } else { - CLog.i("Total time elapsed to get to %dc : %ds", - mTargetTemperature, (System.currentTimeMillis() - start) / 1000); + CLog.i("Total time elapsed to get to %dc : %ds", mTargetTemperature, + (System.currentTimeMillis() - start) / 1000); break; // while loop } if ((System.currentTimeMillis() - start) > maxWaitMs) { @@ -82,7 +82,8 @@ public class TemperatureThrottlingWaiter implements ITargetPreparer { deviceTemperature, mTargetTemperature, maxWaitMs); if (mAbortOnTimeout) { throw new TargetSetupError(String.format("Temperature is still high after wait " - + "timeout; actual %d/expected %d", deviceTemperature, mTargetTemperature)); + + "timeout; actual %d/expected %d", deviceTemperature, + mTargetTemperature), device.getDeviceDescriptor()); } break; // while loop } @@ -107,11 +108,11 @@ public class TemperatureThrottlingWaiter implements ITargetPreparer { CLog.i(String.format("Temperature file output : %s", result)); // example output : Result:30 Raw:7f6f if (result == null || result.contains("No such file or directory")) { - throw new TargetSetupError(String.format( - "File %s doesn't exist", fileName)); + throw new TargetSetupError(String.format("File %s doesn't exist", fileName), + device.getDeviceDescriptor()); } else if (!result.toLowerCase().startsWith("result:")) { - throw new TargetSetupError(String.format( - "file content is not as expected. Content : ", result)); + throw new TargetSetupError(String.format("file content is not as expected. Content : ", + result), device.getDeviceDescriptor()); } try { diff --git a/src/com/android/tradefed/targetprep/TestAppInstallSetup.java b/src/com/android/tradefed/targetprep/TestAppInstallSetup.java index 9c5137fae..7d467aac3 100644 --- a/src/com/android/tradefed/targetprep/TestAppInstallSetup.java +++ b/src/com/android/tradefed/targetprep/TestAppInstallSetup.java @@ -96,17 +96,19 @@ public class TestAppInstallSetup implements ITargetCleaner, IAbiReceiver { * * @param buildInfo build artifact information * @param apkFileName filename of the apk to install + * @param device the {@link ITestDevice} being prepared * @return a {@link File} representing the physical apk file on host or {@code null} if the * file does not exist. */ - protected File getLocalPathForFilename(IBuildInfo buildInfo, String apkFileName) - throws TargetSetupError { + protected File getLocalPathForFilename(IBuildInfo buildInfo, String apkFileName, + ITestDevice device) throws TargetSetupError { try { return BuildTestsZipUtils.getApkFile(buildInfo, apkFileName, mAltDirs, mAltDirBehavior, false /* use resource as fallback */, null /* device signing key */); } catch (IOException ioe) { - throw new TargetSetupError("failed to resolve apk path", ioe); + throw new TargetSetupError("failed to resolve apk path", ioe, + device.getDeviceDescriptor()); } } @@ -127,7 +129,7 @@ public class TestAppInstallSetup implements ITargetCleaner, IAbiReceiver { if (testAppName == null || testAppName.trim().isEmpty()) { continue; } - File testAppFile = getLocalPathForFilename(buildInfo, testAppName); + File testAppFile = getLocalPathForFilename(buildInfo, testAppName, device); if (testAppFile == null) { CLog.d("Test app %s was not found", testAppName); continue; @@ -155,12 +157,13 @@ public class TestAppInstallSetup implements ITargetCleaner, IAbiReceiver { if (result != null) { throw new TargetSetupError( String.format("Failed to install %s on %s. Reason: '%s'", testAppName, - device.getSerialNumber(), result)); + device.getSerialNumber(), result), device.getDeviceDescriptor()); } if (mCleanup) { AaptParser parser = AaptParser.parse(testAppFile); if (parser == null) { - throw new TargetSetupError("apk installed but AaptParser failed"); + throw new TargetSetupError("apk installed but AaptParser failed", + device.getDeviceDescriptor()); } mPackagesInstalled.add(parser.getPackageName()); } diff --git a/src/com/android/tradefed/targetprep/TestFilePushSetup.java b/src/com/android/tradefed/targetprep/TestFilePushSetup.java index 55697f47a..e4bc2eb8f 100644 --- a/src/com/android/tradefed/targetprep/TestFilePushSetup.java +++ b/src/com/android/tradefed/targetprep/TestFilePushSetup.java @@ -91,8 +91,8 @@ public class TestFilePushSetup implements ITargetPreparer { * @param fileName filename of artifacts to push * @return a {@link File} representing the physical file/path on host */ - protected File getLocalPathForFilename(IBuildInfo buildInfo, String fileName) - throws TargetSetupError { + protected File getLocalPathForFilename(IBuildInfo buildInfo, String fileName, + ITestDevice device) throws TargetSetupError { List<File> dirs = new ArrayList<>(); for (File dir : mAltDirs) { dirs.add(dir); @@ -115,12 +115,13 @@ public class TestFilePushSetup implements ITargetPreparer { } else if (mAltDirBehavior == AltDirBehavior.OVERRIDE) { dirs.addAll(expandedTestDirs); } else { - throw new TargetSetupError("Missing handler for alt-dir-behavior: " + mAltDirBehavior); + throw new TargetSetupError("Missing handler for alt-dir-behavior: " + mAltDirBehavior, + device.getDeviceDescriptor()); } if (dirs.isEmpty()) { throw new TargetSetupError( "Provided buildInfo does not contain a valid tests directory and no " + - "alternative directories were provided"); + "alternative directories were provided", device.getDeviceDescriptor()); } for (File dir : dirs) { @@ -148,12 +149,12 @@ public class TestFilePushSetup implements ITargetPreparer { } int filePushed = 0; for (String fileName : mTestPaths) { - File localFile = getLocalPathForFilename(buildInfo, fileName); + File localFile = getLocalPathForFilename(buildInfo, fileName, device); if (localFile == null) { if (mThrowIfNoFile) { throw new TargetSetupError(String.format( "Could not find test file %s directory in extracted tests.zip", - fileName)); + fileName), device.getDeviceDescriptor()); } else { continue; } @@ -170,7 +171,8 @@ public class TestFilePushSetup implements ITargetPreparer { filePushed++; } if (filePushed == 0) { - throw new TargetSetupError("No file is pushed from tests.zip"); + throw new TargetSetupError("No file is pushed from tests.zip", + device.getDeviceDescriptor()); } } diff --git a/src/com/android/tradefed/targetprep/TestJarInstaller.java b/src/com/android/tradefed/targetprep/TestJarInstaller.java index a76130195..d49069904 100644 --- a/src/com/android/tradefed/targetprep/TestJarInstaller.java +++ b/src/com/android/tradefed/targetprep/TestJarInstaller.java @@ -51,7 +51,7 @@ public class TestJarInstaller implements ITargetPreparer, ITargetCleaner { CLog.d("Pushing %s to %s", file.getName(), remotePath); if (!device.pushFile(file, remotePath)) { throw new TargetSetupError(String.format("Failed to push %s to %s", - file.getName(), remotePath)); + file.getName(), remotePath), device.getDeviceDescriptor()); } } } diff --git a/src/com/android/tradefed/targetprep/TestSystemAppInstallSetup.java b/src/com/android/tradefed/targetprep/TestSystemAppInstallSetup.java index 33cc62ed6..2040f824f 100644 --- a/src/com/android/tradefed/targetprep/TestSystemAppInstallSetup.java +++ b/src/com/android/tradefed/targetprep/TestSystemAppInstallSetup.java @@ -70,8 +70,8 @@ public class TestSystemAppInstallSetup implements ITargetPreparer { } File testsDir = ((IDeviceBuildInfo)buildInfo).getTestsDir(); if (testsDir == null || !testsDir.exists()) { - throw new TargetSetupError( - "Provided buildInfo does not contain a valid tests directory"); + throw new TargetSetupError("Provided buildInfo does not contain a valid tests " + + "directory", device.getDeviceDescriptor()); } device.remountSystemWritable(); device.setRecoveryMode(RecoveryMode.ONLINE); @@ -80,9 +80,8 @@ public class TestSystemAppInstallSetup implements ITargetPreparer { for (String testAppName : mTestFileNames) { File testAppFile = FileUtil.getFileForPath(testsDir, "DATA", "app", testAppName); if (!testAppFile.exists()) { - throw new TargetSetupError( - String.format("Could not find test app %s directory in extracted tests.zip", - testAppFile)); + throw new TargetSetupError(String.format("Could not find test app %s directory in " + + "extracted tests.zip", testAppFile), device.getDeviceDescriptor()); } device.pushFile(testAppFile, String.format("/system/app/%s", testAppName)); } diff --git a/src/com/android/tradefed/targetprep/WaitForDeviceDatetimePreparer.java b/src/com/android/tradefed/targetprep/WaitForDeviceDatetimePreparer.java index efb8d13df..140d9902d 100644 --- a/src/com/android/tradefed/targetprep/WaitForDeviceDatetimePreparer.java +++ b/src/com/android/tradefed/targetprep/WaitForDeviceDatetimePreparer.java @@ -58,7 +58,8 @@ public class WaitForDeviceDatetimePreparer implements ITargetPreparer { BuildError, DeviceNotAvailableException { if (!waitForDeviceDatetime(device, mForceDatetime)) { if (mForceSetupError) { - throw new TargetSetupError("datetime on device is incorrect after wait timeout"); + throw new TargetSetupError("datetime on device is incorrect after wait timeout", + device.getDeviceDescriptor()); } else { CLog.w("datetime on device is incorrect after wait timeout."); } diff --git a/src/com/android/tradefed/targetprep/WifiPreparer.java b/src/com/android/tradefed/targetprep/WifiPreparer.java index 1f576c280..ea06b26c0 100644 --- a/src/com/android/tradefed/targetprep/WifiPreparer.java +++ b/src/com/android/tradefed/targetprep/WifiPreparer.java @@ -57,12 +57,12 @@ public class WifiPreparer implements ITargetPreparer, ITargetCleaner { return; } if (mWifiNetwork == null) { - throw new TargetSetupError("wifi-network not specified"); + throw new TargetSetupError("wifi-network not specified", device.getDeviceDescriptor()); } if (!device.connectToWifiNetworkIfNeeded(mWifiNetwork, mWifiPsk)) { throw new TargetSetupError(String.format("Failed to connect to wifi network %s on %s", - mWifiNetwork, device.getSerialNumber())); + mWifiNetwork, device.getSerialNumber()), device.getDeviceDescriptor()); } if (mMonitorNetwork) { diff --git a/src/com/android/tradefed/targetprep/companion/CheckPairingPreparer.java b/src/com/android/tradefed/targetprep/companion/CheckPairingPreparer.java index 8a9d88e97..530cc395e 100644 --- a/src/com/android/tradefed/targetprep/companion/CheckPairingPreparer.java +++ b/src/com/android/tradefed/targetprep/companion/CheckPairingPreparer.java @@ -45,7 +45,7 @@ public class CheckPairingPreparer extends CompanionAwarePreparer { if (!primaryHasCompanion || !companionHasPrimary) { throw new TargetSetupError(String.format( "device bonding error: primaryHasCompanion=%s, companionHasPrimary=%s", - primaryHasCompanion, companionHasPrimary)); + primaryHasCompanion, companionHasPrimary), device.getDeviceDescriptor()); } } } diff --git a/src/com/android/tradefed/targetprep/companion/CompanionAllocator.java b/src/com/android/tradefed/targetprep/companion/CompanionAllocator.java index 477bc0667..ad33ff918 100644 --- a/src/com/android/tradefed/targetprep/companion/CompanionAllocator.java +++ b/src/com/android/tradefed/targetprep/companion/CompanionAllocator.java @@ -44,7 +44,7 @@ public abstract class CompanionAllocator implements ITargetCleaner { device, getCompanionDeviceSelectionOptions()); if (companionDevice == null) { throw new TargetSetupError(String.format("failed to allocate companion device for %s", - device.getSerialNumber())); + device.getSerialNumber()), device.getDeviceDescriptor()); } } diff --git a/src/com/android/tradefed/targetprep/companion/CompanionAwarePreparer.java b/src/com/android/tradefed/targetprep/companion/CompanionAwarePreparer.java index 451071086..e3ba1be0b 100644 --- a/src/com/android/tradefed/targetprep/companion/CompanionAwarePreparer.java +++ b/src/com/android/tradefed/targetprep/companion/CompanionAwarePreparer.java @@ -40,7 +40,7 @@ public abstract class CompanionAwarePreparer implements ITargetPreparer { ITestDevice companionDevice = getCompanionDeviceTracker().getCompanionDevice(primary); if (companionDevice == null) { throw new TargetSetupError(String.format("no companion device allocated for %s", - primary.getSerialNumber())); + primary.getSerialNumber()), primary.getDeviceDescriptor()); } return companionDevice; } diff --git a/src/com/android/tradefed/targetprep/companion/CompanionRunCommandTargetPreparer.java b/src/com/android/tradefed/targetprep/companion/CompanionRunCommandTargetPreparer.java index fb90c1a09..7946a1c36 100644 --- a/src/com/android/tradefed/targetprep/companion/CompanionRunCommandTargetPreparer.java +++ b/src/com/android/tradefed/targetprep/companion/CompanionRunCommandTargetPreparer.java @@ -38,7 +38,7 @@ public class CompanionRunCommandTargetPreparer extends RunCommandTargetPreparer ITestDevice companion = CompanionDeviceTracker.getInstance().getCompanionDevice(device); if (companion == null) { throw new TargetSetupError(String.format("no companion device allocated for %s", - device.getSerialNumber())); + device.getSerialNumber()), device.getDeviceDescriptor()); } super.setUp(companion, buildInfo); } diff --git a/src/com/android/tradefed/targetprep/companion/CompanionTestAppInstallSetup.java b/src/com/android/tradefed/targetprep/companion/CompanionTestAppInstallSetup.java index e1ff35efa..102f38597 100644 --- a/src/com/android/tradefed/targetprep/companion/CompanionTestAppInstallSetup.java +++ b/src/com/android/tradefed/targetprep/companion/CompanionTestAppInstallSetup.java @@ -43,7 +43,7 @@ public class CompanionTestAppInstallSetup extends TestAppInstallSetup { ITestDevice companion = CompanionDeviceTracker.getInstance().getCompanionDevice(device); if (companion == null) { throw new TargetSetupError(String.format("no companion device allocated for %s", - device.getSerialNumber())); + device.getSerialNumber()), device.getDeviceDescriptor()); } super.setUp(companion, buildInfo); } |