Add Android 15 support and test

* Android SDK files for android-VanillaIceCream SDK revision 3
* Update API database base on android-VanillaIceCream SDK revision 3
* Add fresh build of host Art 15 from branch 24Q3-release

Bug: b/343127842

Change-Id: I74d4f9fe5455243d560bf904d4ddfc4a0f32b5b3
diff --git a/.gitignore b/.gitignore
index bb6648e..6b66c27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -328,6 +328,8 @@
 tools/*/host/art-13.0.0.tar.gz
 tools/*/host/art-14.0.0-beta3
 tools/*/host/art-14.0.0-beta3.tar.gz
+tools/*/host/art-15.0.0-beta2
+tools/*/host/art-15.0.0-beta2.tar.gz
 tools/*/host/art-master
 tools/*/host/art-master.tar.gz
 tools/*/art.tar.gz
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index bdbd79e..68a50f3 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -704,7 +704,8 @@
     "lib-v31",
     "lib-v32",
     "lib-v33",
-    "lib-v34"
+    "lib-v34",
+    "lib-v35"
   ).map(::getThirdPartyAndroidJar)
 }
 
@@ -718,6 +719,7 @@
 fun getThirdPartyAndroidVms() : List<ThirdPartyDependency> {
   return listOf(
     listOf("host", "art-master"),
+    listOf("host", "art-15.0.0-beta2"),
     listOf("host", "art-14.0.0-beta3"),
     listOf("host", "art-13.0.0"),
     listOf("host", "art-12.0.0-beta4"),
diff --git a/scripts/add-android-jar.sh b/scripts/add-android-jar.sh
index e6ba2c2..e2fe239 100755
--- a/scripts/add-android-jar.sh
+++ b/scripts/add-android-jar.sh
@@ -16,8 +16,8 @@
 SDK_HOME=$HOME/Android/Sdk
 
 # Modify these to match the SDK android.jar to add.
-SDK_DIR_NAME=android-UpsideDownCake
-SDK_VERSION=34
+SDK_DIR_NAME=android-VanillaIceCream
+SDK_VERSION=35
 
 SDK_DIR=$SDK_HOME/platforms/$SDK_DIR_NAME
 THIRD_PARTY_ANDROID_JAR=third_party/android_jar
diff --git a/scripts/update-host-art.sh b/scripts/update-host-art.sh
index ef7670b..a84c946 100755
--- a/scripts/update-host-art.sh
+++ b/scripts/update-host-art.sh
@@ -180,6 +180,7 @@
 if [ -f $DEST/product/$ANDROID_PRODUCT/system/framework/boot.vdex ]; then
   for VDEXFILE in $DEST/product/$ANDROID_PRODUCT/system/framework/*.vdex; do
     VDEXNAME=$(basename ${VDEXFILE});
+    # Maybe remove arm here.
     for ARCH in arm arm64; do
       rm $DEST/product/$ANDROID_PRODUCT/system/framework/$ARCH/${VDEXNAME};
       # This relative link command will create a symbolic link of the form
diff --git a/src/main/java/com/android/tools/r8/androidapi/CovariantReturnTypeMethods.java b/src/main/java/com/android/tools/r8/androidapi/CovariantReturnTypeMethods.java
index 077c1be..ddbe9c5 100644
--- a/src/main/java/com/android/tools/r8/androidapi/CovariantReturnTypeMethods.java
+++ b/src/main/java/com/android/tools/r8/androidapi/CovariantReturnTypeMethods.java
@@ -91,6 +91,11 @@
             "rewind"));
     consumer.accept(
         factory.createMethod(
+            factory.createType("Ljava/nio/DirectByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "compact"));
+    consumer.accept(
+        factory.createMethod(
             factory.createType("Ljava/nio/DoubleBuffer;"),
             factory.createProto(factory.createType("Ljava/nio/DoubleBuffer;")),
             "clear"));
@@ -239,6 +244,105 @@
             "rewind"));
     consumer.accept(
         factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/ByteBuffer;")),
+            "clear"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "clear"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "compact"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "duplicate"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "duplicate"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/ByteBuffer;")),
+            "flip"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "flip"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(
+                factory.createType("Ljava/nio/ByteBuffer;"), factory.createType("I")),
+            "limit"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(
+                factory.createType("Ljava/nio/MappedByteBuffer;"), factory.createType("I")),
+            "limit"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/ByteBuffer;")),
+            "mark"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "mark"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(
+                factory.createType("Ljava/nio/ByteBuffer;"), factory.createType("I")),
+            "position"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(
+                factory.createType("Ljava/nio/MappedByteBuffer;"), factory.createType("I")),
+            "position"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/ByteBuffer;")),
+            "reset"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "reset"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/ByteBuffer;")),
+            "rewind"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "rewind"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "slice"));
+    consumer.accept(
+        factory.createMethod(
+            factory.createType("Ljava/nio/MappedByteBuffer;"),
+            factory.createProto(factory.createType("Ljava/nio/MappedByteBuffer;")),
+            "slice"));
+    consumer.accept(
+        factory.createMethod(
             factory.createType("Ljava/nio/ShortBuffer;"),
             factory.createProto(factory.createType("Ljava/nio/ShortBuffer;")),
             "clear"));
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 05c0b45..411c87e 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -44,13 +44,14 @@
   Sv2(32),
   T(33),
   U(34),
-  MAIN(35); // API level for main is tentative.
+  V(35),
+  MAIN(36); // API level for main is tentative.
 
   // When updating LATEST and a new version goes public, add a new api-versions.xml to third_party
   // and update the version and generated jar in AndroidApiDatabaseBuilderGeneratorTest. Together
   // with that update third_party/android_jar/libcore_latest/core-oj.jar and run
   // GenerateCovariantReturnTypeMethodsTest.
-  public static final AndroidApiLevel LATEST = U;
+  public static final AndroidApiLevel LATEST = V;
 
   public static final AndroidApiLevel API_DATABASE_LEVEL = LATEST;
 
@@ -114,7 +115,7 @@
 
   public static AndroidApiLevel getAndroidApiLevel(int apiLevel) {
     assert apiLevel > 0;
-    assert U == LATEST; // This has to be updated when we add new api levels.
+    assert V == LATEST; // This has to be updated when we add new api levels.
     assert UNKNOWN.isGreaterThan(LATEST);
     switch (apiLevel) {
       case 1:
@@ -185,6 +186,8 @@
         return T;
       case 34:
         return U;
+      case 35:
+        return V;
       default:
         return MAIN;
     }
diff --git a/src/main/java/com/android/tools/r8/utils/DexVersion.java b/src/main/java/com/android/tools/r8/utils/DexVersion.java
index dc62cf4..f3e1670 100644
--- a/src/main/java/com/android/tools/r8/utils/DexVersion.java
+++ b/src/main/java/com/android/tools/r8/utils/DexVersion.java
@@ -68,6 +68,7 @@
     switch (androidApiLevel) {
         // MAIN is an unknown higher api version we therefore choose the highest known version.
       case MAIN:
+      case V:
       case U:
       case T:
       case Sv2:
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 228536e..17e87f0 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -168,7 +168,19 @@
                   StringUtils.lines(
                       "java.lang.NullPointerException: Attempt to read from field 'byte[]"
                           + " Test.a' on a null object reference in method 'int"
-                          + " TestObject.a(Test, Test)'")));
+                          + " TestObject.a(Test, Test)'")),
+          Version.V15_0_0,
+          ImmutableMap.of(
+              "bad-codegen",
+              StringUtils.lines(
+                  "java.lang.NullPointerException: Attempt to read from field 'Test Test.a'"
+                      + " on a null object reference in method 'Test TestObject.a(Test,"
+                      + " Test, Test, Test, boolean)'"),
+              "type-confusion-regression3",
+              StringUtils.lines(
+                  "java.lang.NullPointerException: Attempt to read from field 'byte[]"
+                      + " Test.a' on a null object reference in method 'int"
+                      + " TestObject.a(Test, Test)'")));
 
   // Tests where the input fails with a verification error on Dalvik instead of the
   // expected runtime exception.
diff --git a/src/test/java/com/android/tools/r8/androidapi/GenerateCovariantReturnTypeMethodsTest.java b/src/test/java/com/android/tools/r8/androidapi/GenerateCovariantReturnTypeMethodsTest.java
index 5826a9a..7c062bd 100644
--- a/src/test/java/com/android/tools/r8/androidapi/GenerateCovariantReturnTypeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/androidapi/GenerateCovariantReturnTypeMethodsTest.java
@@ -22,7 +22,11 @@
 import com.android.tools.r8.cfmethodgeneration.MethodGenerationBase;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationElement;
+import com.android.tools.r8.graph.DexEncodedAnnotation;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
+import com.android.tools.r8.graph.DexValue.DexValueArray;
 import com.android.tools.r8.graph.DexValue.DexValueType;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.MethodReference;
@@ -68,7 +72,7 @@
       Paths.get(ToolHelper.MAIN_SOURCE_DIR)
           .resolve(PACKAGE_NAME.replace('.', '/'))
           .resolve(CLASS_NAME + ".java");
-  private static final AndroidApiLevel GENERATED_FOR_API_LEVEL = AndroidApiLevel.U;
+  private static final AndroidApiLevel GENERATED_FOR_API_LEVEL = AndroidApiLevel.V;
 
   @Parameter public TestParameters parameters;
 
@@ -207,15 +211,9 @@
                           isCovariantReturnTypeAnnotation(annotation.annotation, factory));
               if (!covariantAnnotations.isEmpty()) {
                 MethodReference methodReference = method.asMethodReference();
-                ClassReference holder = clazz.getOriginalReference();
                 for (DexAnnotation covariantAnnotation : covariantAnnotations) {
-                  if (covariantAnnotation.annotation.type
-                      == factory.annotationCovariantReturnType) {
-                    createCovariantMethodReference(
-                        methodReference, covariantAnnotation, methodReferenceMap);
-                  } else {
-                    fail("There are no such annotations present in libcore");
-                  }
+                  createCovariantMethodReference(
+                      factory, methodReference, covariantAnnotation.annotation, methodReferenceMap);
                 }
               }
             });
@@ -224,25 +222,51 @@
     }
 
     private static void createCovariantMethodReference(
+        DexItemFactory factory,
         MethodReference methodReference,
-        DexAnnotation covariantAnnotation,
+        DexEncodedAnnotation covariantAnnotation,
         Map<ClassReference, List<MethodReferenceWithApiLevel>> methodReferenceMap) {
-      DexValueType newReturnType =
-          covariantAnnotation.annotation.getElement(0).getValue().asDexValueType();
-      DexAnnotationElement element = covariantAnnotation.annotation.getElement(1);
-      assert element.name.toString().equals("presentAfter");
-      AndroidApiLevel apiLevel =
-          AndroidApiLevel.getAndroidApiLevel(element.getValue().asDexValueInt().value);
-      methodReferenceMap
-          .computeIfAbsent(methodReference.getHolderClass(), ignoreKey(ArrayList::new))
-          .add(
-              new MethodReferenceWithApiLevel(
-                  Reference.method(
-                      methodReference.getHolderClass(),
-                      methodReference.getMethodName(),
-                      methodReference.getFormalTypes(),
-                      newReturnType.value.asClassReference()),
-                  apiLevel));
+      if (covariantAnnotation.type == factory.annotationCovariantReturnType) {
+        DexAnnotationElement returnTypeElement = covariantAnnotation.getElement(0);
+        assert returnTypeElement.name.toString().equals("returnType");
+        DexValueType newReturnType = returnTypeElement.getValue().asDexValueType();
+        DexAnnotationElement presentAfterElement = covariantAnnotation.getElement(1);
+        assert presentAfterElement.name.toString().equals("presentAfter");
+        AndroidApiLevel apiLevel =
+            AndroidApiLevel.getAndroidApiLevel(
+                presentAfterElement.getValue().asDexValueInt().value);
+        methodReferenceMap
+            .computeIfAbsent(methodReference.getHolderClass(), ignoreKey(ArrayList::new))
+            .add(
+                new MethodReferenceWithApiLevel(
+                    Reference.method(
+                        methodReference.getHolderClass(),
+                        methodReference.getMethodName(),
+                        methodReference.getFormalTypes(),
+                        newReturnType.value.asClassReference()),
+                    apiLevel));
+      } else {
+        assert covariantAnnotation.type == factory.annotationCovariantReturnTypes;
+        DexAnnotationElement valuesElement = covariantAnnotation.getElement(0);
+        assert valuesElement.name.toString().equals("value");
+        DexValueArray array = valuesElement.value.asDexValueArray();
+        if (array == null) {
+          fail(
+              String.format(
+                  "Expected element \"value\" of CovariantReturnTypes annotation to "
+                      + "be an array (method: \"%s\", was: %s)",
+                  methodReference.toSourceString(),
+                  valuesElement.value.getClass().getCanonicalName()));
+        }
+
+        // Handle the inner dalvik.annotation.codegen.CovariantReturnType annotations recursively.
+        for (DexValue value : array.getValues()) {
+          assert value.isDexValueAnnotation();
+          DexValueAnnotation innerAnnotation = value.asDexValueAnnotation();
+          createCovariantMethodReference(
+              factory, methodReference, innerAnnotation.value, methodReferenceMap);
+        }
+      }
     }
 
     public void visitCovariantMethodsForHolder(
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
index 8605db0..ef3db54 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiHashingDatabaseBuilderGeneratorTest.java
@@ -110,9 +110,9 @@
                   methodReferences.forEach(field -> numberOfMethods.increment())));
         });
     // These numbers will change when updating api-versions.xml
-    assertEquals(5716, parsedApiClasses.size());
-    assertEquals(29609, numberOfFields.get());
-    assertEquals(44827, numberOfMethods.get());
+    assertEquals(5904, parsedApiClasses.size());
+    assertEquals(30073, numberOfFields.get());
+    assertEquals(46091, numberOfMethods.get());
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java b/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
index 019a579..7617ca1 100644
--- a/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
+++ b/src/test/java/com/android/tools/r8/apimodel/AndroidApiVersionsXmlParser.java
@@ -56,6 +56,10 @@
       removedTypeNames.add("com.android.internal.util.Predicate");
       removedTypeNames.add("android.adservices.AdServicesVersion");
     }
+    if (maxApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.V)) {
+      removedTypeNames.add("android.media.MediaDrm$HdcpLevel");
+      removedTypeNames.add("android.media.MediaDrm$SecurityLevel");
+    }
     return removedTypeNames;
   }
 
@@ -74,8 +78,9 @@
       if (!clazz.isPresent()) {
         if (!clazz.getOriginalTypeName().startsWith("android.test")
             && !clazz.getOriginalTypeName().startsWith("junit")) {
-          assert exemptionList.contains(type) || hasRemoved(node);
-          assert exemptionList.contains(type) || getRemoved(node).isLessThanOrEqualTo(maxApiLevel);
+          assert exemptionList.contains(type) || hasRemoved(node) : type;
+          assert exemptionList.contains(type) || getRemoved(node).isLessThanOrEqualTo(maxApiLevel)
+              : type;
           if (!hasRemoved(node)) {
             exemptionList.remove(type);
           }
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/invokespecial/InvokeSpecialMethodHandleTest.java b/src/test/java/com/android/tools/r8/cf/methodhandles/invokespecial/InvokeSpecialMethodHandleTest.java
index fbbadb0..a3fba21 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/invokespecial/InvokeSpecialMethodHandleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/invokespecial/InvokeSpecialMethodHandleTest.java
@@ -130,7 +130,7 @@
       } else if (parameters.isDexRuntime()
           && parameters.asDexRuntime().getVersion().isNewerThan(Version.V9_0_0)) {
         // VMs between 9 and 13 segfault.
-        if (parameters.asDexRuntime().getVersion().isEqualTo(Version.V14_0_0)) {
+        if (parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V14_0_0)) {
           result.assertFailureWithOutputThatMatches(
               containsString("reverting to SIG_DFL handler for signal 11"));
         } else {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/LocalVariableTableForParameterWithSignatureTest.java b/src/test/java/com/android/tools/r8/debuginfo/LocalVariableTableForParameterWithSignatureTest.java
index ecbe2e4..bf59b3b 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/LocalVariableTableForParameterWithSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/LocalVariableTableForParameterWithSignatureTest.java
@@ -119,13 +119,14 @@
               assertTrue(hasParamValue);
               assertTrue(hasParamStringsWithSignature);
               if (parameters.isCfRuntime()
-                  || parameters.isDexRuntimeVersionOlderThanOrEqual(Version.V6_0_1)) {
-                // CF runtimes and the old DEX runtimes report the correct local variable table.
+                  || parameters.isDexRuntimeVersionOlderThanOrEqual(Version.V6_0_1)
+                  || parameters.isDexRuntimeVersionNewerThanOrEqual(Version.V15_0_0)) {
+                // CF runtimes and some DEX runtimes report the correct local variable table.
                 // The variable table should be just the two parameters.
                 assertEquals(2, variableTable.size());
                 assertFalse(hasEmptyRange);
               } else {
-                // Newer ART runtimes report a variable with an empty range. That variable is the
+                // Some ART runtimes report a variable with an empty range. That variable is the
                 // parameter without a signature, e.g., List, and is ended immediately as a variable
                 // is started that also includes the signature, e.g., List<String>.
                 assertEquals(variableTable.toString(), 3, variableTable.size());
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeInterfaceTest.java
index 9c36e69..762d1df 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeInterfaceTest.java
@@ -77,7 +77,7 @@
   public void testD8() throws Exception {
     parameters.assumeDexRuntime();
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForD8()
         .addProgramClassFileData(
             dumpHost(),
@@ -112,7 +112,7 @@
   public void testD8WithClasspathAndMerge() throws Exception {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     Path host =
         testForD8()
@@ -200,7 +200,7 @@
   public void testD8WithoutMembersOnClasspath() {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     assertThrows(
         CompilationFailedException.class,
@@ -221,7 +221,7 @@
   public void testD8WithoutHostOnClasspath() {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     assertThrows(
         CompilationFailedException.class,
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSpecialTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSpecialTest.java
index b50b2f9..220f6c0 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSpecialTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSpecialTest.java
@@ -170,9 +170,9 @@
   @Test
   public void testD8DexWithNestSupport() throws Exception {
     parameters.assumeDexRuntime();
-    assumeTrue(parameters.getApiLevel().getLevel() >= 34);
+    assumeTrue(parameters.getApiLevel().getLevel() >= 35);
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForD8()
         .addProgramFiles(JDK17_JAR)
         .setMinApi(AndroidApiLevel.U)
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSuperTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSuperTest.java
index 36290f2..279b975 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeSuperTest.java
@@ -69,7 +69,7 @@
   public void testD8() throws Exception {
     parameters.assumeDexRuntime();
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForD8()
         .addProgramClassFileData(dumpHost(), dumpMember(), dumpSubMember())
         .setMinApi(parameters)
@@ -102,7 +102,7 @@
   public void testD8WithClasspathAndMerge() throws Exception {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     Path host =
         testForD8()
@@ -189,7 +189,7 @@
   public void testD8WithoutMembersOnClasspath() {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     assertThrows(
         CompilationFailedException.class,
@@ -210,7 +210,7 @@
   public void testD8WithoutHostOnClasspath() {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     assertThrows(
         CompilationFailedException.class,
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeVirtualTest.java
index 9e2d0c0..8de9a22 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexRewriteInvokeVirtualTest.java
@@ -69,7 +69,7 @@
   public void testD8() throws Exception {
     parameters.assumeDexRuntime();
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForD8()
         .addProgramClassFileData(dumpHost(), dumpMember1(), dumpMember2())
         .setMinApi(parameters)
@@ -102,7 +102,7 @@
   public void testD8WithClasspathAndMerge() throws Exception {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     Path host =
         testForD8()
@@ -189,7 +189,7 @@
   public void testD8WithoutMembersOnClasspath() {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     assertThrows(
         CompilationFailedException.class,
@@ -210,7 +210,7 @@
   public void testD8WithoutHostOnClasspath() {
     assumeTrue(parameters.isDexRuntime());
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
 
     assertThrows(
         CompilationFailedException.class,
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
index 4a1e82c..790498d 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
@@ -81,7 +81,7 @@
     parameters.assumeR8TestParameters();
     assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForR8(parameters.getBackend())
         .addProgramClassFileData(
             dumpHost(ACC_PRIVATE), dumpMember1(ACC_PRIVATE), dumpMember2(ACC_PRIVATE))
@@ -99,7 +99,7 @@
     parameters.assumeR8TestParameters();
     assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForR8(parameters.getBackend())
         .addProgramClassFileData(
             dumpHost(ACC_PRIVATE), dumpMember1(ACC_PRIVATE), dumpMember2(ACC_PRIVATE))
@@ -121,7 +121,7 @@
     parameters.assumeR8TestParameters();
     assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForR8(parameters.getBackend())
         .addProgramClassFileData(
             dumpHost(ACC_PUBLIC), dumpMember1(ACC_PUBLIC), dumpMember2(ACC_PUBLIC))
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingMethodsTest.java
index eca6260..677e553 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingMethodsTest.java
@@ -80,7 +80,7 @@
     parameters.assumeR8TestParameters();
     assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForR8(parameters.getBackend())
         .addProgramClassFileData(
             dumpHost(ACC_PRIVATE), dumpMember1(ACC_PRIVATE), dumpMember2(ACC_PRIVATE))
@@ -98,7 +98,7 @@
     parameters.assumeR8TestParameters();
     assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForR8(parameters.getBackend())
         .addProgramClassFileData(
             dumpHost(ACC_PRIVATE), dumpMember1(ACC_PRIVATE), dumpMember2(ACC_PRIVATE))
@@ -120,7 +120,7 @@
     parameters.assumeR8TestParameters();
     assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
     // TODO(b/247047415): Update test when a DEX VM natively supporting nests is added.
-    assertFalse(parameters.getApiLevel().getLevel() > 34);
+    assertFalse(parameters.getApiLevel().getLevel() > 35);
     testForR8(parameters.getBackend())
         .addProgramClassFileData(
             dumpHost(ACC_PUBLIC), dumpMember1(ACC_PUBLIC), dumpMember2(ACC_PUBLIC))
diff --git a/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java
index fb097c0..a02faab 100644
--- a/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java
+++ b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java
@@ -70,9 +70,8 @@
   @Test
   public void testDebug() throws Exception {
     Assume.assumeFalse(
-        "VMs 13 and 14 step-out to the continuation (line 28) and not the call-site (line 25).",
-        parameters.isDexRuntimeVersion(Version.V13_0_0)
-            || parameters.isDexRuntimeVersion(Version.V14_0_0));
+        "VMs from 13 step-out to the continuation (line 28) and not the call-site (line 25).",
+        parameters.isDexRuntimeVersionNewerThanOrEqual(Version.V13_0_0));
     runTestDebugComparator();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java b/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java
index fda115e..4c09231 100644
--- a/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java
+++ b/src/test/java/com/android/tools/r8/graph/InvokeSuperTest.java
@@ -132,6 +132,8 @@
       result.assertFailureWithErrorThatThrows(VerifyError.class);
     } else if (version == Version.V5_1_1 || version == Version.V6_0_1) {
       result.assertFailure();
+    } else if (version == Version.V15_0_0) {
+      result.assertFailureWithErrorThatThrows(VerifyError.class);
     } else {
       result.assertSuccessWithOutputThatMatches(containsString(NoSuchMethodError.class.getName()));
     }
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index 3d3ed7f..9289f8e 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -88,6 +88,7 @@
               case V7_0_0:
               case V13_0_0:
               case V14_0_0:
+              case V15_0_0:
                 return StringUtils.joinLines(
                     "Hello!",
                     "Unexpected outcome of checkcast",
diff --git a/src/test/java/com/android/tools/r8/workaround/FilledNewArrayFromSubtypeWithMissingInterfaceWorkaroundTest.java b/src/test/java/com/android/tools/r8/workaround/FilledNewArrayFromSubtypeWithMissingInterfaceWorkaroundTest.java
index 53794e3..b8d0e8b 100644
--- a/src/test/java/com/android/tools/r8/workaround/FilledNewArrayFromSubtypeWithMissingInterfaceWorkaroundTest.java
+++ b/src/test/java/com/android/tools/r8/workaround/FilledNewArrayFromSubtypeWithMissingInterfaceWorkaroundTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -62,7 +63,10 @@
         .setMinApi(parameters)
         .compile()
         .applyIf(
-            parameters.isDexRuntime(),
+            // Only run dex2oat where the host build actually supports it to not get false negatives
+            // for fixes to b/283715197 and b/269228249.
+            parameters.isDexRuntime()
+                && ToolHelper.isDex2OatSupportedForVM(parameters.getRuntime().asDex().getVm()),
             compileResult ->
                 compileResult
                     .inspect(this::inspect)
diff --git a/src/test/testbase/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/testbase/java/com/android/tools/r8/R8RunArtTestsTest.java
index 0dbe829..3cfbd85 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -104,7 +104,26 @@
           DexVm.Version.V10_0_0,
           DexVm.Version.V12_0_0,
           DexVm.Version.V13_0_0,
-          DexVm.Version.V14_0_0);
+          DexVm.Version.V14_0_0,
+          DexVm.Version.V15_0_0);
+
+  private static final TestCondition beforeAndroidN =
+      TestCondition.match(
+          TestCondition.runtimes(
+              DexVm.Version.V4_0_4,
+              DexVm.Version.V4_4_4,
+              DexVm.Version.V5_1_1,
+              DexVm.Version.V6_0_1));
+  // O is 8.0.0, but we don't have that for testing, only O_MR1 which is 8.1.0.
+  private static final TestCondition beforeAndroidO =
+      TestCondition.match(TestCondition.runtimesUpTo(DexVm.Version.V7_0_0));
+  // TODO(b/343124019): Change to V8_0_0 once we have a new art VM.
+  private static final TestCondition beforeAndroidP =
+      TestCondition.match(TestCondition.runtimesUpTo(DexVm.Version.V7_0_0));
+  private static final TestCondition fromAndroidS =
+      TestCondition.match(TestCondition.runtimesFrom(DexVm.Version.V12_0_0));
+  private static final TestCondition fromAndroidV =
+      TestCondition.match(TestCondition.runtimesFrom(DexVm.Version.V15_0_0));
 
   // Test that required to set min-api to a specific value.
   private static Map<String, AndroidApiLevel> needMinSdkVersion =
@@ -172,18 +191,10 @@
               TestCondition.match(TestCondition.runtimesUpTo(DexVm.Version.V4_4_4)))
           // TODO(b/197078746): Triage - fails with "java.lang.NoSuchMethodException:
           //  org.apache.harmony.dalvik.ddmc.DdmVmInternal.enableRecentAllocations [boolean]"
-          .put(
-              "098-ddmc",
-              TestCondition.match(
-                  TestCondition.runtimes(
-                      DexVm.Version.V12_0_0, DexVm.Version.V13_0_0, DexVm.Version.V14_0_0)))
+          .put("098-ddmc", fromAndroidS)
           // TODO(b/197079442): Triage - fails with "java.lang.NoSuchMethodException:
           //  org.apache.harmony.dalvik.ddmc.DdmVmInternal.enableRecentAllocations [boolean]"
-          .put(
-              "145-alloc-tracking-stress",
-              TestCondition.match(
-                  TestCondition.runtimes(
-                      DexVm.Version.V12_0_0, DexVm.Version.V13_0_0, DexVm.Version.V14_0_0)))
+          .put("145-alloc-tracking-stress", fromAndroidS)
           .build();
 
   // Tests that are flaky with the Art version we currently use.
@@ -490,6 +501,7 @@
   static {
     ImmutableMap.Builder<DexVm.Version, List<String>> builder = ImmutableMap.builder();
     builder
+        .put(DexVm.Version.V15_0_0, ImmutableList.of("543-env-long-ref", "518-null-array-get"))
         .put(DexVm.Version.V14_0_0, ImmutableList.of("543-env-long-ref", "518-null-array-get"))
         .put(DexVm.Version.V13_0_0, ImmutableList.of("543-env-long-ref", "518-null-array-get"))
         .put(DexVm.Version.V12_0_0, ImmutableList.of("543-env-long-ref", "518-null-array-get"))
@@ -799,18 +811,6 @@
               TestCondition.anyDexVm())
           .build();
 
-  private static final TestCondition beforeAndroidN =
-      TestCondition
-          .match(TestCondition
-              .runtimes(DexVm.Version.V4_0_4, DexVm.Version.V4_4_4, DexVm.Version.V5_1_1,
-                  DexVm.Version.V6_0_1));
-  // TODO(herhut): Change to V8_0_0 once we have a new art VM.
-  private static final TestCondition beforeAndroidO =
-      TestCondition.match(TestCondition.runtimesUpTo(DexVm.Version.V7_0_0));
-  // TODO(herhut): Change to V8_0_0 once we have a new art VM.
-  private static final TestCondition beforeAndroidP =
-      TestCondition.match(TestCondition.runtimesUpTo(DexVm.Version.V7_0_0));
-
   // TODO(ager): Could we test that these fail in the way that we expect?
   private static final Multimap<String, TestCondition> expectedToFailRunWithArt =
       new ImmutableListMultimap.Builder<String, TestCondition>()
@@ -845,7 +845,8 @@
                           DexVm.Version.V6_0_1,
                           DexVm.Version.V7_0_0,
                           DexVm.Version.V13_0_0,
-                          DexVm.Version.V14_0_0)),
+                          DexVm.Version.V14_0_0,
+                          DexVm.Version.V15_0_0)),
                   TestCondition.match(
                       compilers(
                           CompilerUnderTest.R8,
@@ -874,7 +875,8 @@
                       DexVm.Version.V10_0_0,
                       DexVm.Version.V12_0_0,
                       DexVm.Version.V13_0_0,
-                      DexVm.Version.V14_0_0)))
+                      DexVm.Version.V14_0_0,
+                      DexVm.Version.V15_0_0)))
           .put("454-get-vreg", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // Fails: regs_jni.cc:42] Check failed: GetVReg(m, 0, kIntVReg, &value)
           // The R8/D8 code does not put values in the same registers as the tests expects.
@@ -892,7 +894,8 @@
                       DexVm.Version.V10_0_0,
                       DexVm.Version.V12_0_0,
                       DexVm.Version.V13_0_0,
-                      DexVm.Version.V14_0_0)))
+                      DexVm.Version.V14_0_0,
+                      DexVm.Version.V15_0_0)))
           .put("457-regs", TestCondition.match(TestCondition.R8DEX_COMPILER))
           // Class not found.
           .put("529-checker-unresolved", TestCondition.any())
@@ -951,6 +954,10 @@
           .put("974-verify-interface-super", beforeAndroidN) // --min-sdk = 24
           .put("975-iface-private", beforeAndroidN) // --min-sdk = 24
           .put("979-const-method-handle", beforeAndroidP)
+          .put(
+              "021-string2",
+              fromAndroidV) // Test use com.android.org.bouncycastle.util.Strings.fromUTF8ByteArray
+          // - no longer present.
           // Missing class junit.framework.Assert (see JunitAvailabilityInHostArtTest).
           // TODO(120884788): Add this again.
           /*
diff --git a/src/test/testbase/java/com/android/tools/r8/TestCondition.java b/src/test/testbase/java/com/android/tools/r8/TestCondition.java
index aec73f4..a4eca96 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestCondition.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestCondition.java
@@ -27,13 +27,11 @@
     ART_V12_0_0,
     ART_V13_0_0,
     ART_V14_0_0,
+    ART_V15_0_0,
     ART_DEFAULT,
     ART_MASTER,
     JAVA;
 
-    static final Runtime LOWEST_ART_VERSION = ART_V4_0_4;
-    static final Runtime HIGHEST_ART_VERSION = ART_DEFAULT;
-
     static Runtime fromDexVmVersion(DexVm.Version version) {
       switch (version) {
         case V4_0_4:
@@ -58,6 +56,8 @@
           return ART_V13_0_0;
         case V14_0_0:
           return ART_V14_0_0;
+        case V15_0_0:
+          return ART_V15_0_0;
         case DEFAULT:
           return ART_DEFAULT;
         case MASTER:
@@ -189,6 +189,10 @@
     return RuntimeSet.fromDexVmVersionSet(EnumSet.range(DexVm.Version.first(), upto));
   }
 
+  public static RuntimeSet runtimesFrom(DexVm.Version from) {
+    return RuntimeSet.fromDexVmVersionSet(EnumSet.range(from, DexVm.Version.last()));
+  }
+
   public static RuntimeSet and(RuntimeSet... sets) {
     return new RuntimeSet(
         EnumSet.copyOf(
diff --git a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
index 745b3dd..3cb3bde 100644
--- a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
@@ -352,6 +352,8 @@
     ART_13_0_0_HOST(Version.V13_0_0, Kind.HOST),
     ART_14_0_0_TARGET(Version.V14_0_0, Kind.TARGET),
     ART_14_0_0_HOST(Version.V14_0_0, Kind.HOST),
+    ART_15_0_0_TARGET(Version.V15_0_0, Kind.TARGET),
+    ART_15_0_0_HOST(Version.V15_0_0, Kind.HOST),
     ART_MASTER_TARGET(Version.MASTER, Kind.TARGET),
     ART_MASTER_HOST(Version.MASTER, Kind.HOST);
 
@@ -373,6 +375,7 @@
       V12_0_0("12.0.0"),
       V13_0_0("13.0.0"),
       V14_0_0("14.0.0"),
+      V15_0_0("15.0.0"),
       MASTER("master");
 
       /** This should generally be the latest DEX VM fully supported. */
@@ -440,7 +443,7 @@
       }
 
       public static Version last() {
-        return V14_0_0;
+        return V15_0_0;
       }
 
       public static Version master() {
@@ -959,6 +962,7 @@
       ImmutableMap.<DexVm, String>builder()
           .put(DexVm.ART_DEFAULT, "art")
           .put(DexVm.ART_MASTER_HOST, "host/art-master")
+          .put(DexVm.ART_15_0_0_HOST, "host/art-15.0.0-beta2")
           .put(DexVm.ART_14_0_0_HOST, "host/art-14.0.0-beta3")
           .put(DexVm.ART_13_0_0_HOST, "host/art-13.0.0")
           .put(DexVm.ART_12_0_0_HOST, "host/art-12.0.0-beta4")
@@ -975,6 +979,7 @@
       ImmutableMap.<DexVm, String>builder()
           .put(DexVm.ART_DEFAULT, "bin/art")
           .put(DexVm.ART_MASTER_HOST, "bin/art")
+          .put(DexVm.ART_15_0_0_HOST, "bin/art")
           .put(DexVm.ART_14_0_0_HOST, "bin/art")
           .put(DexVm.ART_13_0_0_HOST, "bin/art")
           .put(DexVm.ART_12_0_0_HOST, "bin/art")
@@ -991,6 +996,7 @@
   private static final Map<DexVm, String> ART_BINARY_VERSIONS_X64 =
       ImmutableMap.<DexVm, String>builder()
           .put(DexVm.ART_DEFAULT, "bin/art")
+          .put(DexVm.ART_15_0_0_HOST, "bin/art")
           .put(DexVm.ART_14_0_0_HOST, "bin/art")
           .put(DexVm.ART_13_0_0_HOST, "bin/art")
           .put(DexVm.ART_12_0_0_HOST, "bin/art")
@@ -1026,6 +1032,7 @@
     ImmutableMap.Builder<DexVm, List<String>> builder = ImmutableMap.builder();
     builder
         .put(DexVm.ART_DEFAULT, ART_7_TO_10_BOOT_LIBS)
+        .put(DexVm.ART_15_0_0_HOST, ART_12_PLUS_BOOT_LIBS)
         .put(DexVm.ART_14_0_0_HOST, ART_12_PLUS_BOOT_LIBS)
         .put(DexVm.ART_13_0_0_HOST, ART_12_PLUS_BOOT_LIBS)
         .put(DexVm.ART_12_0_0_HOST, ART_12_PLUS_BOOT_LIBS)
@@ -1046,6 +1053,7 @@
     ImmutableMap.Builder<DexVm, String> builder = ImmutableMap.builder();
     builder
         .put(DexVm.ART_DEFAULT, "angler")
+        .put(DexVm.ART_15_0_0_HOST, "akita")
         .put(DexVm.ART_14_0_0_HOST, "redfin")
         .put(DexVm.ART_13_0_0_HOST, "redfin")
         .put(DexVm.ART_12_0_0_HOST, "redfin")
@@ -1079,6 +1087,7 @@
         return base.resolve("host").resolve("art-12.0.0-beta4");
       case V13_0_0:
       case V14_0_0:
+      case V15_0_0:
       case MASTER:
         return base.resolve("host").resolve("art-" + version);
       default:
@@ -1114,6 +1123,7 @@
       case V12_0_0:
       case V13_0_0:
       case V14_0_0:
+      case V15_0_0:
       case MASTER:
         return "x86_64";
       default:
@@ -1399,6 +1409,8 @@
     switch (dexVm.version) {
       case MASTER:
         return AndroidApiLevel.MAIN;
+      case V15_0_0:
+        return AndroidApiLevel.V;
       case V14_0_0:
         return AndroidApiLevel.U;
       case V13_0_0:
@@ -1432,6 +1444,8 @@
     switch (apiLevel) {
       case MAIN:
         return DexVm.Version.MASTER;
+      case V:
+        return DexVm.Version.V15_0_0;
       case U:
         return DexVm.Version.V14_0_0;
       case T:
@@ -2397,6 +2411,10 @@
   private static final List<DexVm> SUPPORTED_DEX2OAT_VMS =
       ImmutableList.of(DexVm.ART_12_0_0_HOST, DexVm.ART_6_0_1_HOST);
 
+  public static boolean isDex2OatSupportedForVM(DexVm vm) {
+    return SUPPORTED_DEX2OAT_VMS.contains(vm);
+  }
+
   public static ProcessResult runDex2OatRaw(Path file, Path outFile, DexVm targetVm)
       throws IOException {
     Assume.assumeTrue(ToolHelper.isDex2OatSupported());
diff --git a/third_party/android_jar/lib-v35.tar.gz.sha1 b/third_party/android_jar/lib-v35.tar.gz.sha1
new file mode 100644
index 0000000..f1f5b61
--- /dev/null
+++ b/third_party/android_jar/lib-v35.tar.gz.sha1
@@ -0,0 +1 @@
+c9ad2358cc165f07fd68ef2151741ba12b26dcbc
\ No newline at end of file
diff --git a/third_party/android_jar/libcore_latest.tar.gz.sha1 b/third_party/android_jar/libcore_latest.tar.gz.sha1
index a4bef52..8200e76 100644
--- a/third_party/android_jar/libcore_latest.tar.gz.sha1
+++ b/third_party/android_jar/libcore_latest.tar.gz.sha1
@@ -1 +1 @@
-a82e05e08874d8b869d7f614c24ef8981888c702
\ No newline at end of file
+96a23da90f1b9412821cef769f3524ef6b05436b
\ No newline at end of file
diff --git a/third_party/api_database/api_database.tar.gz.sha1 b/third_party/api_database/api_database.tar.gz.sha1
index 7717064..a3e3b5e 100644
--- a/third_party/api_database/api_database.tar.gz.sha1
+++ b/third_party/api_database/api_database.tar.gz.sha1
@@ -1 +1 @@
-f1d87fa568ba769b5bf72b9f5a45a376c7465dda
\ No newline at end of file
+6fcae4d91999ef50dfbd2367c02270bc0ab9d2de
\ No newline at end of file
diff --git a/tools/linux/README.art-versions b/tools/linux/README.art-versions
index f813085..19d9248 100644
--- a/tools/linux/README.art-versions
+++ b/tools/linux/README.art-versions
@@ -67,6 +67,36 @@
 
 repo init -b udc-preview1-release
 
+
+art-15 (Android V)
+------------------
+Build branch 24Q3-release. Art at 5b498ae35e41f63dddb36d1c22c05165f4bb815d
+
+export BRANCH=24Q3-release
+mkdir ${BRANCH}
+cd ${BRANCH}
+export ANDROID_CHECKOUT=$(pwd)
+repo init -u https://android.googlesource.com/platform/manifest -b ${BRANCH}
+repo sync -cq -j48
+source build/envsetup.sh
+lunch aosp_akita-trunk_staging-userdebug
+m -j
+m -j build-art
+m -j test-art-host
+repo manifest -r -o build_spec.xml
+
+Collected into tools/linux/host/art-15.0.0-beta2. The "host" path element is checked
+by the script for running Art.
+
+  cd <r8 checkout>
+  scripts/update-host-art.sh \
+     --android-checkout $ANDROID_CHECKOUT \
+     --art-dir host/art-15.0.0-beta2 \
+     --android-product akita
+
+  (cd tools/linux/host; upload_to_google_storage.py -a --bucket r8-deps art-15.0.0-beta2)
+
+
 art-14 (Android U)
 ------------------
 Build branch udc-beta3-release. Art at 1f3514c28caf4537fe0fdf14559991ca23cf9e30.
diff --git a/tools/linux/host/art-15.0.0-beta2.tar.gz.sha1 b/tools/linux/host/art-15.0.0-beta2.tar.gz.sha1
new file mode 100644
index 0000000..f83cb4d
--- /dev/null
+++ b/tools/linux/host/art-15.0.0-beta2.tar.gz.sha1
@@ -0,0 +1 @@
+b793914b82da4e1b94ec14750788981063b8c57f
\ No newline at end of file
diff --git a/tools/test.py b/tools/test.py
index 2d358cb..9aee64a 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -28,8 +28,8 @@
     import thread
 
 ALL_ART_VMS = [
-    "default", "14.0.0", "13.0.0", "12.0.0", "10.0.0", "9.0.0", "8.1.0",
-    "7.0.0", "6.0.1", "5.1.1", "4.4.4", "4.0.4"
+    "default", "15.0.0", "14.0.0", "13.0.0", "12.0.0", "10.0.0", "9.0.0",
+    "8.1.0", "7.0.0", "6.0.1", "5.1.1", "4.4.4", "4.0.4"
 ]
 
 # How often do we check for progress on the bots: