1 /*
2  * Copyright (C) 2010 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.tradefed.testtype;
18 
19 import static com.android.tradefed.testtype.coverage.CoverageOptions.Toolchain.CLANG;
20 import static com.android.tradefed.testtype.coverage.CoverageOptions.Toolchain.GCOV;
21 import static com.android.tradefed.testtype.coverage.CoverageOptions.Toolchain.JACOCO;
22 
23 import static com.google.common.base.Preconditions.checkArgument;
24 import static com.google.common.base.Preconditions.checkState;
25 import static com.google.common.base.Verify.verify;
26 
27 import com.android.ddmlib.IDevice;
28 import com.android.ddmlib.Log;
29 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
30 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner.TestSize;
31 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
32 import com.android.tradefed.config.ConfigurationException;
33 import com.android.tradefed.config.IConfiguration;
34 import com.android.tradefed.config.IConfigurationReceiver;
35 import com.android.tradefed.config.Option;
36 import com.android.tradefed.config.Option.Importance;
37 import com.android.tradefed.config.OptionClass;
38 import com.android.tradefed.device.DeviceNotAvailableException;
39 import com.android.tradefed.device.ITestDevice;
40 import com.android.tradefed.device.metric.IMetricCollector;
41 import com.android.tradefed.device.metric.IMetricCollectorReceiver;
42 import com.android.tradefed.invoker.TestInformation;
43 import com.android.tradefed.log.LogUtil.CLog;
44 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
45 import com.android.tradefed.result.BugreportCollector;
46 import com.android.tradefed.result.CollectingTestListener;
47 import com.android.tradefed.result.ITestInvocationListener;
48 import com.android.tradefed.result.TestDescription;
49 import com.android.tradefed.result.TestResult;
50 import com.android.tradefed.result.TestRunResult;
51 import com.android.tradefed.result.ddmlib.DefaultRemoteAndroidTestRunner;
52 import com.android.tradefed.result.proto.TestRecordProto.FailureStatus;
53 import com.android.tradefed.retry.IRetryDecision;
54 import com.android.tradefed.retry.RetryStrategy;
55 import com.android.tradefed.testtype.coverage.CoverageOptions;
56 import com.android.tradefed.util.AbiFormatter;
57 import com.android.tradefed.util.ArrayUtil;
58 import com.android.tradefed.util.JavaCodeCoverageFlusher;
59 import com.android.tradefed.util.ListInstrumentationParser;
60 import com.android.tradefed.util.ListInstrumentationParser.InstrumentationTarget;
61 import com.android.tradefed.util.NativeCodeCoverageFlusher;
62 import com.android.tradefed.util.StringEscapeUtils;
63 
64 import com.google.common.annotations.VisibleForTesting;
65 import com.google.common.collect.Sets;
66 
67 import java.io.File;
68 import java.util.ArrayList;
69 import java.util.Collection;
70 import java.util.HashMap;
71 import java.util.LinkedHashSet;
72 import java.util.List;
73 import java.util.Map;
74 import java.util.Map.Entry;
75 import java.util.Set;
76 import java.util.concurrent.TimeUnit;
77 
78 /** A Test that runs an instrumentation test package on given device. */
79 @OptionClass(alias = "instrumentation")
80 public class InstrumentationTest
81         implements IDeviceTest,
82                 IRemoteTest,
83                 ITestCollector,
84                 IAbiReceiver,
85                 IConfigurationReceiver,
86                 IMetricCollectorReceiver {
87 
88     private static final String LOG_TAG = "InstrumentationTest";
89 
90     /** max number of attempts to collect list of tests in package */
91     private static final int COLLECT_TESTS_ATTEMPTS = 3;
92     /** instrumentation test runner argument key used for test execution using a file */
93     private static final String TEST_FILE_INST_ARGS_KEY = "testFile";
94 
95     /** instrumentation test runner argument key used for individual test timeout */
96     static final String TEST_TIMEOUT_INST_ARGS_KEY = "timeout_msec";
97 
98     /** default timeout for tests collection */
99     static final long TEST_COLLECTION_TIMEOUT_MS = 2 * 60 * 1000;
100 
101     /** test run name for merging coverage measurements */
102     static final String MERGE_COVERAGE_MEASUREMENTS_TEST_NAME = "mergeCoverageMeasurements";
103 
104     @Option(
105         name = "package",
106         shortName = 'p',
107         description = "The manifest package name of the Android test application to run.",
108         importance = Importance.IF_UNSET
109     )
110     private String mPackageName = null;
111 
112     @Option(name = "runner",
113             description="The instrumentation test runner class name to use. Will try to determine "
114                     + "automatically if it is not specified.")
115     private String mRunnerName = null;
116 
117     @Option(name = "class", shortName = 'c',
118             description="The test class name to run.")
119     private String mTestClassName = null;
120 
121     @Option(name = "method", shortName = 'm',
122             description="The test method name to run.")
123     private String mTestMethodName = null;
124 
125     @Option(name = "test-package",
126             description="Only run tests within this specific java package. " +
127             "Will be ignored if --class is set.")
128     private String mTestPackageName = null;
129 
130     /**
131      * @deprecated use shell-timeout or test-timeout option instead.
132      */
133     @Deprecated
134     @Option(name = "timeout",
135             description="Deprecated - Use \"shell-timeout\" or \"test-timeout\" instead.")
136     private Integer mTimeout = null;
137 
138     @Option(
139         name = "shell-timeout",
140         description =
141                 "The defined timeout (in milliseconds) is used as a maximum waiting time when "
142                         + "expecting the command output from the device. At any time, if the shell "
143                         + "command does not output anything for a period longer than defined "
144                         + "timeout the TF run terminates. For no timeout, set to 0.",
145         isTimeVal = true
146     )
147     private long mShellTimeout = 10 * 60 * 1000L; // default to 10 minutes
148 
149     @Option(
150         name = "test-timeout",
151         description =
152                 "Sets timeout (in milliseconds) that will be applied to each test. In the event of "
153                         + "a test timeout, it will log the results and proceed with executing the "
154                         + "next test. For no timeout, set to 0.",
155         isTimeVal = true
156     )
157     private long mTestTimeout = 5 * 60 * 1000L; // default to 5 minutes
158 
159     @Option(
160         name = "max-timeout",
161         description =
162                 "Sets the max timeout for the instrumentation to terminate. "
163                         + "For no timeout, set to 0.",
164         isTimeVal = true
165     )
166     private long mMaxTimeout = 0l;
167 
168     @Option(name = "size",
169             description="Restrict test to a specific test size.")
170     private String mTestSize = null;
171 
172     @Option(name = "rerun",
173             description = "Rerun unexecuted tests individually on same device if test run " +
174             "fails to complete.")
175     private boolean mIsRerunMode = true;
176 
177     @Option(name = "resume",
178             description = "Schedule unexecuted tests for resumption on another device " +
179             "if first device becomes unavailable.")
180     private boolean mIsResumeMode = false;
181 
182     @Option(name = "install-file",
183             description="Optional file path to apk file that contains the tests.")
184     private File mInstallFile = null;
185 
186     @Option(name = "run-name",
187             description="Optional custom test run name to pass to listener. " +
188             "If unspecified, will use package name.")
189     private String mRunName = null;
190 
191     @Option(
192             name = "instrumentation-arg",
193             description = "Additional instrumentation arguments to provide.",
194             requiredForRerun = true)
195     private final Map<String, String> mInstrArgMap = new HashMap<String, String>();
196 
197     @Option(name = "bugreport-on-failure", description = "Sets which failed testcase events " +
198             "cause a bugreport to be collected. a bugreport after failed testcases.  Note that " +
199             "there is _no feedback mechanism_ between the test runner and the bugreport " +
200             "collector, so use the EACH setting with due caution.")
201     private BugreportCollector.Freq mBugreportFrequency = null;
202 
203     @Option(
204         name = "rerun-from-file",
205         description =
206                 "Use test file instead of separate adb commands for each test "
207                         + "when re-running instrumentations for tests that failed to run in previous attempts. "
208     )
209     private boolean mReRunUsingTestFile = true;
210 
211     @Option(
212         name = "rerun-from-file-attempts",
213         description = "Max attempts to rerun tests from file. -1 means rerun from file infinitely."
214     )
215     private int mReRunUsingTestFileAttempts = 3;
216 
217     @Option(
218         name = "fallback-to-serial-rerun",
219         description = "Rerun tests serially after rerun from file failed."
220     )
221     private boolean mFallbackToSerialRerun = false;
222 
223     @Option(name = "reboot-before-rerun", description =
224             "Reboot a device before re-running instrumentations.")
225     private boolean mRebootBeforeReRun = false;
226 
227     @Option(name = AbiFormatter.FORCE_ABI_STRING,
228             description = AbiFormatter.FORCE_ABI_DESCRIPTION,
229             importance = Importance.IF_UNSET)
230     private String mForceAbi = null;
231 
232     @Option(name = "collect-tests-only",
233             description = "Only invoke the instrumentation to collect list of applicable test "
234                     + "cases. All test run callbacks will be triggered, but test execution will "
235                     + "not be actually carried out.")
236     private boolean mCollectTestsOnly = false;
237 
238     @Option(
239         name = "collect-tests-timeout",
240         description = "Timeout for the tests collection operation.",
241         isTimeVal = true
242     )
243     private long mCollectTestTimeout = TEST_COLLECTION_TIMEOUT_MS;
244 
245     @Option(
246         name = "debug",
247         description =
248                 "Wait for debugger before instrumentation starts. Note "
249                         + "that this should only be used for local debugging, not suitable for automated runs."
250     )
251     protected boolean mDebug = false;
252 
253     /** @deprecated Use the --coverage option in CoverageOptions instead. */
254     @Deprecated
255     @Option(
256         name = "coverage",
257         description =
258                 "Collect code coverage for this test run. Note that the build under test must be a "
259                         + "coverage build or else this will fail."
260     )
261     private boolean mCoverage = false;
262 
263     @Option(
264         name = "merge-coverage-measurements",
265         description =
266                 "Merge coverage measurements from all test runs into a single measurement before "
267                         + "logging."
268     )
269     private boolean mMergeCoverageMeasurements = false;
270 
271     @Deprecated
272     @Option(
273             name = "enforce-ajur-format",
274             description = "Whether or not enforcing the AJUR instrumentation output format")
275     private boolean mShouldEnforceFormat = false;
276 
277     @Option(
278         name = "hidden-api-checks",
279         description =
280                 "If set to false, the '--no-hidden-api-checks' flag will be passed to the am "
281                         + "instrument command. Only works for P or later."
282     )
283     private boolean mHiddenApiChecks = true;
284 
285     @Option(
286             name = "test-api-access",
287             description =
288                     "If set to false and hidden API checks are enabled, the '--no-test-api-access'"
289                             + " flag will be passed to the am instrument command."
290                             + " Only works for R or later.")
291     private boolean mTestApiAccess = true;
292 
293     @Option(
294             name = "isolated-storage",
295             description =
296                     "If set to false, the '--no-isolated-storage' flag will be passed to the am "
297                             + "instrument command. Only works for Q or later.")
298     private boolean mIsolatedStorage = true;
299 
300     @Option(
301         name = "window-animation",
302         description =
303                 "If set to false, the '--no-window-animation' flag will be passed to the am "
304                         + "instrument command. Only works for ICS or later."
305     )
306     private boolean mWindowAnimation = true;
307 
308     @Option(
309             name = "disable-duplicate-test-check",
310             description =
311                     "If set to true, it will not check that a method is only run once by a "
312                             + "given instrumentation.")
313     private boolean mDisableDuplicateCheck = false;
314 
315     @Option(
316             name = "enable-soft-restart-check",
317             description =
318                     "Whether or not to enable checking whether instrumentation crash is due to "
319                             + "a system_server restart.")
320     private boolean mEnableSoftRestartCheck = false;
321 
322     @Option(
323             name = "report-unexecuted-tests",
324             description =
325                     "Whether or not to enable reporting all unexecuted tests from instrumentation.")
326     private boolean mReportUnexecuted = true;
327 
328     private IAbi mAbi = null;
329 
330     private Collection<String> mInstallArgs = new ArrayList<>();
331 
332     private ITestDevice mDevice = null;
333 
334     private IRemoteAndroidTestRunner mRunner;
335 
336     private Collection<TestDescription> mTestsToRun = null;
337 
338     private String mCoverageTarget = null;
339 
340     private String mTestFilePathOnDevice = null;
341 
342     private ListInstrumentationParser mListInstrumentationParser = null;
343     private NativeCodeCoverageListener mNativeCoverageListener = null;
344 
345     private List<String> mExtraDeviceListener = new ArrayList<>();
346 
347     private boolean mIsRerun = false;
348 
349     private IConfiguration mConfiguration = null;
350     private List<IMetricCollector> mCollectors = new ArrayList<>();
351 
352     /** {@inheritDoc} */
353     @Override
setConfiguration(IConfiguration config)354     public void setConfiguration(IConfiguration config) {
355         mConfiguration = config;
356     }
357 
358     /** Gets the {@link IConfiguration} for this test. */
getConfiguration()359     public IConfiguration getConfiguration() {
360         return mConfiguration;
361     }
362 
363     /**
364      * {@inheritDoc}
365      */
366     @Override
setDevice(ITestDevice device)367     public void setDevice(ITestDevice device) {
368         mDevice = device;
369     }
370 
371     /**
372      * Set the Android manifest package to run.
373      */
setPackageName(String packageName)374     public void setPackageName(String packageName) {
375         mPackageName = packageName;
376     }
377 
378     /**
379      * Optionally, set the Android instrumentation runner to use.
380      */
setRunnerName(String runnerName)381     public void setRunnerName(String runnerName) {
382         mRunnerName = runnerName;
383     }
384 
385     /**
386      * Gets the Android instrumentation runner to be used.
387      */
getRunnerName()388     public String getRunnerName() {
389         return mRunnerName;
390     }
391 
392     /**
393      * Optionally, set the test class name to run.
394      */
setClassName(String testClassName)395     public void setClassName(String testClassName) {
396         mTestClassName = testClassName;
397     }
398 
399     /**
400      * Optionally, set the test method to run.
401      */
setMethodName(String testMethodName)402     public void setMethodName(String testMethodName) {
403         mTestMethodName = StringEscapeUtils.escapeShell(testMethodName);
404     }
405 
406     /**
407      * Optionally, set the path to a file located on the device that should contain a list of line
408      * separated test classes and methods (format: com.foo.Class#method) to be run.
409      * If set, will automatically attempt to re-run tests using this test file
410      * via {@link InstrumentationFileTest} instead of executing separate adb commands for each
411      * remaining test via {@link InstrumentationSerialTest}"
412      */
setTestFilePathOnDevice(String testFilePathOnDevice)413     public void setTestFilePathOnDevice(String testFilePathOnDevice) {
414         mTestFilePathOnDevice = testFilePathOnDevice;
415     }
416 
417     /**
418      * Optionally, set the test size to run.
419      */
setTestSize(String size)420     public void setTestSize(String size) {
421         mTestSize = size;
422     }
423 
424     /**
425      * Get the Android manifest package to run.
426      */
getPackageName()427     public String getPackageName() {
428         return mPackageName;
429     }
430 
431     /**
432      * Get the custom test run name that will be provided to listener
433      */
getRunName()434     public String getRunName() {
435         return mRunName;
436     }
437 
438     /**
439      * Set the custom test run name that will be provided to listener
440      */
setRunName(String runName)441     public void setRunName(String runName) {
442         mRunName = runName;
443     }
444 
445     /**
446      * Set the collection of tests that should be executed by this InstrumentationTest.
447      *
448      * @param tests the tests to run
449      */
setTestsToRun(Collection<TestDescription> tests)450     public void setTestsToRun(Collection<TestDescription> tests) {
451         mTestsToRun = tests;
452     }
453 
454     /**
455      * Get the class name to run.
456      */
getClassName()457     protected String getClassName() {
458         return mTestClassName;
459     }
460 
461     /**
462      * Get the test method to run.
463      */
getMethodName()464     protected String getMethodName() {
465         return mTestMethodName;
466     }
467 
468     /**
469      * Get the path to a file that contains class#method combinations to be run
470      */
getTestFilePathOnDevice()471     String getTestFilePathOnDevice() {
472         return mTestFilePathOnDevice;
473     }
474 
475     /** Get the test java package to run. */
getTestPackageName()476     protected String getTestPackageName() {
477         return mTestPackageName;
478     }
479 
480     /**
481      * Sets the test package filter.
482      * <p/>
483      * If non-null, only tests within the given java package will be executed.
484      * <p/>
485      * Will be ignored if a non-null value has been provided to {@link #setClassName(String)}
486      */
setTestPackageName(String testPackageName)487     public void setTestPackageName(String testPackageName) {
488         mTestPackageName = testPackageName;
489     }
490 
491     /**
492      * Get the test size to run. Returns <code>null</code> if no size has been set.
493      */
getTestSize()494     String getTestSize() {
495         return mTestSize;
496     }
497 
498     /**
499      * Optionally, set the maximum time (in milliseconds) expecting shell output from the device.
500      */
setShellTimeout(long timeout)501     public void setShellTimeout(long timeout) {
502         mShellTimeout = timeout;
503     }
504 
505     /** Optionally, set the maximum time (in milliseconds) for each individual test run. */
setTestTimeout(long timeout)506     public void setTestTimeout(long timeout) {
507         mTestTimeout = timeout;
508     }
509 
510     /**
511      * Set the coverage target of this test.
512      * <p/>
513      * Currently unused. This method is just present so coverageTarget can be later retrieved via
514      * {@link #getCoverageTarget()}
515      */
setCoverageTarget(String coverageTarget)516     public void setCoverageTarget(String coverageTarget) {
517         mCoverageTarget = coverageTarget;
518     }
519 
520     /**
521      * Get the coverageTarget previously set via {@link #setCoverageTarget(String)}.
522      */
getCoverageTarget()523     public String getCoverageTarget() {
524         return mCoverageTarget;
525     }
526 
527     /**
528      * Return <code>true</code> if rerun mode is on.
529      */
isRerunMode()530     boolean isRerunMode() {
531         return mIsRerunMode;
532     }
533 
534     /** Sets whether this is a test rerun. Reruns do not create new listeners or merge coverage. */
setIsRerun(boolean isRerun)535     void setIsRerun(boolean isRerun) {
536         mIsRerun = isRerun;
537     }
538 
539     /**
540      * Optionally, set the rerun mode.
541      */
setRerunMode(boolean rerun)542     public void setRerunMode(boolean rerun) {
543         mIsRerunMode = rerun;
544     }
545 
546     /**
547      * Optionally, set the resume mode.
548      */
setResumeMode(boolean resume)549     public void setResumeMode(boolean resume) {
550         mIsResumeMode = resume;
551     }
552 
553     /**
554      * Get the shell timeout in ms.
555      */
getShellTimeout()556     long getShellTimeout() {
557         return mShellTimeout;
558     }
559 
560     /** Get the test timeout in ms. */
getTestTimeout()561     long getTestTimeout() {
562         return mTestTimeout;
563     }
564 
565     /** Returns the max timeout set for the instrumentation. */
getMaxTimeout()566     public long getMaxTimeout() {
567         return mMaxTimeout;
568     }
569 
570     /**
571      * Set the optional file to install that contains the tests.
572      *
573      * @param installFile the installable {@link File}
574      */
setInstallFile(File installFile)575     public void setInstallFile(File installFile) {
576         mInstallFile = installFile;
577     }
578 
579     /**
580      * {@inheritDoc}
581      */
582     @Override
getDevice()583     public ITestDevice getDevice() {
584         return mDevice;
585     }
586 
587     /**
588      * Set the max time in ms to allow for the 'max time to shell output response' when collecting
589      * tests.
590      * <p/>
591      * @deprecated This method is a no-op
592      */
593     @Deprecated
594     @SuppressWarnings("unused")
setCollectsTestsShellTimeout(int timeout)595     public void setCollectsTestsShellTimeout(int timeout) {
596         // no-op
597     }
598 
599     /**
600      * Set the frequency with which to automatically collect bugreports after test failures.
601      * <p />
602      * Note that there is _no feedback mechanism_ between the test runner and the bugreport
603      * collector, so use the EACH setting with due caution: if a large quantity of failures happen
604      * in rapid succession, the bugreport for a given one of the failures could end up being
605      * collected tens of minutes or hours after the respective failure occurred.
606      */
setBugreportFrequency(BugreportCollector.Freq freq)607     public void setBugreportFrequency(BugreportCollector.Freq freq) {
608         mBugreportFrequency = freq;
609     }
610 
611     /**
612      * Add an argument to provide when running the instrumentation tests.
613      *
614      * @param key the argument name
615      * @param value the argument value
616      */
addInstrumentationArg(String key, String value)617     public void addInstrumentationArg(String key, String value) {
618         mInstrArgMap.put(key, value);
619     }
620 
621     /** Allows to remove an entry from the instrumentation-arg. */
removeFromInstrumentationArg(String key)622     void removeFromInstrumentationArg(String key) {
623         mInstrArgMap.remove(key);
624     }
625 
626     /**
627      * Retrieve the value of an argument to provide when running the instrumentation tests.
628      *
629      * @param key the argument name
630      * <p/>
631      * Exposed for testing
632      */
getInstrumentationArg(String key)633     String getInstrumentationArg(String key) {
634         if (mInstrArgMap.containsKey(key)) {
635             return mInstrArgMap.get(key);
636         }
637         return null;
638     }
639 
640     /**
641      * Sets force-abi option.
642      * @param abi
643      */
setForceAbi(String abi)644     public void setForceAbi(String abi) {
645         mForceAbi = abi;
646     }
647 
getForceAbi()648     public String getForceAbi() {
649         return mForceAbi;
650     }
651 
652     /** Sets the --merge-coverage-measurements option for testing. */
653     @VisibleForTesting
setMergeCoverageMeasurements(boolean merge)654     void setMergeCoverageMeasurements(boolean merge) {
655         mMergeCoverageMeasurements = merge;
656     }
657 
658     /** Sets the --rerun-from-file option. */
setReRunUsingTestFile(boolean reRunUsingTestFile)659     public void setReRunUsingTestFile(boolean reRunUsingTestFile) {
660         mReRunUsingTestFile = reRunUsingTestFile;
661     }
662 
663     /** Sets the --fallback-to-serial-rerun option. */
setFallbackToSerialRerun(boolean reRunSerially)664     public void setFallbackToSerialRerun(boolean reRunSerially) {
665         mFallbackToSerialRerun = reRunSerially;
666     }
667 
668     /** Sets the --reboot-before-rerun option. */
setRebootBeforeReRun(boolean rebootBeforeReRun)669     public void setRebootBeforeReRun(boolean rebootBeforeReRun) {
670         mRebootBeforeReRun = rebootBeforeReRun;
671     }
672 
673     /** Allows to add more custom listeners to the runner */
addDeviceListeners(List<String> extraListeners)674     public void addDeviceListeners(List<String> extraListeners) {
675         mExtraDeviceListener.addAll(extraListeners);
676     }
677 
678     /**
679      * @return the {@link IRemoteAndroidTestRunner} to use.
680      * @throws DeviceNotAvailableException
681      */
createRemoteAndroidTestRunner(String packageName, String runnerName, IDevice device)682     IRemoteAndroidTestRunner createRemoteAndroidTestRunner(String packageName, String runnerName,
683             IDevice device) throws DeviceNotAvailableException {
684         RemoteAndroidTestRunner runner =
685                 new DefaultRemoteAndroidTestRunner(packageName, runnerName, device);
686         String abiName = resolveAbiName();
687         String runOptions = "";
688         // hidden-api-checks flag only exists in P and after.
689         // Using a temp variable to consolidate the dynamic checks
690         int apiLevel = !mHiddenApiChecks || !mWindowAnimation ? getDevice().getApiLevel() : 0;
691         if (!mHiddenApiChecks && apiLevel >= 28) {
692             runOptions += "--no-hidden-api-checks ";
693         }
694         // test-api-access flag only exists in R and after.
695         // Test API checks are subset of hidden API checks, so only make sense if hidden API
696         // checks are enabled.
697         if (mHiddenApiChecks
698                 && !mTestApiAccess
699                 && getDevice().checkApiLevelAgainstNextRelease(30)) {
700             runOptions += "--no-test-api-access ";
701         }
702         // isolated-storage flag only exists in Q and after.
703         if (!mIsolatedStorage && getDevice().checkApiLevelAgainstNextRelease(29)) {
704             runOptions += "--no-isolated-storage ";
705         }
706         // window-animation flag only exists in ICS and after
707         if (!mWindowAnimation && apiLevel >= 14) {
708             runOptions += "--no-window-animation ";
709         }
710 
711         if (abiName != null && getDevice().getApiLevel() > 20) {
712             mInstallArgs.add(String.format("--abi %s", abiName));
713             runOptions += String.format("--abi %s", abiName);
714         }
715         // Set the run options if any.
716         if (!runOptions.isEmpty()) {
717             runner.setRunOptions(runOptions);
718         }
719 
720         return runner;
721     }
722 
resolveAbiName()723     private String resolveAbiName() throws DeviceNotAvailableException {
724         if (mAbi != null && mForceAbi != null) {
725             throw new IllegalArgumentException("cannot specify both abi flags");
726         }
727         String abiName = null;
728         if (mAbi != null) {
729             abiName = mAbi.getName();
730         } else if (mForceAbi != null && !mForceAbi.isEmpty()) {
731             abiName = AbiFormatter.getDefaultAbi(mDevice, mForceAbi);
732             if (abiName == null) {
733                 throw new RuntimeException(
734                         String.format("Cannot find abi for force-abi %s", mForceAbi));
735             }
736         }
737         return abiName;
738     }
739 
740     /**
741      * Set the {@link ListInstrumentationParser}.
742      */
743     @VisibleForTesting
setListInstrumentationParser(ListInstrumentationParser listInstrumentationParser)744     void setListInstrumentationParser(ListInstrumentationParser listInstrumentationParser) {
745         mListInstrumentationParser = listInstrumentationParser;
746     }
747 
748     /**
749      * Get the {@link ListInstrumentationParser} used to parse 'pm list instrumentation' queries.
750      */
getListInstrumentationParser()751     protected ListInstrumentationParser getListInstrumentationParser() {
752         if (mListInstrumentationParser == null) {
753             mListInstrumentationParser = new ListInstrumentationParser();
754         }
755         return mListInstrumentationParser;
756     }
757 
758     /**
759      * Query the device for a test runner to use.
760      *
761      * @return the first test runner name that matches the package or null if we don't find any.
762      * @throws DeviceNotAvailableException
763      */
queryRunnerName()764     protected String queryRunnerName() throws DeviceNotAvailableException {
765         ListInstrumentationParser parser = getListInstrumentationParser();
766         getDevice().executeShellCommand("pm list instrumentation", parser);
767 
768         Set<String> candidates = new LinkedHashSet<>();
769         for (InstrumentationTarget target : parser.getInstrumentationTargets()) {
770             if (mPackageName.equals(target.packageName)) {
771                 candidates.add(target.runnerName);
772             }
773         }
774         if (candidates.isEmpty()) {
775             CLog.w("Unable to determine runner name for package: %s", mPackageName);
776             return null;
777         }
778         // Bias toward using one of the AJUR runner when available, otherwise use the first runner
779         // available.
780         Set<String> intersection =
781                 Sets.intersection(candidates, ListInstrumentationParser.SHARDABLE_RUNNERS);
782         if (intersection.isEmpty()) {
783             return candidates.iterator().next();
784         }
785         return intersection.iterator().next();
786     }
787 
788     /** {@inheritDoc} */
789     @Override
run(TestInformation testInfo, final ITestInvocationListener listener)790     public void run(TestInformation testInfo, final ITestInvocationListener listener)
791             throws DeviceNotAvailableException {
792         checkArgument(mDevice != null, "Device has not been set.");
793         checkArgument(mPackageName != null, "Package name has not been set.");
794         // Install the apk before checking the runner
795         if (mInstallFile != null) {
796             String installOutput =
797                     mDevice.installPackage(
798                             mInstallFile, true, mInstallArgs.toArray(new String[] {}));
799             if (installOutput != null) {
800                 throw new RuntimeException(
801                         String.format(
802                                 "Error while installing '%s': %s",
803                                 mInstallFile.getName(), installOutput));
804             }
805         }
806         if (mRunnerName == null) {
807             setRunnerName(queryRunnerName());
808             checkArgument(
809                     mRunnerName != null,
810                     "Runner name has not been set and no matching instrumentations were found.");
811             CLog.i("No runner name specified. Using: %s.", mRunnerName);
812         }
813         mRunner = createRemoteAndroidTestRunner(mPackageName, mRunnerName, mDevice.getIDevice());
814         setRunnerArgs(mRunner);
815 
816         doTestRun(testInfo, listener);
817         if (mInstallFile != null) {
818             mDevice.uninstallPackage(mPackageName);
819         }
820     }
821 
setRunnerArgs(IRemoteAndroidTestRunner runner)822     protected void setRunnerArgs(IRemoteAndroidTestRunner runner) {
823         if (mTestClassName != null) {
824             if (mTestMethodName != null) {
825                 runner.setMethodName(mTestClassName, mTestMethodName);
826             } else {
827                 runner.setClassName(mTestClassName);
828             }
829         } else if (mTestPackageName != null) {
830             runner.setTestPackageName(mTestPackageName);
831         }
832         if (mTestFilePathOnDevice != null) {
833             addInstrumentationArg(TEST_FILE_INST_ARGS_KEY, mTestFilePathOnDevice);
834         }
835         if (mTestSize != null) {
836             runner.setTestSize(TestSize.getTestSize(mTestSize));
837         }
838         addTimeoutsToRunner(runner);
839         if (mRunName != null) {
840             runner.setRunName(mRunName);
841         }
842         for (Map.Entry<String, String> argEntry : mInstrArgMap.entrySet()) {
843             runner.addInstrumentationArg(argEntry.getKey(), argEntry.getValue());
844         }
845     }
846 
847     /**
848      * Helper method to add test-timeout & shell-timeout timeouts to  given runner
849      */
addTimeoutsToRunner(IRemoteAndroidTestRunner runner)850     private void addTimeoutsToRunner(IRemoteAndroidTestRunner runner) {
851         if (mTimeout != null) {
852             CLog.w("\"timeout\" argument is deprecated and should not be used! \"shell-timeout\""
853                     + " argument value is overwritten with %d ms", mTimeout);
854             setShellTimeout(mTimeout);
855         }
856         if (mTestTimeout < 0) {
857             throw new IllegalArgumentException(
858                     String.format("test-timeout %d cannot be negative", mTestTimeout));
859         }
860         if (mShellTimeout <= mTestTimeout) {
861             // set shell timeout to 110% of test timeout
862             mShellTimeout = mTestTimeout + mTestTimeout / 10;
863             CLog.w(String.format("shell-timeout should be larger than test-timeout %d; "
864                     + "NOTE: extending shell-timeout to %d, please consider fixing this!",
865                     mTestTimeout, mShellTimeout));
866         }
867         runner.setMaxTimeToOutputResponse(mShellTimeout, TimeUnit.MILLISECONDS);
868         runner.setMaxTimeout(mMaxTimeout, TimeUnit.MILLISECONDS);
869         addInstrumentationArg(TEST_TIMEOUT_INST_ARGS_KEY, Long.toString(mTestTimeout));
870     }
871 
872     /**
873      * Execute test run.
874      *
875      * @param listener the test result listener
876      * @throws DeviceNotAvailableException if device stops communicating
877      */
doTestRun(TestInformation testInfo, ITestInvocationListener listener)878     private void doTestRun(TestInformation testInfo, ITestInvocationListener listener)
879             throws DeviceNotAvailableException {
880         // If this is a dry-run, just collect the tests and return
881         if (mCollectTestsOnly) {
882             checkState(
883                     mTestsToRun == null,
884                     "Tests to run should not be set explicitly when --collect-tests-only is set.");
885 
886             // Use the actual listener to collect the tests, and print a error if this fails
887             Collection<TestDescription> collectedTests = collectTestsToRun(mRunner, listener);
888             if (collectedTests == null) {
889                 CLog.e("Failed to collect tests for %s", mPackageName);
890             } else {
891                 CLog.i("Collected %d tests for %s", collectedTests.size(), mPackageName);
892             }
893             return;
894         }
895 
896         // If the tests to run weren't provided explicitly, collect them.
897         Collection<TestDescription> testsToRun = mTestsToRun;
898         if (testsToRun == null) {
899             // Don't notify the listener since it's not a real run.
900             testsToRun = collectTestsToRun(mRunner, null);
901         }
902 
903         // Only set the debug flag after collecting tests.
904         if (mDebug) {
905             mRunner.setDebug(true);
906         }
907         if (mConfiguration != null && mConfiguration.getCoverageOptions().isCoverageEnabled()) {
908             mRunner.addInstrumentationArg("coverage", "true");
909         }
910 
911         // Reruns do not create new listeners or clear coverage measurements.
912         if (!mIsRerun) {
913             listener = addBugreportListenerIfEnabled(listener);
914             listener = addJavaCoverageListenerIfEnabled(listener);
915             listener = addGcovCoverageListenerIfEnabled(listener);
916             listener = addClangCoverageListenerIfEnabled(listener);
917 
918             // Clear coverage measurements on the device before running.
919             if (mConfiguration != null
920                     && mConfiguration.getCoverageOptions().isCoverageFlushEnabled()) {
921                 CoverageOptions options = mConfiguration.getCoverageOptions();
922 
923                 if (options.getCoverageToolchains().contains(GCOV)
924                         || options.getCoverageToolchains().contains(CLANG)) {
925                     // Enable abd root on the device, otherwise the following commands will fail.
926                     verify(mDevice.enableAdbRoot(), "Failed to enable adb root.");
927 
928                     NativeCodeCoverageFlusher flusher =
929                             new NativeCodeCoverageFlusher(mDevice, options.getCoverageProcesses());
930                     flusher.resetCoverage();
931                 }
932 
933                 if (options.getCoverageToolchains().contains(JACOCO)) {
934                     JavaCodeCoverageFlusher flusher =
935                             new JavaCodeCoverageFlusher(mDevice, options.getCoverageProcesses());
936                     flusher.resetCoverage();
937                 }
938             }
939 
940             // TODO: Convert to device-side collectors when possible.
941             for (IMetricCollector collector : mCollectors) {
942                 if (collector.isDisabled()) {
943                     CLog.d("%s has been disabled. Skipping.", collector);
944                 } else {
945                     CLog.d(
946                             "Initializing %s for instrumentation.",
947                             collector.getClass().getCanonicalName());
948                     listener = collector.init(testInfo.getContext(), listener);
949                 }
950             }
951         }
952 
953         // Add the extra listeners only to the actual run and not the --collect-test-only one
954         if (!mExtraDeviceListener.isEmpty()) {
955             mRunner.addInstrumentationArg("listener", ArrayUtil.join(",", mExtraDeviceListener));
956         }
957 
958         if (testsToRun == null) {
959             // Failed to collect the tests or collection is off. Just try to run them all.
960             mDevice.runInstrumentationTests(mRunner, listener);
961         } else if (!testsToRun.isEmpty()) {
962             runWithRerun(testInfo, listener, testsToRun);
963         } else {
964             CLog.i("No tests expected for %s, skipping", mPackageName);
965         }
966 
967         // Merge coverage measurements after all tests have been run, but not inside the rerun
968         // itself since the merging will be handled by the caller.
969         if (!mIsRerun && mMergeCoverageMeasurements) {
970             listener.testRunStarted(MERGE_COVERAGE_MEASUREMENTS_TEST_NAME, 0);
971             listener.testRunEnded(0, new HashMap<String, Metric>());
972         }
973     }
974 
975     /**
976      * Returns a listener that will collect bugreports, or the original {@code listener} if this
977      * feature is disabled.
978      */
addBugreportListenerIfEnabled(ITestInvocationListener listener)979     ITestInvocationListener addBugreportListenerIfEnabled(ITestInvocationListener listener) {
980         if (mBugreportFrequency != null) {
981             // Collect a bugreport after EACH/FIRST failed testcase
982             BugreportCollector.Predicate pred = new BugreportCollector.Predicate(
983                     BugreportCollector.Relation.AFTER,
984                     mBugreportFrequency,
985                     BugreportCollector.Noun.FAILED_TESTCASE);
986             BugreportCollector collector = new BugreportCollector(listener, getDevice());
987             collector.addPredicate(pred);
988             listener = collector;
989         }
990         return listener;
991     }
992 
993     /**
994      * Returns a listener that will collect coverage measurements, or the original {@code listener}
995      * if this feature is disabled.
996      */
addJavaCoverageListenerIfEnabled(ITestInvocationListener listener)997     ITestInvocationListener addJavaCoverageListenerIfEnabled(ITestInvocationListener listener) {
998         if (mConfiguration == null) {
999             return listener;
1000         }
1001         if (mConfiguration.getCoverageOptions().isCoverageEnabled()
1002                 && mConfiguration.getCoverageOptions().getCoverageToolchains().contains(JACOCO)) {
1003             return new JavaCodeCoverageListener(
1004                     getDevice(),
1005                     mConfiguration.getCoverageOptions(),
1006                     mMergeCoverageMeasurements,
1007                     listener);
1008         }
1009         return listener;
1010     }
1011 
1012     /**
1013      * Returns a listener that will collect gcov coverage measurements, or the original {@code
1014      * listener} if this feature is disabled.
1015      */
addGcovCoverageListenerIfEnabled(ITestInvocationListener listener)1016     ITestInvocationListener addGcovCoverageListenerIfEnabled(ITestInvocationListener listener) {
1017         if (mConfiguration == null) {
1018             return listener;
1019         }
1020         if (mConfiguration.getCoverageOptions().isCoverageEnabled()
1021                 && mConfiguration.getCoverageOptions().getCoverageToolchains().contains(GCOV)) {
1022             mNativeCoverageListener =
1023                     new NativeCodeCoverageListener(
1024                             getDevice(), mConfiguration.getCoverageOptions(), listener);
1025             return mNativeCoverageListener;
1026         }
1027         return listener;
1028     }
1029 
1030     /**
1031      * Returns a listener that will collect Clang coverage measurements, or the original {@code
1032      * listener} if this feature is disabled.
1033      */
addClangCoverageListenerIfEnabled(ITestInvocationListener listener)1034     ITestInvocationListener addClangCoverageListenerIfEnabled(ITestInvocationListener listener) {
1035         if (mConfiguration == null) {
1036             return listener;
1037         }
1038         if (mConfiguration.getCoverageOptions().isCoverageEnabled()
1039                 && mConfiguration.getCoverageOptions().getCoverageToolchains().contains(CLANG)) {
1040             ClangCodeCoverageListener clangListener =
1041                     new ClangCodeCoverageListener(getDevice(), listener);
1042             clangListener.setConfiguration(mConfiguration);
1043             return clangListener;
1044         }
1045         return listener;
1046     }
1047 
1048     /**
1049      * Execute the test run, but re-run incomplete tests individually if run fails to complete.
1050      *
1051      * @param listener the {@link ITestInvocationListener}
1052      * @param expectedTests the full set of expected tests in this run.
1053      */
runWithRerun( TestInformation testInfo, final ITestInvocationListener listener, Collection<TestDescription> expectedTests)1054     private void runWithRerun(
1055             TestInformation testInfo,
1056             final ITestInvocationListener listener,
1057             Collection<TestDescription> expectedTests)
1058             throws DeviceNotAvailableException {
1059         CollectingTestListener testTracker = new CollectingTestListener();
1060         // Our dedicated listener that allows to perform checks for the harness and collect
1061         // the appropriate data.
1062         InstrumentationListener instrumentationListener =
1063                 new InstrumentationListener(getDevice(), expectedTests, listener, testTracker);
1064         instrumentationListener.setDisableDuplicateCheck(mDisableDuplicateCheck);
1065         if (mEnableSoftRestartCheck) {
1066             instrumentationListener.setOriginalSystemServer(
1067                     getDevice().getProcessByName("system_server"));
1068         }
1069         instrumentationListener.setReportUnexecutedTests(mReportUnexecuted);
1070         mDevice.runInstrumentationTests(mRunner, instrumentationListener);
1071         TestRunResult testRun = testTracker.getCurrentRunResults();
1072         if (testRun.isRunFailure() || !testRun.getCompletedTests().containsAll(expectedTests)) {
1073             // Don't re-run any completed tests, unless this is a coverage run.
1074             if (mConfiguration != null
1075                     && !mConfiguration.getCoverageOptions().isCoverageEnabled()) {
1076                 expectedTests.removeAll(excludeNonExecuted(testTracker.getCurrentRunResults()));
1077                 IRetryDecision decision = mConfiguration.getRetryDecision();
1078                 if (!RetryStrategy.NO_RETRY.equals(decision.getRetryStrategy())
1079                         && decision.getMaxRetryCount() > 1) {
1080                     // Delegate retry to the module/invocation level.
1081                     // This prevents the InstrumentationTest retry from re-running by itself and
1082                     // creating overhead.
1083                     return;
1084                 }
1085             }
1086             rerunTests(expectedTests, testInfo, listener);
1087         }
1088     }
1089 
1090     /** Filter out "NOT_EXECUTED" for the purpose of tracking what needs to be rerun. */
excludeNonExecuted(TestRunResult results)1091     protected static Set<TestDescription> excludeNonExecuted(TestRunResult results) {
1092         Set<TestDescription> completedTest = results.getCompletedTests();
1093         for (Entry<TestDescription, TestResult> entry : results.getTestResults().entrySet()) {
1094             if (completedTest.contains(entry.getKey()) && entry.getValue().getFailure() != null) {
1095                 if (FailureStatus.NOT_EXECUTED.equals(
1096                         entry.getValue().getFailure().getFailureStatus())) {
1097                     completedTest.remove(entry.getKey());
1098                 }
1099             }
1100         }
1101         return completedTest;
1102     }
1103 
1104     /**
1105      * Rerun any <var>mRemainingTests</var>
1106      *
1107      * @param listener the {@link ITestInvocationListener}
1108      * @throws DeviceNotAvailableException
1109      */
rerunTests( Collection<TestDescription> expectedTests, TestInformation testInfo, final ITestInvocationListener listener)1110     private void rerunTests(
1111             Collection<TestDescription> expectedTests,
1112             TestInformation testInfo,
1113             final ITestInvocationListener listener)
1114             throws DeviceNotAvailableException {
1115         if (expectedTests.isEmpty()) {
1116             CLog.d("No tests to re-run, all tests executed at least once.");
1117             return;
1118         }
1119         if (mRebootBeforeReRun) {
1120             mDevice.reboot();
1121         } else {
1122             // Ensure device is online and responsive before retrying.
1123             mDevice.waitForDeviceAvailable();
1124         }
1125 
1126         IRemoteTest testReRunner = null;
1127         try {
1128             testReRunner = getTestReRunner(expectedTests);
1129         } catch (ConfigurationException e) {
1130             CLog.e("Failed to create test runner: %s", e.getMessage());
1131             return;
1132         }
1133 
1134         if (mNativeCoverageListener != null) {
1135             mNativeCoverageListener.setCollectOnTestEnd(false);
1136         }
1137 
1138         testReRunner.run(testInfo, listener);
1139 
1140         if (mNativeCoverageListener != null) {
1141             mNativeCoverageListener.setCollectOnTestEnd(true);
1142             mNativeCoverageListener.logCoverageMeasurements("rerun_merged");
1143         }
1144     }
1145 
1146     @VisibleForTesting
getTestReRunner(Collection<TestDescription> tests)1147     IRemoteTest getTestReRunner(Collection<TestDescription> tests) throws ConfigurationException {
1148         if (mReRunUsingTestFile) {
1149             return new InstrumentationFileTest(
1150                     this, tests, mFallbackToSerialRerun, mReRunUsingTestFileAttempts);
1151         } else {
1152             // Since the same runner is reused we must ensure TEST_FILE_INST_ARGS_KEY is not set.
1153             // Otherwise, the runner will attempt to execute tests from file.
1154             mInstrArgMap.remove(TEST_FILE_INST_ARGS_KEY);
1155             return new InstrumentationSerialTest(this, tests);
1156         }
1157     }
1158 
1159     /**
1160      * Collect the list of tests that should be executed by this test run.
1161      *
1162      * <p>This will be done by executing the test run in 'logOnly' mode, and recording the list of
1163      * tests.
1164      *
1165      * @param runner the {@link IRemoteAndroidTestRunner} to use to run the tests.
1166      * @return a {@link Collection} of {@link TestDescription}s that represent all tests to be
1167      *     executed by this run
1168      * @throws DeviceNotAvailableException
1169      */
collectTestsToRun( final IRemoteAndroidTestRunner runner, final ITestInvocationListener listener)1170     private Collection<TestDescription> collectTestsToRun(
1171             final IRemoteAndroidTestRunner runner, final ITestInvocationListener listener)
1172             throws DeviceNotAvailableException {
1173         if (isRerunMode()) {
1174             Log.d(LOG_TAG, String.format("Collecting test info for %s on device %s",
1175                     mPackageName, mDevice.getSerialNumber()));
1176             runner.setTestCollection(true);
1177             // always explicitly set debug to false when collecting tests
1178             runner.setDebug(false);
1179             // try to collect tests multiple times, in case device is temporarily not available
1180             // on first attempt
1181             Collection<TestDescription> tests = collectTestsAndRetry(runner, listener);
1182             // done with "logOnly" mode, restore proper test timeout before real test execution
1183             addTimeoutsToRunner(runner);
1184             runner.setTestCollection(false);
1185             return tests;
1186         }
1187         return null;
1188     }
1189 
1190     /**
1191      * Performs the actual work of collecting tests, making multiple attempts if necessary
1192      *
1193      * @param runner the {@link IRemoteAndroidTestRunner} that will be used for the instrumentation
1194      * @param listener the {ITestInvocationListener} where to report results, can be null if we are
1195      *     not reporting the results to the main invocation and simply collecting tests.
1196      * @return the collection of tests, or <code>null</code> if tests could not be collected
1197      * @throws DeviceNotAvailableException if communication with the device was lost
1198      */
1199     @VisibleForTesting
collectTestsAndRetry( final IRemoteAndroidTestRunner runner, final ITestInvocationListener listener)1200     Collection<TestDescription> collectTestsAndRetry(
1201             final IRemoteAndroidTestRunner runner, final ITestInvocationListener listener)
1202             throws DeviceNotAvailableException {
1203         boolean communicationFailure = false;
1204         for (int i=0; i < COLLECT_TESTS_ATTEMPTS; i++) {
1205             CollectingTestListener collector = new CollectingTestListener();
1206             boolean instrResult = false;
1207             // We allow to override the ddmlib default timeout for collection of tests.
1208             runner.setMaxTimeToOutputResponse(mCollectTestTimeout, TimeUnit.MILLISECONDS);
1209             if (listener == null) {
1210                 instrResult = mDevice.runInstrumentationTests(runner, collector);
1211             } else {
1212                 instrResult = mDevice.runInstrumentationTests(runner, collector, listener);
1213             }
1214             TestRunResult runResults = collector.getCurrentRunResults();
1215             if (!instrResult || !runResults.isRunComplete()) {
1216                 // communication failure with device, retry
1217                 Log.w(LOG_TAG, String.format(
1218                         "No results when collecting tests to run for %s on device %s. Retrying",
1219                         mPackageName, mDevice.getSerialNumber()));
1220                 communicationFailure = true;
1221             } else if (runResults.isRunFailure()) {
1222                 // not a communication failure, but run still failed.
1223                 // TODO: should retry be attempted
1224                 CLog.w("Run failure %s when collecting tests to run for %s on device %s.",
1225                         runResults.getRunFailureMessage(), mPackageName,
1226                         mDevice.getSerialNumber());
1227                 return null;
1228             } else {
1229                 // success!
1230                 return runResults.getCompletedTests();
1231             }
1232         }
1233         if (communicationFailure) {
1234             // TODO: find a better way to handle this
1235             // throwing DeviceUnresponsiveException is not always ideal because a misbehaving
1236             // instrumentation can hang, even though device is responsive. Would be nice to have
1237             // a louder signal for this situation though than just logging an error
1238 //            throw new DeviceUnresponsiveException(String.format(
1239 //                    "Communication failure when attempting to collect tests %s on device %s",
1240 //                    mPackageName, mDevice.getSerialNumber()));
1241             CLog.w("Ignoring repeated communication failure when collecting tests %s for device %s",
1242                     mPackageName, mDevice.getSerialNumber());
1243         }
1244         CLog.e("Failed to collect tests to run for %s on device %s.",
1245                 mPackageName, mDevice.getSerialNumber());
1246         return null;
1247     }
1248 
1249     /**
1250      * {@inheritDoc}
1251      */
1252     @Override
setCollectTestsOnly(boolean shouldCollectTest)1253     public void setCollectTestsOnly(boolean shouldCollectTest) {
1254         mCollectTestsOnly = shouldCollectTest;
1255     }
1256 
1257     @Override
setAbi(IAbi abi)1258     public void setAbi(IAbi abi) {
1259         mAbi = abi;
1260     }
1261 
1262     @Override
getAbi()1263     public IAbi getAbi() {
1264         return mAbi;
1265     }
1266 
1267     @Override
setMetricCollectors(List<IMetricCollector> collectors)1268     public void setMetricCollectors(List<IMetricCollector> collectors) {
1269         mCollectors = collectors;
1270     }
1271 
1272     /** Set True if we enforce the AJUR output format of instrumentation. */
setEnforceFormat(boolean enforce)1273     public void setEnforceFormat(boolean enforce) {
1274         mShouldEnforceFormat = enforce;
1275     }
1276 
1277     /**
1278      * Set the instrumentation debug setting.
1279      *
1280      * @param debug boolean value to set the instrumentation debug setting to.
1281      */
setDebug(boolean debug)1282     public void setDebug(boolean debug) {
1283         mDebug = debug;
1284     }
1285 
1286     /**
1287      * Get the instrumentation debug setting.
1288      *
1289      * @return The boolean debug setting.
1290      */
getDebug()1291     public boolean getDebug() {
1292         return mDebug;
1293     }
1294 
1295     /** Set wether or not to use the isolated storage. */
setIsolatedStorage(boolean isolatedStorage)1296     public void setIsolatedStorage(boolean isolatedStorage) {
1297         mIsolatedStorage = isolatedStorage;
1298     }
1299 }
1300