Merge cherrypicks of [9111407, 9111408, 9111409, 9111410, 9111411, 9111332, 9110454] into qt-release

Change-Id: I0b3d8f617f2fedf3c01fe9594aadc5e0ada809ce
diff --git a/src/com/android/tradefed/testtype/suite/retry/RetryRescheduler.java b/src/com/android/tradefed/testtype/suite/retry/RetryRescheduler.java
index 5358794..3206494 100644
--- a/src/com/android/tradefed/testtype/suite/retry/RetryRescheduler.java
+++ b/src/com/android/tradefed/testtype/suite/retry/RetryRescheduler.java
@@ -38,6 +38,7 @@
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.suite.BaseTestSuite;
 import com.android.tradefed.testtype.suite.SuiteTestFilter;
+import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.QuotationAwareTokenizer;
 import com.android.tradefed.util.TestRecordInterpreter;
 
@@ -222,10 +223,28 @@
         } else {
             types.add(mRetryType);
         }
+
+        // Expand the exclude-filter in case no abi is specified.
+        Set<String> extendedExcludeRetryFilters = new HashSet<>();
+        for (String excludeFilter : mExcludeFilters) {
+            SuiteTestFilter suiteFilter = SuiteTestFilter.createFrom(excludeFilter);
+            // Keep the current exclude-filter
+            extendedExcludeRetryFilters.add(excludeFilter);
+            if (suiteFilter.getAbi() == null) {
+                // If no abi is specified, exclude them all.
+                Set<String> abis = AbiUtils.getAbisSupportedByCompatibility();
+                for (String abi : abis) {
+                    SuiteTestFilter namingFilter =
+                            new SuiteTestFilter(abi, suiteFilter.getName(), suiteFilter.getTest());
+                    extendedExcludeRetryFilters.add(namingFilter.toString());
+                }
+            }
+        }
+
         // Prepare exclusion filters
         for (TestRunResult moduleResult : results.getMergedTestRunResults()) {
             // If the module is explicitly excluded from retries, preserve the original results.
-            if (!mExcludeFilters.contains(moduleResult.getName())
+            if (!extendedExcludeRetryFilters.contains(moduleResult.getName())
                     && RetryResultHelper.shouldRunModule(moduleResult, types)) {
                 if (types.contains(RetryType.NOT_EXECUTED)) {
                     // Clear the run failure since we are attempting to rerun all non-executed
diff --git a/tests/src/com/android/tradefed/testtype/suite/retry/RetryReschedulerTest.java b/tests/src/com/android/tradefed/testtype/suite/retry/RetryReschedulerTest.java
index 23d219c..380e75c 100644
--- a/tests/src/com/android/tradefed/testtype/suite/retry/RetryReschedulerTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/retry/RetryReschedulerTest.java
@@ -35,6 +35,8 @@
 import com.android.tradefed.result.TestDescription;
 import com.android.tradefed.result.proto.ProtoResultReporter;
 import com.android.tradefed.result.proto.TestRecordProto.TestRecord;
+import com.android.tradefed.testtype.Abi;
+import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.suite.BaseTestSuite;
 
 import org.easymock.EasyMock;
@@ -345,6 +347,50 @@
         verify(mSuite).setExcludeFilter(excludeRun1);
     }
 
+    /**
+     * Test that if an exclude-filter is provided without abi, we are still able to exclude all the
+     * matching modules for all abis.
+     */
+    @Test
+    public void testReschedule_excludeFilters_abi() throws Exception {
+        OptionSetter setter = new OptionSetter(mTest);
+        // We specify to exclude "run1"
+        setter.setOptionValue(BaseTestSuite.EXCLUDE_FILTER_OPTION, "run1");
+        populateFakeResults(2, 2, 1, 0, 0, false, new Abi("armeabi-v7a", "32"));
+        mMockLoader.init();
+        EasyMock.expect(mMockLoader.getCommandLine()).andReturn("previous_command");
+        EasyMock.expect(mMockFactory.createConfigurationFromArgs(EasyMock.anyObject()))
+                .andReturn(mRescheduledConfiguration);
+        EasyMock.expect(mMockLoader.loadPreviousRecord()).andReturn(mFakeRecord);
+
+        mRescheduledConfiguration.setTests(EasyMock.anyObject());
+        EasyMock.expectLastCall().times(1);
+
+        EasyMock.expect(mMockRescheduler.scheduleConfig(mRescheduledConfiguration)).andReturn(true);
+        EasyMock.replay(
+                mMockRescheduler,
+                mMockLoader,
+                mMockFactory,
+                mRescheduledConfiguration,
+                mMockCommandOptions);
+        mTest.run(null);
+        EasyMock.verify(
+                mMockRescheduler,
+                mMockLoader,
+                mMockFactory,
+                mRescheduledConfiguration,
+                mMockCommandOptions);
+
+        Set<String> excludeRun0 = new HashSet<>();
+        // Run with the abi are excluded
+        excludeRun0.add("armeabi-v7a run0 test.class#testPass0");
+        verify(mSuite).setExcludeFilter(excludeRun0);
+        Set<String> excludeRun1 = new HashSet<>();
+        // Even if run1 had failed test cases, it was excluded so it's not running.
+        excludeRun1.add("armeabi-v7a run1");
+        verify(mSuite).setExcludeFilter(excludeRun1);
+    }
+
     /** Test rescheduling a configuration when no parameterized tests previously failed. */
     @Test
     public void testReschedule_parameterized_nofail() throws Exception {
@@ -452,6 +498,18 @@
             int assumpFailure,
             int parameterized,
             boolean failedParam) {
+        populateFakeResults(
+                numModule, numTests, failedTests, assumpFailure, parameterized, failedParam, null);
+    }
+
+    private void populateFakeResults(
+            int numModule,
+            int numTests,
+            int failedTests,
+            int assumpFailure,
+            int parameterized,
+            boolean failedParam,
+            IAbi abi) {
         ProtoResultReporter reporter =
                 new ProtoResultReporter() {
                     @Override
@@ -464,7 +522,11 @@
         context.addDeviceBuildInfo(ConfigurationDef.DEFAULT_DEVICE_NAME, new BuildInfo());
         reporter.invocationStarted(context);
         for (int i = 0; i < numModule; i++) {
-            reporter.testRunStarted("run" + i, numTests);
+            String runName = "run" + i;
+            if (abi != null) {
+                runName = abi.getName() + " " + runName;
+            }
+            reporter.testRunStarted(runName, numTests);
             for (int j = 0; j < numTests - failedTests - assumpFailure - parameterized; j++) {
                 TestDescription test = new TestDescription("test.class", "testPass" + j);
                 reporter.testStarted(test);