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.ddmlib.testrunner.TestResult.TestStatus;
21 import com.android.tradefed.config.IConfiguration;
22 import com.android.tradefed.config.IConfigurationReceiver;
23 import com.android.tradefed.config.Option;
24 import com.android.tradefed.config.OptionClass;
25 import com.android.tradefed.device.DeviceNotAvailableException;
26 import com.android.tradefed.device.ITestDevice;
27 import com.android.tradefed.invoker.TestInformation;
28 import com.android.tradefed.log.LogUtil.CLog;
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.targetprep.BuildError;
34 import com.android.tradefed.targetprep.TargetSetupError;
35 import com.android.tradefed.testtype.AndroidJUnitTest;
36 
37 import java.io.File;
38 import java.io.FileNotFoundException;
39 import java.util.Map.Entry;
40 
41 /** Target preparer that instruments an APK. */
42 @OptionClass(alias = "apk-instrumentation-preparer")
43 public class ApkInstrumentationPreparer extends PreconditionPreparer
44         implements IConfigurationReceiver {
45 
46     @Option(name = "apk", description = "Name of the apk to instrument", mandatory = true)
47     protected String mApkFileName = null;
48 
49     @Option(name = "package", description = "Name of the package", mandatory = true)
50     protected String mPackageName = null;
51 
52     public enum When {
53         BEFORE, AFTER, BOTH;
54     }
55 
56     @Option(name = "when", description = "When to instrument the apk", mandatory = true)
57     protected When mWhen = null;
58 
59     @Option(name = "throw-error", description = "Whether to throw error for device test failure")
60     protected boolean mThrowError = true;
61 
62     private IConfiguration mConfiguration = null;
63 
64     /** {@inheritDoc} */
65     @Override
setConfiguration(IConfiguration configuration)66     public void setConfiguration(IConfiguration configuration) {
67         mConfiguration = configuration;
68     }
69 
70     /** {@inheritDoc} */
71     @Override
run(TestInformation testInfo)72     public void run(TestInformation testInfo)
73             throws TargetSetupError, BuildError, DeviceNotAvailableException {
74         if (mWhen == When.AFTER) {
75             return;
76         }
77         ITestDevice device = testInfo.getDevice();
78         try {
79             if (instrument(testInfo)) {
80                 CLog.d("Target preparation successful");
81             } else if (mThrowError) {
82                 throw new TargetSetupError("Not all target preparation steps completed",
83                         device.getDeviceDescriptor());
84             }
85         } catch (FileNotFoundException e) {
86             throw new TargetSetupError("Couldn't find apk to instrument", e,
87                     device.getDeviceDescriptor());
88         }
89     }
90 
91     /** {@inheritDoc} */
92     @Override
tearDown(TestInformation testInfo, Throwable e)93     public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException {
94         if (e instanceof DeviceNotAvailableException) {
95             return;
96         }
97         if (mWhen == When.BEFORE) {
98             return;
99         }
100         try {
101             instrument(testInfo);
102         } catch (FileNotFoundException e1) {
103             CLog.e("Couldn't find apk to instrument");
104             CLog.e(e1);
105         }
106     }
107 
instrument(TestInformation testInfo)108     private boolean instrument(TestInformation testInfo)
109             throws DeviceNotAvailableException, FileNotFoundException {
110         CompatibilityBuildHelper buildHelper =
111                 new CompatibilityBuildHelper(testInfo.getBuildInfo());
112 
113         File apkFile = buildHelper.getTestFile(mApkFileName);
114         if (!apkFile.exists()) {
115             throw new FileNotFoundException(String.format("%s not found", mApkFileName));
116         }
117 
118         ITestDevice device = testInfo.getDevice();
119         if (device.getAppPackageInfo(mPackageName) != null) {
120             CLog.i("Package %s already present on the device, uninstalling ...", mPackageName);
121             device.uninstallPackage(mPackageName);
122         }
123 
124         CLog.i("Instrumenting package: %s", mPackageName);
125         CollectingTestListener listener = new CollectingTestListener();
126         AndroidJUnitTest instrTest = new AndroidJUnitTest();
127         instrTest.setConfiguration(mConfiguration);
128         instrTest.setDevice(device);
129         instrTest.setInstallFile(apkFile);
130         instrTest.setPackageName(mPackageName);
131         instrTest.setRerunMode(false);
132         instrTest.setReRunUsingTestFile(false);
133         // TODO: Make this configurable.
134         instrTest.setIsolatedStorage(false);
135         instrTest.run(testInfo, listener);
136         TestRunResult result = listener.getCurrentRunResults();
137 
138         for (Entry<TestDescription, TestResult> results : result.getTestResults().entrySet()) {
139             if (TestStatus.FAILURE.equals(results.getValue().getStatus())) {
140                 if (mThrowError) {
141                     CLog.e(
142                             "Target preparation step %s failed.\n%s",
143                             results.getKey(), results.getValue().getStackTrace());
144                 } else {
145                     CLog.w(
146                             "Target preparation step %s failed.\n%s",
147                             results.getKey(), results.getValue().getStackTrace());
148                 }
149             }
150         }
151         // If any failure return false
152         return !(result.isRunFailure() || result.hasFailedTests());
153     }
154 }
155