• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package com.android.tradefed.device.metric;
17 
18 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey;
19 import com.android.tradefed.build.IBuildInfo;
20 import com.android.tradefed.build.IDeviceBuildInfo;
21 import com.android.tradefed.config.Option;
22 import com.android.tradefed.device.DeviceNotAvailableException;
23 import com.android.tradefed.device.IDeviceActionReceiver;
24 import com.android.tradefed.device.ITestDevice;
25 import com.android.tradefed.device.StubDevice;
26 import com.android.tradefed.invoker.IInvocationContext;
27 import com.android.tradefed.invoker.logger.InvocationMetricLogger;
28 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey;
29 import com.android.tradefed.invoker.tracing.CloseableTraceScope;
30 import com.android.tradefed.log.LogUtil.CLog;
31 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
32 import com.android.tradefed.result.FailureDescription;
33 import com.android.tradefed.result.ILogSaver;
34 import com.android.tradefed.result.ILogSaverListener;
35 import com.android.tradefed.result.ITestInvocationListener;
36 import com.android.tradefed.result.InputStreamSource;
37 import com.android.tradefed.result.LogDataType;
38 import com.android.tradefed.result.LogFile;
39 import com.android.tradefed.result.TestDescription;
40 import com.android.tradefed.result.proto.TestRecordProto.FailureStatus;
41 import com.android.tradefed.result.skipped.SkipReason;
42 import com.android.tradefed.testtype.suite.ModuleDefinition;
43 import com.android.tradefed.util.FileUtil;
44 import com.android.tradefed.util.SearchArtifactUtil;
45 
46 import java.io.File;
47 import java.io.IOException;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Set;
55 import java.util.stream.Collectors;
56 
57 /**
58  * Base implementation of {@link IMetricCollector} that allows to start and stop collection on
59  * {@link #onTestRunStart(DeviceMetricData)} and {@link #onTestRunEnd(DeviceMetricData, Map)}.
60  */
61 public class BaseDeviceMetricCollector implements IMetricCollector, IDeviceActionReceiver {
62 
63     public static final String TEST_CASE_INCLUDE_GROUP_OPTION = "test-case-include-group";
64     public static final String TEST_CASE_EXCLUDE_GROUP_OPTION = "test-case-exclude-group";
65 
66     @Option(name = "disable", description = "disables the metrics collector")
67     private boolean mDisable = false;
68 
69     @Option(
70         name = TEST_CASE_INCLUDE_GROUP_OPTION,
71         description =
72                 "Specify a group to include as part of the collection,"
73                         + "group can be specified via @MetricOption. Can be repeated."
74                         + "Usage: @MetricOption(group = \"groupname\") to your test methods, then"
75                         + "use --test-case-include-anotation groupename to only run your group."
76     )
77     private List<String> mTestCaseIncludeAnnotationGroup = new ArrayList<>();
78 
79     @Option(
80         name = TEST_CASE_EXCLUDE_GROUP_OPTION,
81         description =
82                 "Specify a group to exclude from the metric collection,"
83                         + "group can be specified via @MetricOption. Can be repeated."
84     )
85     private List<String> mTestCaseExcludeAnnotationGroup = new ArrayList<>();
86 
87     private IInvocationContext mContext;
88     private List<ITestDevice> mRealDeviceList;
89     private ITestInvocationListener mForwarder;
90     private Map<String, File> mTestArtifactFilePathMap = new HashMap<>();
91     private DeviceMetricData mRunData;
92     private DeviceMetricData mTestData;
93     private String mRunName;
94 
95     /**
96      * Variable for whether or not to skip the collection of one test case because it was filtered.
97      */
98     private boolean mSkipTestCase = false;
99     /** Whether or not the collector was initialized already or not. */
100     private boolean mWasInitDone = false;
101     /** Whether or not a DNAE occurred and we should stop collection. */
102     private boolean mDeviceNoAvailable = false;
103     /** Whether the {@link IDeviceActionReceiver} should be disabled or not. */
104     private boolean mDisableReceiver = true;
105 
106     @Override
init( IInvocationContext context, ITestInvocationListener listener)107     public final ITestInvocationListener init(
108             IInvocationContext context, ITestInvocationListener listener)
109             throws DeviceNotAvailableException {
110         mContext = context;
111         mForwarder = listener;
112         if (mWasInitDone) {
113             throw new IllegalStateException(
114                     String.format("init was called a second time on %s", this));
115         }
116         mWasInitDone = true;
117         mDeviceNoAvailable = false;
118         // Register this collector for device action events.
119         if (!isDisabledReceiver()) {
120             for (ITestDevice device : getRealDevices()) {
121                 device.registerDeviceActionReceiver(this);
122             }
123         }
124         long start = System.currentTimeMillis();
125         try {
126             extraInit(context, listener);
127         } finally {
128             InvocationMetricLogger.addInvocationMetrics(
129                     InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
130         }
131         return this;
132     }
133 
134     /**
135      * @param context
136      * @param listener
137      * @throws DeviceNotAvailableException
138      */
extraInit(IInvocationContext context, ITestInvocationListener listener)139     public void extraInit(IInvocationContext context, ITestInvocationListener listener)
140             throws DeviceNotAvailableException {
141         // Empty by default
142     }
143 
144     @Override
getDevices()145     public final List<ITestDevice> getDevices() {
146         return mContext.getDevices();
147     }
148 
149     /** Returns all the non-stub devices from the {@link #getDevices()} list. */
getRealDevices()150     public final List<ITestDevice> getRealDevices() {
151         if (mRealDeviceList == null) {
152             mRealDeviceList =
153                     mContext.getDevices()
154                             .stream()
155                             .filter(d -> !(d.getIDevice() instanceof StubDevice))
156                             .collect(Collectors.toList());
157         }
158         return mRealDeviceList;
159     }
160 
161     /**
162      * Retrieve the file from the test artifacts or module artifacts and cache
163      * it in a map for the subsequent calls.
164      *
165      * @param fileName name of the file to look up in the artifacts.
166      * @return File from the test artifact or module artifact. Returns null
167      *         if file is not found.
168      */
getFileFromTestArtifacts(String fileName)169     public File getFileFromTestArtifacts(String fileName) {
170         if (mTestArtifactFilePathMap.containsKey(fileName)) {
171             return mTestArtifactFilePathMap.get(fileName);
172         }
173 
174         File resolvedFile = resolveRelativeFilePath(fileName);
175         if (resolvedFile != null) {
176             CLog.i("Using file %s from %s", fileName, resolvedFile.getAbsolutePath());
177             mTestArtifactFilePathMap.put(fileName, resolvedFile);
178         }
179         return resolvedFile;
180     }
181 
182     @Override
getBuildInfos()183     public final List<IBuildInfo> getBuildInfos() {
184         return mContext.getBuildInfos();
185     }
186 
187     @Override
getInvocationListener()188     public final ITestInvocationListener getInvocationListener() {
189         return mForwarder;
190     }
191 
192     @Override
onTestModuleStarted()193     public void onTestModuleStarted() throws DeviceNotAvailableException {
194         // Does nothing
195     }
196 
197     @Override
onTestModuleEnded()198     public void onTestModuleEnded() throws DeviceNotAvailableException {
199         // Does nothing
200     }
201 
202     @Override
onTestRunStart(DeviceMetricData runData)203     public void onTestRunStart(DeviceMetricData runData) throws DeviceNotAvailableException {
204         // Does nothing
205     }
206 
207     /**
208      * Callback for testRunFailed events
209      *
210      * @param testData
211      * @param failure
212      * @throws DeviceNotAvailableException
213      */
onTestRunFailed(DeviceMetricData testData, FailureDescription failure)214     public void onTestRunFailed(DeviceMetricData testData, FailureDescription failure)
215             throws DeviceNotAvailableException {
216         // Does nothing
217     }
218 
219     @Override
onTestRunEnd(DeviceMetricData runData, final Map<String, Metric> currentRunMetrics)220     public void onTestRunEnd(DeviceMetricData runData, final Map<String, Metric> currentRunMetrics)
221             throws DeviceNotAvailableException {
222         // Does nothing
223     }
224 
225     @Override
onTestStart(DeviceMetricData testData)226     public void onTestStart(DeviceMetricData testData) throws DeviceNotAvailableException {
227         // Does nothing
228     }
229 
230     @Override
onTestFail(DeviceMetricData testData, TestDescription test)231     public void onTestFail(DeviceMetricData testData, TestDescription test)
232             throws DeviceNotAvailableException {
233         // Does nothing
234     }
235 
236     @Override
onTestAssumptionFailure(DeviceMetricData testData, TestDescription test)237     public void onTestAssumptionFailure(DeviceMetricData testData, TestDescription test)
238             throws DeviceNotAvailableException {
239         // Does nothing
240     }
241 
242     @Override
onTestEnd( DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics)243     public void onTestEnd(
244             DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics)
245             throws DeviceNotAvailableException {
246         // Does nothing
247     }
248 
249     @Override
onTestEnd( DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics, TestDescription test)250     public void onTestEnd(
251             DeviceMetricData testData,
252             final Map<String, Metric> currentTestCaseMetrics,
253             TestDescription test)
254             throws DeviceNotAvailableException {
255         // Call the default implementation of onTestEnd if not overridden
256         onTestEnd(testData, currentTestCaseMetrics);
257     }
258 
259     /** =================================== */
260     /** Invocation Listeners for forwarding */
261     @Override
invocationStarted(IInvocationContext context)262     public final void invocationStarted(IInvocationContext context) {
263         mForwarder.invocationStarted(context);
264     }
265 
266     @Override
invocationFailed(Throwable cause)267     public final void invocationFailed(Throwable cause) {
268         mForwarder.invocationFailed(cause);
269     }
270 
271     @Override
invocationFailed(FailureDescription failure)272     public final void invocationFailed(FailureDescription failure) {
273         mForwarder.invocationFailed(failure);
274     }
275 
276     @Override
invocationSkipped(SkipReason reason)277     public void invocationSkipped(SkipReason reason) {
278         mForwarder.invocationSkipped(reason);
279     }
280 
281     @Override
invocationEnded(long elapsedTime)282     public final void invocationEnded(long elapsedTime) {
283         mForwarder.invocationEnded(elapsedTime);
284     }
285 
286     @Override
testLog(String dataName, LogDataType dataType, InputStreamSource dataStream)287     public final void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) {
288         mForwarder.testLog(dataName, dataType, dataStream);
289     }
290 
291     @Override
testModuleStarted(IInvocationContext moduleContext)292     public final void testModuleStarted(IInvocationContext moduleContext) {
293         long start = System.currentTimeMillis();
294         try (CloseableTraceScope ignored =
295                 new CloseableTraceScope("module_start_" + this.getClass().getSimpleName())) {
296             onTestModuleStarted();
297         } catch (DeviceNotAvailableException dnae) {
298             mDeviceNoAvailable = true;
299             CLog.e(dnae);
300         } catch (Throwable t) {
301             CLog.e(t);
302         } finally {
303             InvocationMetricLogger.addInvocationMetrics(
304                     InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
305             mForwarder.testModuleStarted(moduleContext);
306         }
307     }
308 
309     @Override
testModuleEnded()310     public final void testModuleEnded() {
311         long start = System.currentTimeMillis();
312         try (CloseableTraceScope ignored =
313                 new CloseableTraceScope("module_end_" + this.getClass().getSimpleName())) {
314             onTestModuleEnded();
315         } catch (DeviceNotAvailableException dnae) {
316             CLog.e(dnae);
317         } catch (Throwable t) {
318             CLog.e(t);
319         } finally {
320             // De-register this collector from device action events
321             if (!isDisabledReceiver()) {
322                 for (ITestDevice device : getRealDevices()) {
323                     device.deregisterDeviceActionReceiver(this);
324                 }
325             }
326             InvocationMetricLogger.addInvocationMetrics(
327                     InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
328             mForwarder.testModuleEnded();
329         }
330     }
331 
332     /** Test run callbacks */
333     @Override
testRunStarted(String runName, int testCount)334     public final void testRunStarted(String runName, int testCount) {
335         testRunStarted(runName, testCount, 0);
336     }
337 
338     @Override
testRunStarted(String runName, int testCount, int attemptNumber)339     public final void testRunStarted(String runName, int testCount, int attemptNumber) {
340         testRunStarted(runName, testCount, 0, System.currentTimeMillis());
341     }
342 
343     @Override
testRunStarted( String runName, int testCount, int attemptNumber, long startTime)344     public final void testRunStarted(
345             String runName, int testCount, int attemptNumber, long startTime) {
346         mRunData = new DeviceMetricData(mContext);
347         mRunName = runName;
348         mDeviceNoAvailable = false;
349         long start = System.currentTimeMillis();
350         try (CloseableTraceScope ignored =
351                 new CloseableTraceScope("run_start_" + this.getClass().getSimpleName())) {
352             onTestRunStart(mRunData, testCount);
353         } catch (DeviceNotAvailableException e) {
354             mDeviceNoAvailable = true;
355             CLog.e(e);
356         } catch (Throwable t) {
357             // Prevent exception from messing up the status reporting.
358             CLog.e(t);
359         } finally {
360             InvocationMetricLogger.addInvocationMetrics(
361                     InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
362         }
363         mForwarder.testRunStarted(runName, testCount, attemptNumber, startTime);
364     }
365 
366     @Override
testRunFailed(String errorMessage)367     public final void testRunFailed(String errorMessage) {
368         if (!mDeviceNoAvailable) {
369             long start = System.currentTimeMillis();
370             try {
371                 onTestRunFailed(mRunData, FailureDescription.create(errorMessage));
372             } catch (DeviceNotAvailableException e) {
373                 mDeviceNoAvailable = true;
374                 CLog.e(e);
375             } catch (Throwable t) {
376                 // Prevent exception from messing up the status reporting.
377                 CLog.e(t);
378             } finally {
379                 InvocationMetricLogger.addInvocationMetrics(
380                         InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
381             }
382         }
383         mForwarder.testRunFailed(errorMessage);
384     }
385 
386     @Override
testRunFailed(FailureDescription failure)387     public final void testRunFailed(FailureDescription failure) {
388         if (!mDeviceNoAvailable) {
389             long start = System.currentTimeMillis();
390             try {
391                 onTestRunFailed(mRunData, failure);
392             } catch (DeviceNotAvailableException e) {
393                 mDeviceNoAvailable = true;
394                 CLog.e(e);
395             } catch (Throwable t) {
396                 // Prevent exception from messing up the status reporting.
397                 CLog.e(t);
398             } finally {
399                 InvocationMetricLogger.addInvocationMetrics(
400                         InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
401             }
402         }
403         mForwarder.testRunFailed(failure);
404     }
405 
406     @Override
testRunStopped(long elapsedTime)407     public final void testRunStopped(long elapsedTime) {
408         mForwarder.testRunStopped(elapsedTime);
409     }
410 
411     @Override
testRunEnded(long elapsedTime, HashMap<String, Metric> runMetrics)412     public final void testRunEnded(long elapsedTime, HashMap<String, Metric> runMetrics) {
413         if (!mDeviceNoAvailable) {
414             long start = System.currentTimeMillis();
415             try (CloseableTraceScope ignored =
416                     new CloseableTraceScope("run_end_" + this.getClass().getSimpleName())) {
417                 onTestRunEnd(mRunData, runMetrics);
418                 mRunData.addToMetrics(runMetrics);
419             } catch (DeviceNotAvailableException e) {
420                 mDeviceNoAvailable = true;
421                 CLog.e(e);
422             } catch (Throwable t) {
423                 // Prevent exception from messing up the status reporting.
424                 CLog.e(t);
425             } finally {
426                 // De-register this collector from device action events
427                 if (!isDisabledReceiver()) {
428                     for (ITestDevice device : getRealDevices()) {
429                         device.deregisterDeviceActionReceiver(this);
430                     }
431                 }
432                 InvocationMetricLogger.addInvocationMetrics(
433                         InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
434             }
435         }
436         mForwarder.testRunEnded(elapsedTime, runMetrics);
437     }
438 
439     /** Test cases callbacks */
440     @Override
testStarted(TestDescription test)441     public final void testStarted(TestDescription test) {
442         testStarted(test, System.currentTimeMillis());
443     }
444 
445     @Override
testStarted(TestDescription test, long startTime)446     public final void testStarted(TestDescription test, long startTime) {
447         if (!mDeviceNoAvailable) {
448             mTestData = new DeviceMetricData(mContext);
449             mSkipTestCase = shouldSkip(test);
450             if (!mSkipTestCase) {
451                 long start = System.currentTimeMillis();
452                 try {
453                     onTestStart(mTestData);
454                 } catch (DeviceNotAvailableException e) {
455                     mDeviceNoAvailable = true;
456                     CLog.e(e);
457                 } catch (Throwable t) {
458                     // Prevent exception from messing up the status reporting.
459                     CLog.e(t);
460                 } finally {
461                     InvocationMetricLogger.addInvocationMetrics(
462                             InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
463                 }
464             }
465         }
466         mForwarder.testStarted(test, startTime);
467     }
468 
469     @Override
testFailed(TestDescription test, String trace)470     public final void testFailed(TestDescription test, String trace) {
471         if (!mSkipTestCase && !mDeviceNoAvailable) {
472             long start = System.currentTimeMillis();
473             try {
474                 onTestFail(mTestData, test);
475             } catch (DeviceNotAvailableException e) {
476                 mDeviceNoAvailable = true;
477                 CLog.e(e);
478             } catch (Throwable t) {
479                 // Prevent exception from messing up the status reporting.
480                 CLog.e(t);
481             } finally {
482                 InvocationMetricLogger.addInvocationMetrics(
483                         InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
484             }
485         }
486         mForwarder.testFailed(test, trace);
487     }
488 
489     @Override
testFailed(TestDescription test, FailureDescription failure)490     public final void testFailed(TestDescription test, FailureDescription failure) {
491         if (!mSkipTestCase && !mDeviceNoAvailable) {
492             // Don't collect on not_executed test case
493             if (failure.getFailureStatus() == null
494                     || !FailureStatus.NOT_EXECUTED.equals(failure.getFailureStatus())) {
495                 long start = System.currentTimeMillis();
496                 try {
497                     onTestFail(mTestData, test);
498                 } catch (DeviceNotAvailableException e) {
499                     mDeviceNoAvailable = true;
500                     CLog.e(e);
501                 } catch (Throwable t) {
502                     // Prevent exception from messing up the status reporting.
503                     CLog.e(t);
504                 } finally {
505                     InvocationMetricLogger.addInvocationMetrics(
506                             InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
507                 }
508             }
509         }
510         mForwarder.testFailed(test, failure);
511     }
512 
513     @Override
testEnded(TestDescription test, HashMap<String, Metric> testMetrics)514     public final void testEnded(TestDescription test, HashMap<String, Metric> testMetrics) {
515         testEnded(test, System.currentTimeMillis(), testMetrics);
516     }
517 
518     @Override
testEnded( TestDescription test, long endTime, HashMap<String, Metric> testMetrics)519     public final void testEnded(
520             TestDescription test, long endTime, HashMap<String, Metric> testMetrics) {
521         if (!mSkipTestCase && !mDeviceNoAvailable) {
522             long start = System.currentTimeMillis();
523             try {
524                 onTestEnd(mTestData, testMetrics, test);
525                 mTestData.addToMetrics(testMetrics);
526             } catch (DeviceNotAvailableException e) {
527                 mDeviceNoAvailable = true;
528                 CLog.e(e);
529             } catch (Throwable t) {
530                 // Prevent exception from messing up the status reporting.
531                 CLog.e(t);
532             } finally {
533                 InvocationMetricLogger.addInvocationMetrics(
534                         InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
535             }
536         } else {
537             CLog.d("Skipping %s collection for %s.", this.getClass().getName(), test.toString());
538         }
539         mForwarder.testEnded(test, endTime, testMetrics);
540     }
541 
542     @Override
testSkipped(TestDescription test, SkipReason reason)543     public final void testSkipped(TestDescription test, SkipReason reason) {
544         mForwarder.testSkipped(test, reason);
545     }
546 
547     @Override
testAssumptionFailure(TestDescription test, String trace)548     public final void testAssumptionFailure(TestDescription test, String trace) {
549         if (!mSkipTestCase && !mDeviceNoAvailable) {
550             long start = System.currentTimeMillis();
551             try {
552                 onTestAssumptionFailure(mTestData, test);
553             } catch (DeviceNotAvailableException e) {
554                 mDeviceNoAvailable = true;
555                 CLog.e(e);
556             } catch (Throwable t) {
557                 // Prevent exception from messing up the status reporting.
558                 CLog.e(t);
559             } finally {
560                 InvocationMetricLogger.addInvocationMetrics(
561                         InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
562             }
563         }
564         mForwarder.testAssumptionFailure(test, trace);
565     }
566 
567     @Override
testAssumptionFailure(TestDescription test, FailureDescription failure)568     public final void testAssumptionFailure(TestDescription test, FailureDescription failure) {
569         if (!mSkipTestCase && !mDeviceNoAvailable) {
570             long start = System.currentTimeMillis();
571             try {
572                 onTestAssumptionFailure(mTestData, test);
573             } catch (DeviceNotAvailableException e) {
574                 mDeviceNoAvailable = true;
575                 CLog.e(e);
576             } catch (Throwable t) {
577                 // Prevent exception from messing up the status reporting.
578                 CLog.e(t);
579             } finally {
580                 InvocationMetricLogger.addInvocationMetrics(
581                         InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start);
582             }
583         }
584         mForwarder.testAssumptionFailure(test, failure);
585     }
586 
587     @Override
testIgnored(TestDescription test)588     public final void testIgnored(TestDescription test) {
589         mForwarder.testIgnored(test);
590     }
591 
592     /**
593      * Do not use inside metric collector implementation. This is pure forwarding.
594      */
595     @Override
setLogSaver(ILogSaver logSaver)596     public final void setLogSaver(ILogSaver logSaver) {
597         if (mForwarder instanceof ILogSaverListener) {
598             ((ILogSaverListener) mForwarder).setLogSaver(logSaver);
599         }
600     }
601 
602     /**
603      * Do not use inside metric collector implementation. This is pure forwarding.
604      */
605     @Override
logAssociation(String dataName, LogFile logFile)606     public final void logAssociation(String dataName, LogFile logFile) {
607         if (mForwarder instanceof ILogSaverListener) {
608             ((ILogSaverListener) mForwarder).logAssociation(dataName, logFile);
609         }
610     }
611 
612     /**
613      * Do not use inside metric collector implementation. This is pure forwarding.
614      */
615     @Override
testLogSaved(String dataName, LogDataType dataType, InputStreamSource dataStream, LogFile logFile)616     public final void testLogSaved(String dataName, LogDataType dataType,
617             InputStreamSource dataStream, LogFile logFile) {
618         if (mForwarder instanceof ILogSaverListener) {
619             ((ILogSaverListener) mForwarder).testLogSaved(dataName, dataType, dataStream, logFile);
620         }
621     }
622 
623     /** {@inheritDoc} */
624     @Override
isDisabled()625     public final boolean isDisabled() {
626         return mDisable;
627     }
628 
629     /** {@inheritDoc} */
630     @Override
setDisable(boolean isDisabled)631     public final void setDisable(boolean isDisabled) {
632         mDisable = isDisabled;
633     }
634 
635     /**
636      * Returns the name of test run {@code mRunName} that triggers the collector.
637      *
638      * @return mRunName, the current test run name.
639      */
getRunName()640     public String getRunName() {
641         return mRunName;
642     }
643 
getModuleName()644     public String getModuleName() {
645         return mContext.getAttributes().get(ModuleDefinition.MODULE_NAME) != null
646                 ? mContext.getAttributes().get(ModuleDefinition.MODULE_NAME).get(0)
647                 : null;
648     }
649 
650     /**
651      * Helper to decide if a test case should or not run the collector method associated.
652      *
653      * @param desc the identifier of the test case.
654      * @return True the collector should be skipped. False otherwise.
655      */
shouldSkip(TestDescription desc)656     private boolean shouldSkip(TestDescription desc) {
657         Set<String> testCaseGroups = new HashSet<>();
658         if (desc.getAnnotation(MetricOption.class) != null) {
659             String groupName = desc.getAnnotation(MetricOption.class).group();
660             testCaseGroups.addAll(Arrays.asList(groupName.split(",")));
661         } else {
662             // Add empty group name for default case.
663             testCaseGroups.add("");
664         }
665         // Exclusion has priority: if any of the groups is excluded, exclude the test case.
666         for (String groupName : testCaseGroups) {
667             if (mTestCaseExcludeAnnotationGroup.contains(groupName)) {
668                 return true;
669             }
670         }
671         // Inclusion filter: if any of the group is included, include the test case.
672         for (String includeGroupName : mTestCaseIncludeAnnotationGroup) {
673             if (testCaseGroups.contains(includeGroupName)) {
674                 return false;
675             }
676         }
677 
678         // If we had filters and did not match any groups
679         if (!mTestCaseIncludeAnnotationGroup.isEmpty()) {
680             return true;
681         }
682         return false;
683     }
684 
685     /**
686      * Resolves the relative path of the file from the test artifacts
687      * directory or module directory.
688      *
689      * @param fileName file name that needs to be resolved.
690      * @return File file resolved for the given file name. Returns null
691      *         if file not found.
692      */
resolveRelativeFilePath(String fileName)693     private File resolveRelativeFilePath(String fileName) {
694         File src = null;
695         try {
696             src = SearchArtifactUtil.searchFile(fileName, true);
697         } catch (Exception e) {
698             // TODO: handle error when migration is complete.
699             CLog.e(e);
700         }
701         if (src != null && src.exists()) {
702             CLog.d("Found '%s' using SearchArtifactUtil", fileName);
703             return src;
704         } else {
705             CLog.d("Did not find '%s' using SearchArtifactUtil, fall back to old logic", fileName);
706             // Silently report not found and fall back to old logic.
707             InvocationMetricLogger.addInvocationMetrics(
708                     InvocationMetricKey.SEARCH_ARTIFACT_FAILURE_COUNT, 1);
709         }
710 
711         IBuildInfo buildInfo = getBuildInfos().get(0);
712         String mModuleName = null;
713         // Retrieve the module name.
714         if (mContext.getAttributes().get(ModuleDefinition.MODULE_NAME) != null) {
715             mModuleName = mContext.getAttributes().get(ModuleDefinition.MODULE_NAME)
716                     .get(0);
717         }
718 
719         if (buildInfo != null) {
720             src = buildInfo.getFile(fileName);
721             if (src != null && src.exists()) {
722                 return src;
723             }
724         }
725 
726         if (buildInfo instanceof IDeviceBuildInfo) {
727             IDeviceBuildInfo deviceBuild = (IDeviceBuildInfo) buildInfo;
728             File testDir = deviceBuild.getTestsDir();
729             List<File> scanDirs = new ArrayList<>();
730             // If it exists, always look first in the ANDROID_TARGET_OUT_TESTCASES
731             File targetTestCases = deviceBuild.getFile(BuildInfoFileKey.TARGET_LINKED_DIR);
732             if (targetTestCases != null) {
733                 scanDirs.add(targetTestCases);
734             }
735             // If not, look into the test directory.
736             if (testDir != null) {
737                 scanDirs.add(testDir);
738             }
739 
740             if (mModuleName != null) {
741                 // Use module name as a discriminant to find some files
742                 if (testDir != null) {
743                     try {
744                         File moduleDir = FileUtil.findDirectory(
745                                 mModuleName, scanDirs.toArray(new File[] {}));
746                         if (moduleDir != null) {
747                             // If the spec is pushing the module itself
748                             if (mModuleName.equals(fileName)) {
749                                 // If that's the main binary generated by the target, we push the
750                                 // full directory
751                                 return moduleDir;
752                             }
753                             // Search the module directory if it exists use it in priority
754                             src = FileUtil.findFile(fileName, null, moduleDir);
755                             if (src != null) {
756                                 CLog.i("Retrieving src file from" + src.getAbsolutePath());
757                                 return src;
758                             }
759                         } else {
760                             CLog.d("Did not find any module directory for '%s'", mModuleName);
761                         }
762 
763                     } catch (IOException e) {
764                         CLog.w(
765                                 "Something went wrong while searching for the module '%s' "
766                                         + "directory.",
767                                 mModuleName);
768                     }
769                 }
770             }
771 
772             for (File searchDir : scanDirs) {
773                 try {
774                     Set<File> allMatch = FileUtil.findFilesObject(searchDir, fileName);
775                     if (allMatch.size() > 1) {
776                         CLog.d(
777                                 "Several match for filename '%s', searching for top-level match.",
778                                 fileName);
779                         for (File f : allMatch) {
780                             if (f.getParent().equals(searchDir.getAbsolutePath())) {
781                                 return f;
782                             }
783                         }
784                     } else if (allMatch.size() == 1) {
785                         return allMatch.iterator().next();
786                     }
787                 } catch (IOException e) {
788                     CLog.w("Failed to find test files from directory.");
789                 }
790             }
791         }
792 
793         if (src == null) {
794             // if old logic fails too, do not report search artifact failure
795             InvocationMetricLogger.addInvocationMetrics(
796                     InvocationMetricKey.SEARCH_ARTIFACT_FAILURE_COUNT, -1);
797         }
798 
799         return src;
800     }
801 
802     @Override
rebootStarted(ITestDevice device)803     public void rebootStarted(ITestDevice device) throws DeviceNotAvailableException {
804         // Does nothing
805     }
806 
807     @Override
rebootEnded(ITestDevice device)808     public void rebootEnded(ITestDevice device) throws DeviceNotAvailableException {
809         // Does nothing
810     }
811 
812     @Override
setDisableReceiver(boolean isDisabled)813     public void setDisableReceiver(boolean isDisabled) {
814         mDisableReceiver = isDisabled;
815     }
816 
817     @Override
isDisabledReceiver()818     public boolean isDisabledReceiver() {
819         return mDisableReceiver;
820     }
821 }
822