1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.compatibility.common.tradefed.targetprep; 18 19 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; 20 import com.android.tradefed.config.IConfiguration; 21 import com.android.tradefed.config.IConfigurationReceiver; 22 import com.android.tradefed.config.Option; 23 import com.android.tradefed.config.OptionClass; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.invoker.TestInformation; 27 import com.android.tradefed.log.LogUtil.CLog; 28 import com.android.tradefed.observatory.IDiscoverDependencies; 29 import com.android.tradefed.result.CollectingTestListener; 30 import com.android.tradefed.result.TestDescription; 31 import com.android.tradefed.result.TestResult; 32 import com.android.tradefed.result.TestRunResult; 33 import com.android.tradefed.result.TestStatus; 34 import com.android.tradefed.result.error.DeviceErrorIdentifier; 35 import com.android.tradefed.result.error.InfraErrorIdentifier; 36 import com.android.tradefed.targetprep.BuildError; 37 import com.android.tradefed.targetprep.TargetSetupError; 38 import com.android.tradefed.testtype.AndroidJUnitTest; 39 40 import java.io.File; 41 import java.io.FileNotFoundException; 42 import java.util.HashSet; 43 import java.util.Map.Entry; 44 import java.util.Set; 45 46 /** Target preparer that instruments an APK. */ 47 @OptionClass(alias = "apk-instrumentation-preparer") 48 public class ApkInstrumentationPreparer extends PreconditionPreparer 49 implements IConfigurationReceiver, IDiscoverDependencies { 50 51 @Option(name = "apk", description = "Name of the apk to instrument", mandatory = true) 52 protected String mApkFileName = null; 53 54 @Option(name = "package", description = "Name of the package", mandatory = true) 55 protected String mPackageName = null; 56 57 public enum When { 58 BEFORE, AFTER, BOTH; 59 } 60 61 @Option(name = "when", description = "When to instrument the apk", mandatory = true) 62 protected When mWhen = null; 63 64 @Option(name = "throw-error", description = "Whether to throw error for device test failure") 65 protected boolean mThrowError = true; 66 67 @Option( 68 name = "apk-instrumentation-filter", 69 description = "The include filters of the test name to run in the apk", 70 requiredForRerun = true) 71 private Set<String> mIncludeFilters = new HashSet<>(); 72 73 private IConfiguration mConfiguration = null; 74 75 /** {@inheritDoc} */ 76 @Override setConfiguration(IConfiguration configuration)77 public void setConfiguration(IConfiguration configuration) { 78 mConfiguration = configuration; 79 } 80 81 /** {@inheritDoc} */ 82 @Override run(TestInformation testInfo)83 public void run(TestInformation testInfo) 84 throws TargetSetupError, BuildError, DeviceNotAvailableException { 85 if (mWhen == When.AFTER) { 86 return; 87 } 88 ITestDevice device = testInfo.getDevice(); 89 try { 90 if (instrument(testInfo)) { 91 CLog.d("Target preparation successful"); 92 } else if (mThrowError) { 93 throw new TargetSetupError( 94 "Not all target preparation steps completed", 95 device.getDeviceDescriptor(), 96 DeviceErrorIdentifier.DEVICE_UNEXPECTED_RESPONSE); 97 } 98 } catch (FileNotFoundException e) { 99 throw new TargetSetupError( 100 "Couldn't find apk to instrument", 101 e, 102 device.getDeviceDescriptor(), 103 InfraErrorIdentifier.ARTIFACT_NOT_FOUND); 104 } 105 } 106 107 /** {@inheritDoc} */ 108 @Override tearDown(TestInformation testInfo, Throwable e)109 public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException { 110 if (e instanceof DeviceNotAvailableException) { 111 return; 112 } 113 if (mWhen == When.BEFORE) { 114 return; 115 } 116 try { 117 instrument(testInfo); 118 } catch (FileNotFoundException e1) { 119 CLog.e("Couldn't find apk to instrument"); 120 CLog.e(e1); 121 } 122 } 123 124 @Override reportDependencies()125 public Set<String> reportDependencies() { 126 Set<String> deps = new HashSet<>(); 127 deps.add(mApkFileName); 128 return deps; 129 } 130 instrument(TestInformation testInfo)131 private boolean instrument(TestInformation testInfo) 132 throws DeviceNotAvailableException, FileNotFoundException { 133 CompatibilityBuildHelper buildHelper = 134 new CompatibilityBuildHelper(testInfo.getBuildInfo()); 135 136 File apkFile = buildHelper.getTestFile(mApkFileName); 137 if (!apkFile.exists()) { 138 throw new FileNotFoundException(String.format("%s not found", mApkFileName)); 139 } 140 141 ITestDevice device = testInfo.getDevice(); 142 if (device.getAppPackageInfo(mPackageName) != null) { 143 CLog.i("Package %s already present on the device, uninstalling ...", mPackageName); 144 device.uninstallPackage(mPackageName); 145 } 146 // Ensure device online before attempting instrumentation 147 testInfo.getDevice().waitForDeviceAvailable(); 148 CLog.i("Instrumenting package: %s", mPackageName); 149 CollectingTestListener listener = new CollectingTestListener(); 150 AndroidJUnitTest instrTest = new AndroidJUnitTest(); 151 instrTest.setConfiguration(mConfiguration); 152 instrTest.setDevice(device); 153 instrTest.setInstallFile(apkFile); 154 instrTest.setPackageName(mPackageName); 155 instrTest.addAllIncludeFilters(mIncludeFilters); 156 instrTest.setRerunMode(false); 157 instrTest.setReRunUsingTestFile(false); 158 // TODO: Make this configurable. 159 instrTest.setIsolatedStorage(false); 160 instrTest.run(testInfo, listener); 161 TestRunResult result = listener.getCurrentRunResults(); 162 163 for (Entry<TestDescription, TestResult> results : result.getTestResults().entrySet()) { 164 if (TestStatus.FAILURE.equals(results.getValue().getResultStatus())) { 165 if (mThrowError) { 166 CLog.e( 167 "Target preparation step %s failed.\n%s", 168 results.getKey(), results.getValue().getStackTrace()); 169 } else { 170 CLog.w( 171 "Target preparation step %s failed.\n%s", 172 results.getKey(), results.getValue().getStackTrace()); 173 } 174 } 175 } 176 // If any failure return false 177 return !(result.isRunFailure() || result.hasFailedTests()); 178 } 179 } 180