Bundle all download of dependencies into internal and public

Bug: b/270105162
Change-Id: I09e719ceea47aaa10fdd363c6709a79ba099d969
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index d4ccc60..a2410ae 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -6,6 +6,7 @@
 import java.io.File
 import java.net.URI
 import java.nio.file.Paths
+import kotlin.reflect.full.declaredMemberProperties
 import org.gradle.api.JavaVersion
 import org.gradle.api.Plugin
 import org.gradle.api.Project
@@ -633,48 +634,23 @@
       DependencyType.X20)}
 }
 
-val testRuntimeDependencies = (listOf(
-  ThirdPartyDeps.aapt2,
-  ThirdPartyDeps.artTests,
-  ThirdPartyDeps.artTestsLegacy,
-  ThirdPartyDeps.compilerApi,
-  ThirdPartyDeps.coreLambdaStubs,
-  ThirdPartyDeps.customConversion,
-  ThirdPartyDeps.dagger,
-  ThirdPartyDeps.desugarJdkLibs,
-  ThirdPartyDeps.desugarJdkLibsLegacy,
-  ThirdPartyDeps.desugarJdkLibs11,
-  ThirdPartyDeps.examplesAndroidOLegacy,
-  ThirdPartyDeps.gson,
-  ThirdPartyDeps.guavaJre,
-  ThirdPartyDeps.jacoco,
-  ThirdPartyDeps.java8Runtime,
-  ThirdPartyDeps.jdk11Test,
-  ThirdPartyDeps.jsr223,
-  ThirdPartyDeps.multidex,
-  ThirdPartyDeps.r8,
-  ThirdPartyDeps.r8Mappings,
-  ThirdPartyDeps.r8v2_0_74,
-  ThirdPartyDeps.r8v3_2_54,
-  ThirdPartyDeps.retraceBenchmark,
-  ThirdPartyDeps.retraceBinaryCompatibility,
-  ThirdPartyDeps.rhino,
-  ThirdPartyDeps.rhinoAndroid,
-  ThirdPartyDeps.smali,
-  ThirdPartyDeps.tivi)
-    + ThirdPartyDeps.androidJars
-    + ThirdPartyDeps.androidVMs
-    + ThirdPartyDeps.desugarLibraryReleases
-    + ThirdPartyDeps.jdks
-    + ThirdPartyDeps.kotlinCompilers
-    + ThirdPartyDeps.proguards)
+private fun Project.allDependencies() : List<ThirdPartyDependency> {
+  val allDeps = mutableListOf<ThirdPartyDependency>()
+  ThirdPartyDeps::class.declaredMemberProperties.forEach {
+    val value = it.get(ThirdPartyDeps)
+    if (value is List<*>) {
+      allDeps.addAll(value as List<ThirdPartyDependency>)
+    } else {
+      allDeps.add(value as ThirdPartyDependency)
+    }
+  }
+  return allDeps
+}
 
-val testRuntimeInternalDependencies = (listOf(
-  ThirdPartyDeps.clank,
-  ThirdPartyDeps.framework,
-  ThirdPartyDeps.nest,
-  ThirdPartyDeps.proto,
-  ThirdPartyDeps.protobufLite,
-  ThirdPartyDeps.retraceInternal)
-  + ThirdPartyDeps.internalIssues
-  + ThirdPartyDeps.gmscoreVersions)
\ No newline at end of file
+fun Project.allPublicDependencies() : List<ThirdPartyDependency> {
+  return allDependencies().filter { x -> x.type == DependencyType.GOOGLE_STORAGE }
+}
+
+fun Project.allInternalDependencies() : List<ThirdPartyDependency> {
+  return allDependencies().filter { x -> x.type == DependencyType.X20 }
+}
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DownloadAllDependenciesTask.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DownloadAllDependenciesTask.kt
new file mode 100644
index 0000000..62328e6
--- /dev/null
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DownloadAllDependenciesTask.kt
@@ -0,0 +1,162 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import java.io.BufferedReader
+import java.io.File
+import java.io.IOException
+import java.io.InputStreamReader
+import java.nio.charset.StandardCharsets
+import java.util.Arrays
+import java.util.stream.Collectors
+import javax.inject.Inject
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.FileCollection
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.OutputDirectories
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.options.Option
+import org.gradle.internal.os.OperatingSystem
+import org.gradle.workers.WorkAction
+import org.gradle.workers.WorkParameters
+import org.gradle.workers.WorkerExecutor
+
+abstract class DownloadAllDependenciesTask : DefaultTask() {
+
+  private var _root: File? = null
+  private var _thirdPartyDeps: List<ThirdPartyDependency>? = null;
+
+  @InputFiles
+  fun getInputFile(): FileCollection {
+    val sha1Files = _thirdPartyDeps!!.map { _root!!.resolve(it.sha1File) }
+    return project.files(*sha1Files.toTypedArray())
+  }
+
+  @OutputDirectories
+  fun getOutputDir(): FileCollection {
+    val outputDirs = _thirdPartyDeps!!.map { _root!!.resolve(it.path) }
+    return project.files(*outputDirs.toTypedArray())
+  }
+
+  @Inject
+  protected abstract fun getWorkerExecutor(): WorkerExecutor?
+
+  fun setDependencies(root: File, thirdPartyDeps: List<ThirdPartyDependency>) {
+    this._root = root
+    this._thirdPartyDeps = thirdPartyDeps;
+  }
+
+  @TaskAction
+  fun execute() {
+    val noIsolation = getWorkerExecutor()!!.noIsolation()
+    _thirdPartyDeps?.forEach {
+      val root = _root!!
+      val sha1File = root.resolve(it.sha1File)
+      val tarGzFile = sha1File.resolveSibling(sha1File.name.replace(".sha1", ""))
+      val outputDir = root.resolve(it.path)
+      if (!sha1File.exists()) {
+        throw RuntimeException("Missing sha1 file: $sha1File")
+      }
+      if (shouldExecute(outputDir, tarGzFile, sha1File)) {
+        println("Downloading ${it}")
+        noIsolation.submit(RunDownload::class.java) {
+          type.set(it.type)
+          this.sha1File.set(sha1File)
+          this.outputDir.set(outputDir)
+          this.tarGzFile.set(tarGzFile)
+          this.root.set(root)
+        }
+      }
+    }
+  }
+
+  interface RunDownloadParameters : WorkParameters {
+    val type : Property<DependencyType>
+    val sha1File : RegularFileProperty
+    val outputDir : RegularFileProperty
+    val tarGzFile : RegularFileProperty
+    val root : RegularFileProperty
+  }
+
+  abstract class RunDownload : WorkAction<RunDownloadParameters> {
+    override fun execute() {
+      val sha1File = parameters.sha1File.asFile.get()
+      val outputDir = parameters.outputDir.asFile.get()
+      val tarGzFile = parameters.tarGzFile.asFile.get()
+      if (!shouldExecute(outputDir, tarGzFile, sha1File)) {
+        return;
+      }
+      if (outputDir.exists() && outputDir.isDirectory) {
+        outputDir.delete()
+      }
+      when (parameters.type.get()) {
+        DependencyType.GOOGLE_STORAGE -> {
+          downloadFromGoogleStorage(parameters, sha1File)
+        }
+        DependencyType.X20 -> {
+          downloadFromX20(parameters, sha1File)
+        }
+      }
+    }
+
+    @Throws(IOException::class, InterruptedException::class)
+    private fun downloadFromGoogleStorage(parameters: RunDownload2Parameters, sha1File: File) {
+      val args = Arrays.asList("-n", "-b", "r8-deps", "-s", "-u", sha1File.toString())
+      if (OperatingSystem.current().isWindows) {
+        val command: MutableList<String> = ArrayList()
+        command.add("download_from_google_storage.bat")
+        command.addAll(args)
+        runProcess(parameters, ProcessBuilder().command(command))
+      } else {
+        runProcess(
+          parameters,
+          ProcessBuilder()
+            .command("bash",
+                     "-c",
+                     "download_from_google_storage " + java.lang.String.join(" ", args)))
+      }
+    }
+
+    @Throws(IOException::class, InterruptedException::class)
+    private fun downloadFromX20(parameters: RunDownload2Parameters, sha1File: File) {
+      if (OperatingSystem.current().isWindows) {
+        throw RuntimeException("Downloading from x20 unsupported on windows")
+      }
+      runProcess(parameters,
+        ProcessBuilder()
+          .command("bash", "-c", "tools/download_from_x20.py $sha1File"))
+    }
+
+    @Throws(IOException::class, InterruptedException::class)
+    private fun runProcess(parameters: RunDownload2Parameters, builder: ProcessBuilder) {
+      builder.directory(parameters.root.asFile.get())
+      val command = java.lang.String.join(" ", builder.command())
+      val p = builder.start()
+      val exit = p.waitFor()
+      if (exit != 0) {
+        throw IOException("Process failed for $command\n"
+            + BufferedReader(
+            InputStreamReader(p.errorStream, StandardCharsets.UTF_8))
+            .lines()
+            .collect(Collectors.joining("\n")))
+      }
+    }
+  }
+
+  companion object {
+    fun shouldExecute(outputDir: File, tarGzFile: File, sha1File: File) : Boolean {
+      // First run will write the tar.gz file, causing the second run to still be out-of-date.
+      // Check if the modification time of the tar is newer than the sha in which case we are done.
+      if (outputDir.exists()
+        && outputDir.isDirectory
+        && outputDir.list()!!.isNotEmpty()
+        && tarGzFile.exists()
+        && sha1File.lastModified() <= tarGzFile.lastModified()) {
+        return false
+      }
+      return true
+    }
+  }
+}
\ No newline at end of file
diff --git a/d8_r8/keepanno/build.gradle.kts b/d8_r8/keepanno/build.gradle.kts
index d04408d..b7a2acf 100644
--- a/d8_r8/keepanno/build.gradle.kts
+++ b/d8_r8/keepanno/build.gradle.kts
@@ -19,13 +19,3 @@
   compileOnly(Deps.asm)
   compileOnly(Deps.guava)
 }
-
-val thirdPartyCompileDependenciesTask = ensureThirdPartyDependencies(
-  "compileDeps",
-  listOf(Jdk.JDK_11.getThirdPartyDependency()))
-
-tasks {
-  withType<JavaCompile> {
-    dependsOn(thirdPartyCompileDependenciesTask)
-  }
-}
\ No newline at end of file
diff --git a/d8_r8/library_desugar/build.gradle.kts b/d8_r8/library_desugar/build.gradle.kts
index d7f32c6..2bba9c5 100644
--- a/d8_r8/library_desugar/build.gradle.kts
+++ b/d8_r8/library_desugar/build.gradle.kts
@@ -18,13 +18,3 @@
 
 dependencies {
 }
-
-val thirdPartyCompileDependenciesTask = ensureThirdPartyDependencies(
-  "compileDeps",
-  listOf(Jdk.JDK_11.getThirdPartyDependency()))
-
-tasks {
-  withType<JavaCompile> {
-    dependsOn(thirdPartyCompileDependenciesTask)
-  }
-}
diff --git a/d8_r8/main/build.gradle.kts b/d8_r8/main/build.gradle.kts
index c34d924..5b3e38c 100644
--- a/d8_r8/main/build.gradle.kts
+++ b/d8_r8/main/build.gradle.kts
@@ -34,14 +34,6 @@
   errorprone(Deps.errorprone)
 }
 
-val thirdPartyCompileDependenciesTask = ensureThirdPartyDependencies(
-  "compileDeps",
-  listOf(Jdk.JDK_11.getThirdPartyDependency()))
-
-val thirdPartyResourceDependenciesTask = ensureThirdPartyDependencies(
-  "resourceDeps",
-  listOf(ThirdPartyDeps.apiDatabase))
-
 val keepAnnoJarTask = projectTask("keepanno", "jar")
 val resourceShrinkerJarTask = projectTask("resourceshrinker", "jar")
 val resourceShrinkerDepsTask = projectTask("resourceshrinker", "depsJar")
@@ -65,10 +57,11 @@
   }
 
   withType<ProcessResources> {
-    dependsOn(thirdPartyResourceDependenciesTask)
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
   }
 
   val consolidatedLicense by registering {
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
     val root = getRoot()
     val r8License = root.resolve("LICENSE")
     val libraryLicense = root.resolve("LIBRARY-LICENSE")
@@ -125,6 +118,7 @@
   val swissArmyKnife by registering(Jar::class) {
     dependsOn(keepAnnoJarTask)
     dependsOn(resourceShrinkerJarTask)
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
     from(sourceSets.main.get().output)
     from(keepAnnoJarTask.outputs.files.map(::zipTree))
     from(resourceShrinkerJarTask.outputs.files.map(::zipTree))
@@ -138,6 +132,7 @@
   }
 
   val depsJar by registering(Jar::class) {
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
     dependsOn(resourceShrinkerDepsTask)
     from(mainJarDependencies().map(::zipTree))
     from(resourceShrinkerDepsTask.outputs.files.map(::zipTree))
@@ -223,7 +218,7 @@
 }
 
 tasks.withType<JavaCompile> {
-  dependsOn(thirdPartyCompileDependenciesTask)
+  dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
   println("NOTE: Running with JDK: " + org.gradle.internal.jvm.Jvm.current().javaHome)
 
   // Enable error prone for D8/R8 main sources.
diff --git a/d8_r8/main/settings.gradle.kts b/d8_r8/main/settings.gradle.kts
index 34ab9ed..4e1d975 100644
--- a/d8_r8/main/settings.gradle.kts
+++ b/d8_r8/main/settings.gradle.kts
@@ -27,5 +27,6 @@
 rootProject.name = "r8"
 
 val root = rootProject.projectDir.parentFile
+includeBuild(root.resolve("shared"))
 includeBuild(root.resolve("keepanno"))
 includeBuild(root.resolve("resourceshrinker"))
diff --git a/d8_r8/resourceshrinker/build.gradle.kts b/d8_r8/resourceshrinker/build.gradle.kts
index 60a037b..62e44f6 100644
--- a/d8_r8/resourceshrinker/build.gradle.kts
+++ b/d8_r8/resourceshrinker/build.gradle.kts
@@ -29,14 +29,10 @@
     })
 }
 
-val thirdPartyCompileDependenciesTask = ensureThirdPartyDependencies(
-  "compileDeps",
-  listOf(ThirdPartyDeps.r8))
-
 dependencies {
   compileOnly(Deps.asm)
   compileOnly(Deps.guava)
-  compileOnly(files(getRoot().resolve(ThirdPartyDeps.r8.path).resolve("r8lib_8.2.20-dev.jar")))
+  compileOnly(files(resolve(ThirdPartyDeps.r8, "r8lib_8.2.20-dev.jar")))
   implementation("com.android.tools.build:aapt2-proto:8.2.0-alpha10-10154469")
   implementation("com.google.protobuf:protobuf-java:3.19.3")
   implementation("com.android.tools.layoutlib:layoutlib-api:31.2.0-alpha10")
@@ -46,7 +42,7 @@
 
 tasks {
   withType<KotlinCompile> {
-    dependsOn(thirdPartyCompileDependenciesTask)
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
     kotlinOptions {
       // We cannot use languageVersion.set(JavaLanguageVersion.of(8)) because gradle cannot figure
       // out that the jdk is 1_8 and will try to download it.
diff --git a/d8_r8/resourceshrinker/settings.gradle.kts b/d8_r8/resourceshrinker/settings.gradle.kts
index 604d9cb..d879107 100644
--- a/d8_r8/resourceshrinker/settings.gradle.kts
+++ b/d8_r8/resourceshrinker/settings.gradle.kts
@@ -25,3 +25,6 @@
 }
 
 rootProject.name = "resourceshrinker"
+
+val root = rootProject.projectDir.parentFile
+includeBuild(root.resolve("shared"))
diff --git a/d8_r8/settings.gradle.kts b/d8_r8/settings.gradle.kts
index c3c86b7..000a280 100644
--- a/d8_r8/settings.gradle.kts
+++ b/d8_r8/settings.gradle.kts
@@ -78,8 +78,7 @@
   }
 }
 
-// This project is temporarily located in d8_r8. When moved to root, the parent
-// folder should just be removed.
+includeBuild(root.resolve("shared"))
 includeBuild(root.resolve("keepanno"))
 includeBuild(root.resolve("resourceshrinker"))
 
diff --git a/d8_r8/shared/build.gradle.kts b/d8_r8/shared/build.gradle.kts
new file mode 100644
index 0000000..fa66c14
--- /dev/null
+++ b/d8_r8/shared/build.gradle.kts
@@ -0,0 +1,19 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+plugins {
+  `kotlin-dsl`
+  id("dependencies-plugin")
+}
+
+tasks {
+
+  val downloadDeps by registering(DownloadAllDependenciesTask::class) {
+    this.setDependencies(getRoot(), allPublicDependencies())
+  }
+
+  val downloadDepsInternal by registering(DownloadAllDependenciesTask::class) {
+    this.setDependencies(getRoot(), allInternalDependencies())
+  }
+}
\ No newline at end of file
diff --git a/d8_r8/shared/gradle.properties b/d8_r8/shared/gradle.properties
new file mode 100644
index 0000000..a82d85e
--- /dev/null
+++ b/d8_r8/shared/gradle.properties
@@ -0,0 +1,18 @@
+# Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
+kotlin.daemon.jvmargs=-Xmx3g -Dkotlin.js.compiler.legacy.force_enabled=true
+systemProp.file.encoding=UTF-8
+
+# Enable new incremental compilation
+kotlin.incremental.useClasspathSnapshot=true
+
+org.gradle.parallel=true
+org.gradle.caching=false
+org.gradle.configuration-cache=true
+
+# Do not download any jdks or detect them. We provide them.
+org.gradle.java.installations.auto-detect=false
+org.gradle.java.installations.auto-download=false
diff --git a/d8_r8/shared/settings.gradle.kts b/d8_r8/shared/settings.gradle.kts
new file mode 100644
index 0000000..0de348f
--- /dev/null
+++ b/d8_r8/shared/settings.gradle.kts
@@ -0,0 +1,27 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+pluginManagement {
+  repositories {
+    maven {
+      url = uri("file:../../third_party/dependencies")
+    }
+    maven {
+      url = uri("file:../../third_party/dependencies_new")
+    }
+  }
+}
+
+dependencyResolutionManagement {
+  repositories {
+    maven {
+      url = uri("file:../../third_party/dependencies")
+    }
+    maven {
+      url = uri("file:../../third_party/dependencies_new")
+    }
+  }
+}
+
+rootProject.name = "shared"
diff --git a/d8_r8/test/build.gradle.kts b/d8_r8/test/build.gradle.kts
index 2e5d20f..1b19265 100644
--- a/d8_r8/test/build.gradle.kts
+++ b/d8_r8/test/build.gradle.kts
@@ -28,14 +28,6 @@
 val java8TestsDepsJarTask = projectTask("tests_java_8", "depsJar")
 val bootstrapTestsDepsJarTask = projectTask("tests_bootstrap", "depsJar")
 
-val thirdPartyRuntimeDependenciesTask = ensureThirdPartyDependencies(
-  "runtimeDeps",
-  testRuntimeDependencies)
-
-val thirdPartyRuntimeInternalDependenciesTask = ensureThirdPartyDependencies(
-  "runtimeInternalDeps",
-  testRuntimeInternalDependencies)
-
 tasks {
   withType<Exec> {
     doFirst {
@@ -193,7 +185,7 @@
     dependsOn(allTestsJarRelocated)
     dependsOn(r8WithRelocatedDepsTask)
     dependsOn(allTestWithApplyMappingProguardConfiguration)
-    dependsOn(thirdPartyRuntimeDependenciesTask)
+    // dependsOn(thirdPartyRuntimeDependenciesTask)
     val r8 = r8WithRelocatedDepsTask.outputs.files.singleFile
     val allTests = allTestsJarRelocated.get().outputs.files.singleFile
     val pgConf = allTestWithApplyMappingProguardConfiguration.get().outputs.files.singleFile
@@ -243,9 +235,9 @@
     dependsOn(r8LibWithRelocatedDeps)
     dependsOn(unzipTests)
     dependsOn(unzipRewrittenTests)
-    dependsOn(thirdPartyRuntimeDependenciesTask)
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
     if (!project.hasProperty("no_internal")) {
-      dependsOn(thirdPartyRuntimeInternalDependenciesTask)
+      dependsOn(gradle.includedBuild("shared").task(":downloadDepsInternal"))
     }
     val r8LibJar = r8LibWithRelocatedDeps.get().outputs.files.singleFile
     this.configure(isR8Lib = true, r8Jar = r8LibJar)
diff --git a/d8_r8/test/settings.gradle.kts b/d8_r8/test/settings.gradle.kts
index 5df668c..38419b5 100644
--- a/d8_r8/test/settings.gradle.kts
+++ b/d8_r8/test/settings.gradle.kts
@@ -27,6 +27,7 @@
 rootProject.name = "r8-tests"
 
 val root = rootProject.projectDir.parentFile
+includeBuild(root.resolve("shared"))
 includeBuild(root.resolve("keepanno"))
 includeBuild(root.resolve("main"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_8"))
diff --git a/d8_r8/test_modules/tests_bootstrap/build.gradle.kts b/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
index 3acace1..bf64d96 100644
--- a/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
+++ b/d8_r8/test_modules/tests_bootstrap/build.gradle.kts
@@ -81,6 +81,10 @@
   }
 
   val depsJar by registering(Jar::class) {
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
+    if (!project.hasProperty("no_internal")) {
+      dependsOn(gradle.includedBuild("shared").task(":downloadDepsInternal"))
+    }
     from(testDependencies().map(::zipTree))
     duplicatesStrategy = DuplicatesStrategy.EXCLUDE
     archiveFileName.set("deps.jar")
diff --git a/d8_r8/test_modules/tests_bootstrap/settings.gradle.kts b/d8_r8/test_modules/tests_bootstrap/settings.gradle.kts
index fba8852..cb05e4f 100644
--- a/d8_r8/test_modules/tests_bootstrap/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_bootstrap/settings.gradle.kts
@@ -27,8 +27,9 @@
 rootProject.name = "tests_bootstrap"
 
 val root = rootProject.projectDir.parentFile.parentFile
-//
+
 // We need to include src/main as a composite-build otherwise our test-modules
 // will compete with the test to compile the source files.
+includeBuild(root.resolve("shared"))
 includeBuild(root.resolve("main"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_8"))
diff --git a/d8_r8/test_modules/tests_java_8/build.gradle.kts b/d8_r8/test_modules/tests_java_8/build.gradle.kts
index 434a635..d0ef602 100644
--- a/d8_r8/test_modules/tests_java_8/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/build.gradle.kts
@@ -58,22 +58,6 @@
   implementation(Deps.smaliUtil)
 }
 
-val thirdPartyCompileDependenciesTask = ensureThirdPartyDependencies(
-  "compileDeps",
-  listOf(
-    ThirdPartyDeps.apiDatabase,
-    ThirdPartyDeps.ddmLib,
-    ThirdPartyDeps.jasmin,
-    ThirdPartyDeps.jdwpTests))
-
-val thirdPartyRuntimeDependenciesTask = ensureThirdPartyDependencies(
-  "runtimeDeps",
-  testRuntimeDependencies)
-
-val thirdPartyRuntimeInternalDependenciesTask = ensureThirdPartyDependencies(
-  "runtimeInternalDeps",
-  testRuntimeInternalDependencies)
-
 val sourceSetDependenciesTasks = arrayOf(
   projectTask("tests_java_examples", getExampleJarsTaskName("examples")),
   projectTask("tests_java_9", getExampleJarsTaskName("examplesJava9")),
@@ -101,14 +85,14 @@
 
 tasks {
   "compileTestJava" {
-    dependsOn(thirdPartyCompileDependenciesTask)
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
   }
   withType<JavaCompile> {
     dependsOn(gradle.includedBuild("keepanno").task(":jar"))
     dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
     dependsOn(gradle.includedBuild("main").task(":compileJava"))
     dependsOn(gradle.includedBuild("main").task(":processResources"))
-    dependsOn(thirdPartyCompileDependenciesTask)
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
   }
 
   withType<KotlinCompile> {
@@ -118,9 +102,9 @@
   withType<Test> {
     TestingState.setUpTestingState(this)
     dependsOn(mainDepsJarTask)
-    dependsOn(thirdPartyRuntimeDependenciesTask)
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
     if (!project.hasProperty("no_internal")) {
-      dependsOn(thirdPartyRuntimeInternalDependenciesTask)
+      dependsOn(gradle.includedBuild("shared").task(":downloadDepsInternal"))
     }
     dependsOn(*sourceSetDependenciesTasks)
     systemProperty("TEST_DATA_LOCATION",
@@ -150,9 +134,9 @@
   }
 
   val depsJar by registering(Jar::class) {
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
     dependsOn(gradle.includedBuild("keepanno").task(":jar"))
     dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
-    dependsOn(thirdPartyCompileDependenciesTask)
     from(testDependencies().map(::zipTree))
     duplicatesStrategy = DuplicatesStrategy.EXCLUDE
     archiveFileName.set("deps.jar")
diff --git a/d8_r8/test_modules/tests_java_8/settings.gradle.kts b/d8_r8/test_modules/tests_java_8/settings.gradle.kts
index 627a65a..f5ac288 100644
--- a/d8_r8/test_modules/tests_java_8/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/settings.gradle.kts
@@ -27,13 +27,13 @@
 rootProject.name = "tests_java_8"
 
 val root = rootProject.projectDir.parentFile.parentFile
+includeBuild(root.resolve("shared"))
 includeBuild(root.resolve("keepanno"))
 includeBuild(root.resolve("resourceshrinker"))
 
 // We need to include src/main as a composite-build otherwise our test-modules
 // will compete with the test to compile the source files.
 includeBuild(root.resolve("main"))
-
 includeBuild(root.resolve("test_modules").resolve("tests_java_9"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_10"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_11"))