[ApiModel] Disable stubbing of super classes on L and below

Bug: b/279780940
Change-Id: I1afd04dcb2134815162f073e186d25d2c61f6fca
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index c42f8c6..27a43b9 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.synthesis.CommittedItems;
 import com.android.tools.r8.synthesis.SyntheticItems;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.WorkList;
@@ -116,9 +117,13 @@
     // We cannot reliably create a stub that will have the same throwing behavior for all VMs.
     // Only create stubs for exceptions to allow them being present in catch handlers and super
     // types of existing program classes. See b/258270051 and b/259076765 for more information.
-    clazz
-        .allImmediateSupertypes()
-        .forEach(superType -> findReferencedLibraryClasses(superType, clazz));
+    // Also, for L devices we can have verification issues if there are super invokes to missing
+    // members on stubbed classes. See b/279780940 for more information.
+    if (appView.options().getMinApiLevel().isGreaterThan(AndroidApiLevel.L)) {
+      clazz
+          .allImmediateSupertypes()
+          .forEach(superType -> findReferencedLibraryClasses(superType, clazz));
+    }
     clazz.forEachProgramMethodMatching(
         DexEncodedMethod::hasCode,
         method -> {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
index 2332313..3e60454 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelD8GradleSetupTest.java
@@ -82,7 +82,8 @@
   }
 
   private boolean willStubLibraryClassThree() {
-    return parameters.getApiLevel().isLessThan(mockApiLevelThree);
+    return parameters.getApiLevel().isGreaterThan(AndroidApiLevel.L)
+        && parameters.getApiLevel().isLessThan(mockApiLevelThree);
   }
 
   public AndroidApiLevel getApiLevelForRuntime() {
@@ -222,7 +223,9 @@
     // classes. Depending on the api a number of synthetic classes.
     int numberOfClasses =
         4
-            + (willStubLibraryClassThree() ? 2 : 0)
+            + (willStubLibraryClassThree()
+                ? 2
+                : (BooleanUtils.intValue(parameters.getApiLevel().isLessThan(mockApiLevelThree))))
             + BooleanUtils.intValue(parameters.getApiLevel().isLessThan(mockApiLevelTwo))
             + BooleanUtils.intValue(parameters.getApiLevel().isLessThan(mockApiLevelOne));
     assertEquals(numberOfClasses, inspector.allClasses().size());
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
index c7a2674..f03be0a 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
@@ -97,7 +97,8 @@
   }
 
   private void inspect(CodeInspector inspector) {
-    verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel);
+    verifyThat(inspector, parameters, LibraryClass.class)
+        .stubbedBetween(AndroidApiLevel.L_MR1, mockLevel);
   }
 
   private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockRetraceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockRetraceTest.java
index 9394280..23945e1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockRetraceTest.java
@@ -60,10 +60,15 @@
   }
 
   private void inspect(CodeInspector inspector) {
-    verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel);
+    verifyThat(inspector, parameters, LibraryClass.class)
+        .stubbedBetween(AndroidApiLevel.L_MR1, mockLevel);
   }
 
   private void checkOutput(SingleTestRunResult<?> runResult) {
+    if (!addToBootClasspath()) {
+      runResult.assertFailureWithErrorThatThrows(NoClassDefFoundError.class);
+      return;
+    }
     StackTraceLine clinitFrame =
         StackTraceLine.builder()
             .setClassName(typeName(LibraryClass.class))
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
index 3d31170..4c4590a 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
@@ -121,9 +121,12 @@
   }
 
   private void inspect(CodeInspector inspector) {
-    verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(lowerMockApiLevel);
-    verifyThat(inspector, parameters, LibraryInterface.class).stubbedUntil(lowerMockApiLevel);
-    verifyThat(inspector, parameters, OtherLibraryClass.class).stubbedUntil(mockApiLevel);
+    verifyThat(inspector, parameters, LibraryClass.class)
+        .stubbedBetween(AndroidApiLevel.L_MR1, lowerMockApiLevel);
+    verifyThat(inspector, parameters, LibraryInterface.class)
+        .stubbedBetween(AndroidApiLevel.L_MR1, lowerMockApiLevel);
+    verifyThat(inspector, parameters, OtherLibraryClass.class)
+        .stubbedBetween(AndroidApiLevel.L_MR1, mockApiLevel);
   }
 
   private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
index cfa2e8a..c632b1a 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -277,6 +277,16 @@
                   || parameters.getApiLevel().isGreaterThanOrEqualTo(finalApiLevel)));
     }
 
+    public void stubbedBetween(AndroidApiLevel startingApilevel, AndroidApiLevel endingApiLevel) {
+      assertThat(
+          inspector.clazz(classOfInterest),
+          notIf(
+              isPresent(),
+              parameters.isCfRuntime()
+                  || parameters.getApiLevel().isLessThan(startingApilevel)
+                  || parameters.getApiLevel().isGreaterThanOrEqualTo(endingApiLevel)));
+    }
+
     void hasCheckCastOutlinedFromUntil(Method method, AndroidApiLevel apiLevel) {
       if (parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(apiLevel)) {
         hasCheckCastOutlinedFrom(method);