[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 dd1d6c1..ba210ce 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.graph.ThrowExceptionCode;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.synthesis.CommittedItems;
+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;
@@ -108,9 +109,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/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
index 322b30f..0137c9e 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/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
index 5d4fc8f..d4eba25 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 6a487a9..f60fb87 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -263,6 +263,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);