Merge commit 'c25e07eaeb7b581173c16a8a47cdb4c357581f85' into dev-release
Change-Id: I7859e63678e602bebc4e36e1f7b814b63fdcbbe7
diff --git a/.gitignore b/.gitignore
index 062fe33..8eab4b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -91,8 +91,6 @@
third_party/ddmlib.tar.gz
third_party/dependencies/
third_party/dependencies.tar.gz
-third_party/dependencies_new/
-third_party/dependencies_new.tar.gz
third_party/dependencies_plugin/
third_party/dependencies_plugin.tar.gz
third_party/desugar/desugar_*.tar.gz
diff --git a/README.md b/README.md
index 0a085c1..a152891 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,9 @@
The prebuilt JARs have been processed by R8, and for each build the corresponding
mapping file is located together with the prebuild under the name `r8lib.jar.map`.
+To get prebuilds which has not been processed by R8 replace `r8lib.jar` with `r8.jar`
+in the URLs above.
+
The Google Cloud Storage bucket r8-releases can also be used as a simple
Maven repository using the following in a Gradle build file:
@@ -150,6 +153,40 @@
R8 is not command line compatible with ProGuard, for instance keep rules cannot be passed
on the command line, but have to be passed in a file using the `--pg-conf` option.
+## <a name="replacing-r8-in-agp"></a>Replacing R8 in Android Gradle plugin
+
+Android Gradle plugin (AGP) ships with R8 embedded (as part of the `builder.jar` from
+`com.android.tools.build:builder:<agp version>` on https://maven.google.com).
+
+To override the embedded version with a prebuilt R8 with version `<version>`, merge
+the following into the top level `settings.gradle` or `settings.gradle.kts`:
+```
+pluginManagement {
+ buildscript {
+ repositories {
+ mavenCentral()
+ maven {
+ url = uri("https://storage.googleapis.com/r8-releases/raw")
+ }
+ }
+ dependencies {
+ classpath("com.android.tools:r8:<version>")
+ }
+ }
+}
+```
+To override the embedded version with a downloaded or freshly built `<path>/r8.jar` merge
+the following into the top level `settings.gradle` or `settings.gradle.kts`:
+```
+pluginManagement {
+ buildscript {
+ dependencies {
+ classpath(files("<path>/r8.jar"))
+ }
+ }
+}
+```
+
## Testing
Typical steps to run tests:
diff --git a/d8_r8/commonBuildSrc/settings.gradle.kts b/d8_r8/commonBuildSrc/settings.gradle.kts
index f0a7aba..9180dc7 100644
--- a/d8_r8/commonBuildSrc/settings.gradle.kts
+++ b/d8_r8/commonBuildSrc/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../third_party/dependencies")
+ url = uri("file:../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../third_party/dependencies_new")
+ url = uri("file:../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../third_party/dependencies")
}
- maven {
- url = uri("file:../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index 794e58e..32e3732 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -308,14 +308,14 @@
}
object Versions {
- const val asmVersion = "9.5"
+ const val asmVersion = "9.6"
const val errorproneVersion = "2.18.0"
const val fastUtilVersion = "7.2.1"
const val gsonVersion = "2.10.1"
const val guavaVersion = "32.1.2-jre"
const val javassist = "3.29.2-GA"
const val junitVersion = "4.13-beta-2"
- const val kotlinVersion = "1.8.10"
+ const val kotlinVersion = "1.9.0"
const val kotlinMetadataVersion = "0.7.0"
const val mockito = "2.10.0"
const val smaliVersion = "3.0.3"
diff --git a/d8_r8/keepanno/settings.gradle.kts b/d8_r8/keepanno/settings.gradle.kts
index 8159946..4b9b240 100644
--- a/d8_r8/keepanno/settings.gradle.kts
+++ b/d8_r8/keepanno/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../third_party/dependencies")
+ url = uri("file:../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../third_party/dependencies_new")
+ url = uri("file:../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../third_party/dependencies")
}
- maven {
- url = uri("file:../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/library_desugar/settings.gradle.kts b/d8_r8/library_desugar/settings.gradle.kts
index 642d900..02ff676 100644
--- a/d8_r8/library_desugar/settings.gradle.kts
+++ b/d8_r8/library_desugar/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../third_party/dependencies")
+ url = uri("file:../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../third_party/dependencies_new")
+ url = uri("file:../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../third_party/dependencies")
}
- maven {
- url = uri("file:../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/main/build.gradle.kts b/d8_r8/main/build.gradle.kts
index 47b5da0..3aeb083 100644
--- a/d8_r8/main/build.gradle.kts
+++ b/d8_r8/main/build.gradle.kts
@@ -107,11 +107,7 @@
fun getOriginJson() : java.nio.file.Path {
var repositoryDir =
moduleId.group.replace('.', '/') + "/" + moduleId.name + "/" + moduleId.version
- val path : Path =
- Paths.get("third_party", "dependencies", repositoryDir, "origin.json");
- val path_new : Path =
- Paths.get("third_party", "dependencies_new", repositoryDir, "origin.json");
- return if (path.exists()) path else path_new
+ return Paths.get("third_party", "dependencies", repositoryDir, "origin.json");
}
// Simple data model of the content of origin.json generated by the tool to download
diff --git a/d8_r8/main/settings.gradle.kts b/d8_r8/main/settings.gradle.kts
index d4f7ab8..f279f0b 100644
--- a/d8_r8/main/settings.gradle.kts
+++ b/d8_r8/main/settings.gradle.kts
@@ -8,7 +8,7 @@
url = uri("file:../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../third_party/dependencies_new")
+ url = uri("file:../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../third_party/dependencies")
}
- maven {
- url = uri("file:../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/resourceshrinker/build.gradle.kts b/d8_r8/resourceshrinker/build.gradle.kts
index 750f076..c716378 100644
--- a/d8_r8/resourceshrinker/build.gradle.kts
+++ b/d8_r8/resourceshrinker/build.gradle.kts
@@ -36,9 +36,9 @@
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")
- implementation("com.android.tools:common:31.2.0-alpha10")
- implementation("com.android.tools:sdk-common:31.2.0-alpha10")
+ implementation("com.android.tools.layoutlib:layoutlib-api:31.2.0-rc01")
+ implementation("com.android.tools:common:31.2.0-rc01")
+ implementation("com.android.tools:sdk-common:31.2.0-rc01")
}
tasks {
diff --git a/d8_r8/resourceshrinker/settings.gradle.kts b/d8_r8/resourceshrinker/settings.gradle.kts
index d879107..31a3ce7 100644
--- a/d8_r8/resourceshrinker/settings.gradle.kts
+++ b/d8_r8/resourceshrinker/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../third_party/dependencies")
+ url = uri("file:../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../third_party/dependencies_new")
+ url = uri("file:../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../third_party/dependencies")
}
- maven {
- url = uri("file:../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/settings.gradle.kts b/d8_r8/settings.gradle.kts
index ad7577f..03039c0 100644
--- a/d8_r8/settings.gradle.kts
+++ b/d8_r8/settings.gradle.kts
@@ -67,16 +67,15 @@
val thirdParty = getRepoRoot().resolve("third_party")
downloadFromGoogleStorage(thirdParty.resolve("dependencies"))
-downloadFromGoogleStorage(thirdParty.resolve("dependencies_new"))
downloadFromGoogleStorage(thirdParty.resolve("dependencies_plugin"))
pluginManagement {
repositories {
maven {
- url = uri("file:../third_party/dependencies")
+ url = uri("file:../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../third_party/dependencies_new")
+ url = uri("file:../third_party/dependencies")
}
}
includeBuild(rootProject.projectDir.resolve("commonBuildSrc"))
@@ -87,9 +86,6 @@
maven {
url = uri("file:../third_party/dependencies")
}
- maven {
- url = uri("file:../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/shared/settings.gradle.kts b/d8_r8/shared/settings.gradle.kts
index 0de348f..35918f8 100644
--- a/d8_r8/shared/settings.gradle.kts
+++ b/d8_r8/shared/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../third_party/dependencies")
+ url = uri("file:../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../third_party/dependencies_new")
+ url = uri("file:../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../third_party/dependencies")
}
- maven {
- url = uri("file:../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/test/settings.gradle.kts b/d8_r8/test/settings.gradle.kts
index 375809a..38ba359 100644
--- a/d8_r8/test/settings.gradle.kts
+++ b/d8_r8/test/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../third_party/dependencies")
+ url = uri("file:../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../third_party/dependencies_new")
+ url = uri("file:../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../third_party/dependencies")
}
- maven {
- url = uri("file:../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/test_modules/tests_bootstrap/settings.gradle.kts b/d8_r8/test_modules/tests_bootstrap/settings.gradle.kts
index cb05e4f..b4fb012 100644
--- a/d8_r8/test_modules/tests_bootstrap/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_bootstrap/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../../third_party/dependencies")
+ url = uri("file:../../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../../third_party/dependencies_new")
+ url = uri("file:../../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../../third_party/dependencies")
}
- maven {
- url = uri("file:../../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/test_modules/tests_java_10/settings.gradle.kts b/d8_r8/test_modules/tests_java_10/settings.gradle.kts
index d7b2f9a..c1ca87a 100644
--- a/d8_r8/test_modules/tests_java_10/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_10/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../../third_party/dependencies")
+ url = uri("file:../../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../../third_party/dependencies_new")
+ url = uri("file:../../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../../third_party/dependencies")
}
- maven {
- url = uri("file:../../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/test_modules/tests_java_11/settings.gradle.kts b/d8_r8/test_modules/tests_java_11/settings.gradle.kts
index 90fa823..98af16e 100644
--- a/d8_r8/test_modules/tests_java_11/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_11/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../../third_party/dependencies")
+ url = uri("file:../../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../../third_party/dependencies_new")
+ url = uri("file:../../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../../third_party/dependencies")
}
- maven {
- url = uri("file:../../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/test_modules/tests_java_17/settings.gradle.kts b/d8_r8/test_modules/tests_java_17/settings.gradle.kts
index fc53d30..c01f377 100644
--- a/d8_r8/test_modules/tests_java_17/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_17/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../../third_party/dependencies")
+ url = uri("file:../../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../../third_party/dependencies_new")
+ url = uri("file:../../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../../third_party/dependencies")
}
- maven {
- url = uri("file:../../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/test_modules/tests_java_20/settings.gradle.kts b/d8_r8/test_modules/tests_java_20/settings.gradle.kts
index 85d94d0..390fdb7 100644
--- a/d8_r8/test_modules/tests_java_20/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_20/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../../third_party/dependencies")
+ url = uri("file:../../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../../third_party/dependencies_new")
+ url = uri("file:../../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../../third_party/dependencies")
}
- maven {
- url = uri("file:../../../third_party/dependencies_new")
- }
}
}
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 3397217..cb1f81e 100644
--- a/d8_r8/test_modules/tests_java_8/build.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/build.gradle.kts
@@ -34,6 +34,7 @@
val keepAnnoCompileTask = projectTask("keepanno", "compileJava")
val mainCompileTask = projectTask("main", "compileJava")
val mainDepsJarTask = projectTask("main", "depsJar")
+val resourceShrinkerDepsJarTask = projectTask("resourceshrinker", "depsJar")
dependencies {
implementation(keepAnnoJarTask.outputs.files)
@@ -41,7 +42,7 @@
implementation(projectTask("main", "processResources").outputs.files)
implementation(projectTask("resourceshrinker", "compileJava").outputs.files)
implementation(projectTask("resourceshrinker", "compileKotlin").outputs.files)
- implementation(projectTask("resourceshrinker", "depsJar").outputs.files)
+ implementation(resourceShrinkerDepsJarTask.outputs.files)
implementation(Deps.asm)
implementation(Deps.asmCommons)
implementation(Deps.asmUtil)
@@ -158,6 +159,7 @@
dependsOn(gradle.includedBuild("keepanno").task(":jar"))
dependsOn(gradle.includedBuild("resourceshrinker").task(":jar"))
from(testDependencies().map(::zipTree))
+ from(resourceShrinkerDepsJarTask.outputs.getFiles().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 a0cc31c..6600f09 100644
--- a/d8_r8/test_modules/tests_java_8/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_8/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../../third_party/dependencies")
+ url = uri("file:../../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../../third_party/dependencies_new")
+ url = uri("file:../../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../../third_party/dependencies")
}
- maven {
- url = uri("file:../../../third_party/dependencies_new")
- }
}
}
diff --git a/d8_r8/test_modules/tests_java_9/settings.gradle.kts b/d8_r8/test_modules/tests_java_9/settings.gradle.kts
index 46bc3a8..ad1c8ab 100644
--- a/d8_r8/test_modules/tests_java_9/settings.gradle.kts
+++ b/d8_r8/test_modules/tests_java_9/settings.gradle.kts
@@ -5,10 +5,10 @@
pluginManagement {
repositories {
maven {
- url = uri("file:../../../third_party/dependencies")
+ url = uri("file:../../../third_party/dependencies_plugin")
}
maven {
- url = uri("file:../../../third_party/dependencies_new")
+ url = uri("file:../../../third_party/dependencies")
}
}
}
@@ -18,9 +18,6 @@
maven {
url = uri("file:../../../third_party/dependencies")
}
- maven {
- url = uri("file:../../../third_party/dependencies_new")
- }
}
}
diff --git a/src/main/java/com/android/tools/r8/ArchiveProtoAndroidResourceConsumer.java b/src/main/java/com/android/tools/r8/ArchiveProtoAndroidResourceConsumer.java
index c601e80..f2c4b5d 100644
--- a/src/main/java/com/android/tools/r8/ArchiveProtoAndroidResourceConsumer.java
+++ b/src/main/java/com/android/tools/r8/ArchiveProtoAndroidResourceConsumer.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.utils.OutputBuilder;
import java.nio.file.Path;
+@Keep
public class ArchiveProtoAndroidResourceConsumer implements AndroidResourceConsumer {
private final OutputBuilder outputBuilder;
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 9964d6e..8be855e 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -7,6 +7,9 @@
import static com.android.tools.r8.utils.AssertionUtils.forTesting;
import static com.android.tools.r8.utils.ExceptionUtils.unwrapExecutionException;
+import com.android.build.shrinker.r8integration.LegacyResourceShrinker;
+import com.android.build.shrinker.r8integration.LegacyResourceShrinker.ShrinkerResult;
+import com.android.tools.r8.DexIndexedConsumer.ForwardingConsumer;
import com.android.tools.r8.androidapi.ApiReferenceStubber;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryKeepRuleGenerator;
import com.android.tools.r8.dex.ApplicationReader;
@@ -25,6 +28,7 @@
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.GenericSignatureContextBuilder;
import com.android.tools.r8.graph.GenericSignatureCorrectnessHelper;
+import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.SubtypingInfo;
@@ -75,6 +79,7 @@
import com.android.tools.r8.optimize.proto.ProtoNormalizer;
import com.android.tools.r8.optimize.redundantbridgeremoval.RedundantBridgeRemover;
import com.android.tools.r8.origin.CommandLineOrigin;
+import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.profile.art.ArtProfileCompletenessChecker;
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.repackaging.Repackaging;
@@ -105,9 +110,11 @@
import com.android.tools.r8.synthesis.SyntheticFinalization;
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ResourceTracing;
+import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.SelfRetraceTest;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
@@ -118,6 +125,8 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -125,6 +134,8 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.SAXException;
/**
* The R8 compiler.
@@ -246,6 +257,7 @@
@SuppressWarnings("DefaultCharset")
private void run(AndroidApp inputApp, ExecutorService executorService) throws IOException {
+ timing.begin("Run prelude");
assert options.programConsumer != null;
if (options.quiet) {
System.setOut(new PrintStream(ByteStreams.nullOutputStream()));
@@ -267,21 +279,32 @@
System.out.println("R8 is running with max memory:" + runtime.maxMemory());
}
options.prepareForReportingLibraryAndProgramDuplicates();
+ timing.end();
try {
AppView<AppInfoWithClassHierarchy> appView;
{
+ timing.begin("Read app");
ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
- DirectMappedDexApplication application = applicationReader.read(executorService).toDirect();
+ LazyLoadedDexApplication lazyLoaded = applicationReader.read(executorService);
+ timing.begin("To direct app");
+ DirectMappedDexApplication application = lazyLoaded.toDirect();
+ timing.end();
+ timing.end();
options.loadMachineDesugaredLibrarySpecification(timing, application);
+ timing.begin("Read main dex classes");
MainDexInfo mainDexInfo = applicationReader.readMainDexClassesForR8(application);
+ timing.end();
// Now that the dex-application is fully loaded, close any internal archive providers.
- inputApp.closeInternalArchiveProviders();
-
+ timing.time("Close providers", () -> inputApp.closeInternalArchiveProviders());
+ timing.begin("Create AppView");
appView = AppView.createForR8(application, mainDexInfo);
- appView.setAppServices(AppServices.builder(appView).build());
- SyntheticItems.collectSyntheticInputs(appView);
+ timing.end();
+ timing.time(
+ "Set app services", () -> appView.setAppServices(AppServices.builder(appView).build()));
+ timing.time(
+ "Collect synthetic inputs", () -> SyntheticItems.collectSyntheticInputs(appView));
}
-
+ timing.begin("Register references and more setup");
assert ArtProfileCompletenessChecker.verify(appView);
// Check for potentially having pass-through of Cf-code for kotlin libraries.
@@ -320,7 +343,7 @@
.rebuildWithClassHierarchy(
appView.getSyntheticItems().commit(appView.appInfo().app())));
}
-
+ timing.end();
timing.begin("Strip unused code");
timing.begin("Before enqueuer");
RuntimeTypeCheckInfo.Builder classMergingEnqueuerExtensionBuilder =
@@ -435,7 +458,7 @@
} finally {
timing.end();
}
-
+ timing.begin("Run center tasks");
assert appView.appInfo().hasLiveness();
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
@@ -550,7 +573,7 @@
timing.begin("AppliedGraphLens construction");
appView.setGraphLens(new AppliedGraphLens(appView));
timing.end();
-
+ timing.end();
if (options.shouldRerunEnqueuer()) {
timing.begin("Post optimization code stripping");
try {
@@ -678,7 +701,7 @@
converter, executorService, timing));
}
}
-
+ timing.begin("Run postlude");
performFinalMainDexTracing(appView, executorService);
if (appView.appInfo().hasLiveness()) {
@@ -830,17 +853,31 @@
new DesugaredLibraryKeepRuleGenerator(appView).runIfNecessary(timing);
+ List<Pair<Integer, byte[]>> dexFileContent = new ArrayList<>();
if (options.androidResourceProvider != null && options.androidResourceConsumer != null) {
- // Currently this is simply a pass through of all resources.
- writeAndroidResources(
- options.androidResourceProvider, options.androidResourceConsumer, appView.reporter());
+ options.programConsumer =
+ new ForwardingConsumer((DexIndexedConsumer) options.programConsumer) {
+ @Override
+ public void accept(
+ int fileIndex,
+ ByteDataView data,
+ Set<String> descriptors,
+ DiagnosticsHandler handler) {
+ dexFileContent.add(new Pair<>(fileIndex, data.copyByteData()));
+ super.accept(fileIndex, data, descriptors, handler);
+ }
+ };
}
assert appView.verifyMovedMethodsHaveOriginalMethodPosition();
+ timing.end();
// Generate the resulting application resources.
writeApplication(appView, inputApp, executorService);
+ if (options.androidResourceProvider != null && options.androidResourceConsumer != null) {
+ shrinkResources(dexFileContent);
+ }
assert appView.getDontWarnConfiguration().validate(options);
options.printWarnings();
@@ -856,14 +893,68 @@
}
}
- private void writeAndroidResources(
- AndroidResourceProvider androidResourceProvider,
- AndroidResourceConsumer androidResourceConsumer,
- DiagnosticsHandler diagnosticsHandler) {
- ResourceTracing resourceTracing = ResourceTracing.getImpl();
- resourceTracing.setConsumer(androidResourceConsumer);
- resourceTracing.setProvider(androidResourceProvider);
- resourceTracing.done(diagnosticsHandler);
+ private void shrinkResources(List<Pair<Integer, byte[]>> dexFileContent) {
+ LegacyResourceShrinker.Builder resourceShrinkerBuilder = LegacyResourceShrinker.builder();
+ Reporter reporter = options.reporter;
+ dexFileContent.forEach(p -> resourceShrinkerBuilder.addDexInput(p.getFirst(), p.getSecond()));
+ try {
+ Collection<AndroidResourceInput> androidResources =
+ options.androidResourceProvider.getAndroidResources();
+ for (AndroidResourceInput androidResource : androidResources) {
+ try {
+ byte[] bytes = androidResource.getByteStream().readAllBytes();
+ Path path = Paths.get(androidResource.getPath().location());
+ switch (androidResource.getKind()) {
+ case MANIFEST:
+ resourceShrinkerBuilder.setManifest(path, bytes);
+ break;
+ case RES_FOLDER_FILE:
+ resourceShrinkerBuilder.addResFolderInput(path, bytes);
+ break;
+ case RESOURCE_TABLE:
+ resourceShrinkerBuilder.setResourceTable(path, bytes);
+ break;
+ case XML_FILE:
+ resourceShrinkerBuilder.addXmlInput(path, bytes);
+ break;
+ case UNKNOWN:
+ break;
+ }
+ } catch (IOException e) {
+ reporter.error(new ExceptionDiagnostic(e, androidResource.getOrigin()));
+ }
+ }
+
+ LegacyResourceShrinker shrinker = resourceShrinkerBuilder.build();
+ ShrinkerResult shrinkerResult = shrinker.run();
+ AndroidResourceConsumer androidResourceConsumer = options.androidResourceConsumer;
+ Set<String> toKeep = shrinkerResult.getResFolderEntriesToKeep();
+ for (AndroidResourceInput androidResource : androidResources) {
+ switch (androidResource.getKind()) {
+ case MANIFEST:
+ case UNKNOWN:
+ androidResourceConsumer.accept(
+ new R8PassThroughAndroidResource(androidResource, reporter), reporter);
+ break;
+ case RESOURCE_TABLE:
+ androidResourceConsumer.accept(
+ new R8AndroidResourceWithData(
+ androidResource, reporter, shrinkerResult.getResourceTableInProtoFormat()),
+ reporter);
+ break;
+ case RES_FOLDER_FILE:
+ case XML_FILE:
+ if (toKeep.contains(androidResource.getPath().location())) {
+ androidResourceConsumer.accept(
+ new R8PassThroughAndroidResource(androidResource, reporter), reporter);
+ }
+ break;
+ }
+ }
+ androidResourceConsumer.finished(reporter);
+ } catch (ParserConfigurationException | SAXException | ResourceException | IOException e) {
+ reporter.error(new ExceptionDiagnostic(e));
+ }
}
private static boolean allReferencesAssignedApiLevel(
@@ -1093,4 +1184,58 @@
}
ExceptionUtils.withMainProgramHandler(() -> run(args));
}
+
+ private abstract static class R8AndroidResourceBase implements AndroidResourceOutput {
+
+ protected final AndroidResourceInput androidResource;
+ protected final Reporter reporter;
+
+ public R8AndroidResourceBase(AndroidResourceInput androidResource, Reporter reporter) {
+ this.androidResource = androidResource;
+ this.reporter = reporter;
+ }
+
+ @Override
+ public ResourcePath getPath() {
+ return androidResource.getPath();
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return androidResource.getOrigin();
+ }
+ }
+
+ private static class R8PassThroughAndroidResource extends R8AndroidResourceBase {
+
+ public R8PassThroughAndroidResource(AndroidResourceInput androidResource, Reporter reporter) {
+ super(androidResource, reporter);
+ }
+
+ @Override
+ public ByteDataView getByteDataView() {
+ try {
+ return ByteDataView.of(ByteStreams.toByteArray(androidResource.getByteStream()));
+ } catch (IOException | ResourceException e) {
+ reporter.error(new ExceptionDiagnostic(e, androidResource.getOrigin()));
+ }
+ return null;
+ }
+ }
+
+ private static class R8AndroidResourceWithData extends R8AndroidResourceBase {
+
+ private final byte[] data;
+
+ public R8AndroidResourceWithData(
+ AndroidResourceInput androidResource, Reporter reporter, byte[] data) {
+ super(androidResource, reporter);
+ this.data = data;
+ }
+
+ @Override
+ public ByteDataView getByteDataView() {
+ return ByteDataView.of(data);
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/cf/CfVersion.java b/src/main/java/com/android/tools/r8/cf/CfVersion.java
index c85f50f..0c1d72b 100644
--- a/src/main/java/com/android/tools/r8/cf/CfVersion.java
+++ b/src/main/java/com/android/tools/r8/cf/CfVersion.java
@@ -46,8 +46,8 @@
public static final CfVersion V20_PREVIEW = new CfVersion(Opcodes.V20 | Opcodes.V_PREVIEW);
public static final CfVersion V21 = new CfVersion(Opcodes.V21);
public static final CfVersion V21_PREVIEW = new CfVersion(Opcodes.V21 | Opcodes.V_PREVIEW);
- public static final CfVersion V22 = new CfVersion(66);
- public static final CfVersion V22_PREVIEW = new CfVersion(66 | Opcodes.V_PREVIEW);
+ public static final CfVersion V22 = new CfVersion(Opcodes.V22);
+ public static final CfVersion V22_PREVIEW = new CfVersion(Opcodes.V22 | Opcodes.V_PREVIEW);
private final int version;
@@ -72,7 +72,8 @@
CfVersion.V18,
CfVersion.V19,
CfVersion.V20,
- CfVersion.V21
+ CfVersion.V21,
+ CfVersion.V22
};
// Private constructor in case we want to canonicalize versions.
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/ResourceShrinkerImpl.kt b/src/resourceshrinker/java/com/android/build/shrinker/ResourceShrinkerImpl.kt
index 1136085..153f1ce 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/ResourceShrinkerImpl.kt
+++ b/src/resourceshrinker/java/com/android/build/shrinker/ResourceShrinkerImpl.kt
@@ -301,6 +301,11 @@
.any { it.isReachable }
}
+fun ResourceStore.isJarPathReachable(path: String) : Boolean {
+ val (_, folder, name) = path.split('/', limit = 3)
+ return isJarPathReachable(folder, name);
+}
+
private fun ResourceStore.getResourceId(
folder: String,
name: String
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/graph/ProtoResourcesGraphBuilder.kt b/src/resourceshrinker/java/com/android/build/shrinker/graph/ProtoResourcesGraphBuilder.kt
index 130e585..a0a1f76 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/graph/ProtoResourcesGraphBuilder.kt
+++ b/src/resourceshrinker/java/com/android/build/shrinker/graph/ProtoResourcesGraphBuilder.kt
@@ -21,6 +21,7 @@
import com.android.aapt.Resources.FileReference
import com.android.aapt.Resources.FileReference.Type.PROTO_XML
import com.android.aapt.Resources.Reference
+import com.android.aapt.Resources.ResourceTable
import com.android.aapt.Resources.XmlAttribute
import com.android.aapt.Resources.XmlElement
import com.android.aapt.Resources.XmlNode
@@ -56,12 +57,23 @@
* @param resourceTable path to resource table in proto format.
*/
class ProtoResourcesGraphBuilder(
- private val resourceRoot: Path,
- private val resourceTable: Path
+ private val resourceRoot: ResFolderFileTree,
+ private val resourceTableProducer: (ResourceShrinkerModel) -> ResourceTable
) : ResourcesGraphBuilder {
+ constructor(resourceRootPath: Path, resourceTablePath: Path) : this(
+ object : ResFolderFileTree {
+ override fun getEntryByName(pathInRes: String): ByteArray {
+ val lazyVal : ByteArray by lazy {
+ Files.readAllBytes(resourceRootPath.resolve(pathInRes))
+ }
+ return lazyVal
+ }
+ },
+ { model -> model.readResourceTable(resourceTablePath) }
+ )
override fun buildGraph(model: ResourceShrinkerModel) {
- model.readResourceTable(resourceTable).entriesSequence()
+ resourceTableProducer(model).entriesSequence()
.map { (id, _, _, entry) ->
model.resourceStore.getResource(id)?.let {
ReferencesForResourceFinder(resourceRoot, model, entry, it)
@@ -71,9 +83,12 @@
.forEach { it.findReferences() }
}
}
+interface ResFolderFileTree {
+ fun getEntryByName(pathInRes: String) : ByteArray
+}
private class ReferencesForResourceFinder(
- private val resourcesRoot: Path,
+ private val resourcesRoot: ResFolderFileTree,
private val model: ResourceShrinkerModel,
private val entry: Entry,
private val current: Resource
@@ -196,10 +211,9 @@
}
private fun findFromFile(file: FileReference) {
- val path = resourcesRoot.resolve(file.path.substringAfter("res/"))
- val bytes: ByteArray by lazy { Files.readAllBytes(path) }
+ val bytes = resourcesRoot.getEntryByName(file.path.substringAfter("res/"))
val content: String by lazy { String(bytes, StandardCharsets.UTF_8) }
- val extension = Ascii.toLowerCase(path.fileName.toString()).substringAfter('.')
+ val extension = Ascii.toLowerCase(file.path.substringAfterLast('.'))
when {
file.type == PROTO_XML -> fillFromXmlNode(XmlNode.parseFrom(bytes))
extension in listOf("html", "htm") -> webTokenizers.tokenizeHtml(content)
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java
new file mode 100644
index 0000000..87158c9
--- /dev/null
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java
@@ -0,0 +1,277 @@
+// 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.
+
+package com.android.build.shrinker.r8integration;
+
+import static java.nio.charset.StandardCharsets.UTF_16BE;
+import static java.nio.charset.StandardCharsets.UTF_16LE;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.android.aapt.Resources.ResourceTable;
+import com.android.aapt.Resources.XmlNode;
+import com.android.build.shrinker.NoDebugReporter;
+import com.android.build.shrinker.ResourceShrinkerImplKt;
+import com.android.build.shrinker.ResourceTableUtilKt;
+import com.android.build.shrinker.graph.ProtoResourcesGraphBuilder;
+import com.android.build.shrinker.graph.ResFolderFileTree;
+import com.android.build.shrinker.r8integration.R8ResourceShrinkerState.R8ResourceShrinkerModel;
+import com.android.build.shrinker.usages.DexFileAnalysisCallback;
+import com.android.build.shrinker.usages.ProtoAndroidManifestUsageRecorderKt;
+import com.android.build.shrinker.usages.R8ResourceShrinker;
+import com.android.build.shrinker.usages.ToolsAttributeUsageRecorderKt;
+import com.android.ide.common.resources.ResourcesUtil;
+import com.android.ide.common.resources.usage.ResourceStore;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.xml.parsers.ParserConfigurationException;
+import org.jetbrains.annotations.NotNull;
+import org.xml.sax.SAXException;
+
+public class LegacyResourceShrinker {
+ private final Map<Integer, byte[]> dexInputs;
+ private final List<PathAndBytes> resFolderInputs;
+ private final List<PathAndBytes> xmlInputs;
+ private final PathAndBytes manifest;
+ private final PathAndBytes resourceTable;
+
+ public static class Builder {
+
+ private final Map<Integer, byte[]> dexInputs = new HashMap<>();
+ private final List<PathAndBytes> resFolderInputs = new ArrayList<>();
+ private final List<PathAndBytes> xmlInputs = new ArrayList<>();
+
+ private PathAndBytes manifest;
+ private PathAndBytes resourceTable;
+
+ private Builder() {}
+
+ public Builder setManifest(Path path, byte[] bytes) {
+ this.manifest = new PathAndBytes(bytes, path);
+ return this;
+ }
+
+ public Builder setResourceTable(Path path, byte[] bytes) {
+ this.resourceTable = new PathAndBytes(bytes, path);
+ return this;
+ }
+
+ public Builder addDexInput(int index, byte[] bytes) {
+ dexInputs.put(index, bytes);
+ return this;
+ }
+
+ public Builder addResFolderInput(Path path, byte[] bytes) {
+ resFolderInputs.add(new PathAndBytes(bytes, path));
+ return this;
+ }
+
+ public Builder addXmlInput(Path path, byte[] bytes) {
+ xmlInputs.add(new PathAndBytes(bytes, path));
+ return this;
+ }
+
+ public LegacyResourceShrinker build() {
+ assert manifest != null && resourceTable != null;
+ return new LegacyResourceShrinker(
+ dexInputs, resFolderInputs, manifest, resourceTable, xmlInputs);
+ }
+ }
+
+ private LegacyResourceShrinker(
+ Map<Integer, byte[]> dexInputs,
+ List<PathAndBytes> resFolderInputs,
+ PathAndBytes manifest,
+ PathAndBytes resourceTable,
+ List<PathAndBytes> xmlInputs) {
+ this.dexInputs = dexInputs;
+ this.resFolderInputs = resFolderInputs;
+ this.manifest = manifest;
+ this.resourceTable = resourceTable;
+ this.xmlInputs = xmlInputs;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public ShrinkerResult run() throws IOException, ParserConfigurationException, SAXException {
+ R8ResourceShrinkerModel model = new R8ResourceShrinkerModel(NoDebugReporter.INSTANCE, false);
+ ResourceTable loadedResourceTable = ResourceTable.parseFrom(resourceTable.bytes);
+ model.instantiateFromResourceTable(loadedResourceTable);
+ for (Entry<Integer, byte[]> entry : dexInputs.entrySet()) {
+ // The analysis needs an origin for the dex files, synthesize an easy recognizable one.
+ Path inMemoryR8 = Paths.get("in_memory_r8_classes" + entry.getKey() + ".dex");
+ R8ResourceShrinker.runResourceShrinkerAnalysis(
+ entry.getValue(), inMemoryR8, new DexFileAnalysisCallback(inMemoryR8, model));
+ }
+ ProtoAndroidManifestUsageRecorderKt.recordUsagesFromNode(
+ XmlNode.parseFrom(manifest.bytes), model);
+ for (PathAndBytes xmlInput : xmlInputs) {
+ if (xmlInput.path.startsWith("res/raw")) {
+ ToolsAttributeUsageRecorderKt.processRawXml(getUtfReader(xmlInput.getBytes()), model);
+ }
+ }
+ new ProtoResourcesGraphBuilder(
+ new ResFolderFileTree() {
+ Map<String, PathAndBytes> pathToBytes =
+ new ImmutableMap.Builder<String, PathAndBytes>()
+ .putAll(
+ xmlInputs.stream()
+ .collect(Collectors.toMap(PathAndBytes::getPathWithoutRes, a -> a)))
+ .putAll(
+ resFolderInputs.stream()
+ .collect(Collectors.toMap(PathAndBytes::getPathWithoutRes, a -> a)))
+ .build();
+
+ @Override
+ public byte[] getEntryByName(@NotNull String pathInRes) {
+ return pathToBytes.get(pathInRes).getBytes();
+ }
+ },
+ unused -> loadedResourceTable)
+ .buildGraph(model);
+ ResourceStore resourceStore = model.getResourceStore();
+ resourceStore.processToolsAttributes();
+ model.keepPossiblyReferencedResources();
+ // Transitively mark the reachable resources in the model.
+ // Finds unused resources in provided resources collection.
+ // Marks all used resources as 'reachable' in original collection.
+ ResourcesUtil.findUnusedResources(model.getResourceStore().getResources(), x -> {});
+ ImmutableSet.Builder<String> resEntriesToKeep = new ImmutableSet.Builder<>();
+ for (PathAndBytes xmlInput : Iterables.concat(xmlInputs, resFolderInputs)) {
+ if (ResourceShrinkerImplKt.isJarPathReachable(resourceStore, xmlInput.path.toString())) {
+ resEntriesToKeep.add(xmlInput.path.toString());
+ }
+ }
+ List<Integer> resourceIdsToRemove =
+ model.getResourceStore().getResources().stream()
+ .filter(r -> !r.isReachable())
+ .map(r -> r.value)
+ .collect(Collectors.toList());
+ ResourceTable shrunkenResourceTable =
+ ResourceTableUtilKt.nullOutEntriesWithIds(loadedResourceTable, resourceIdsToRemove);
+ return new ShrinkerResult(resEntriesToKeep.build(), shrunkenResourceTable.toByteArray());
+ }
+
+ // Lifted from com/android/utils/XmlUtils.java which we can't easily update internal dependency
+ // for.
+ /**
+ * Returns a character reader for the given bytes, which must be a UTF encoded file.
+ *
+ * <p>The reader does not need to be closed by the caller (because the file is read in full in one
+ * shot and the resulting array is then wrapped in a byte array input stream, which does not need
+ * to be closed.)
+ */
+ public static Reader getUtfReader(byte[] bytes) throws IOException {
+ int length = bytes.length;
+ if (length == 0) {
+ return new StringReader("");
+ }
+
+ switch (bytes[0]) {
+ case (byte) 0xEF:
+ {
+ if (length >= 3 && bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF) {
+ // UTF-8 BOM: EF BB BF: Skip it
+ return new InputStreamReader(new ByteArrayInputStream(bytes, 3, length - 3), UTF_8);
+ }
+ break;
+ }
+ case (byte) 0xFE:
+ {
+ if (length >= 2 && bytes[1] == (byte) 0xFF) {
+ // UTF-16 Big Endian BOM: FE FF
+ return new InputStreamReader(new ByteArrayInputStream(bytes, 2, length - 2), UTF_16BE);
+ }
+ break;
+ }
+ case (byte) 0xFF:
+ {
+ if (length >= 2 && bytes[1] == (byte) 0xFE) {
+ if (length >= 4 && bytes[2] == (byte) 0x00 && bytes[3] == (byte) 0x00) {
+ // UTF-32 Little Endian BOM: FF FE 00 00
+ return new InputStreamReader(
+ new ByteArrayInputStream(bytes, 4, length - 4), "UTF-32LE");
+ }
+
+ // UTF-16 Little Endian BOM: FF FE
+ return new InputStreamReader(new ByteArrayInputStream(bytes, 2, length - 2), UTF_16LE);
+ }
+ break;
+ }
+ case (byte) 0x00:
+ {
+ if (length >= 4
+ && bytes[0] == (byte) 0x00
+ && bytes[1] == (byte) 0x00
+ && bytes[2] == (byte) 0xFE
+ && bytes[3] == (byte) 0xFF) {
+ // UTF-32 Big Endian BOM: 00 00 FE FF
+ return new InputStreamReader(
+ new ByteArrayInputStream(bytes, 4, length - 4), "UTF-32BE");
+ }
+ break;
+ }
+ }
+
+ // No byte order mark: Assume UTF-8 (where the BOM is optional).
+ return new InputStreamReader(new ByteArrayInputStream(bytes), UTF_8);
+ }
+
+ public static class ShrinkerResult {
+ private final Set<String> resFolderEntriesToKeep;
+ private final byte[] resourceTableInProtoFormat;
+
+ public ShrinkerResult(Set<String> resFolderEntriesToKeep, byte[] resourceTableInProtoFormat) {
+ this.resFolderEntriesToKeep = resFolderEntriesToKeep;
+ this.resourceTableInProtoFormat = resourceTableInProtoFormat;
+ }
+
+ public byte[] getResourceTableInProtoFormat() {
+ return resourceTableInProtoFormat;
+ }
+
+ public Set<String> getResFolderEntriesToKeep() {
+ return resFolderEntriesToKeep;
+ }
+ }
+
+ private static class PathAndBytes {
+ private final byte[] bytes;
+ private final Path path;
+
+ private PathAndBytes(byte[] bytes, Path path) {
+ this.bytes = bytes;
+ this.path = path;
+ }
+
+ public Path getPath() {
+ return path;
+ }
+
+ public String getPathWithoutRes() {
+ assert path.toString().startsWith("res/");
+ return path.toString().substring(4);
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+ }
+}
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
index 5f9bec6..d8ac6a9 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
@@ -32,7 +32,7 @@
r8ResourceShrinkerModel.instantiateFromResourceTable(inputStream);
}
- private static class R8ResourceShrinkerModel extends ResourceShrinkerModel {
+ public static class R8ResourceShrinkerModel extends ResourceShrinkerModel {
public R8ResourceShrinkerModel(
ShrinkerDebugReporter debugReporter, boolean supportMultipackages) {
@@ -40,25 +40,29 @@
}
// Similar to instantiation in ProtoResourceTableGatherer, but using an inputstream.
- public void instantiateFromResourceTable(InputStream inputStream) {
+ void instantiateFromResourceTable(InputStream inputStream) {
try {
ResourceTable resourceTable = ResourceTable.parseFrom(inputStream);
- ResourceTableUtilKt.entriesSequence(resourceTable)
- .iterator()
- .forEachRemaining(
- entryWrapper -> {
- ResourceType resourceType = ResourceType.fromClassName(entryWrapper.getType());
- if (resourceType != ResourceType.STYLEABLE) {
- this.addResource(
- resourceType,
- entryWrapper.getPackageName(),
- ResourcesUtil.resourceNameToFieldName(entryWrapper.getEntry().getName()),
- entryWrapper.getId());
- }
- });
+ instantiateFromResourceTable(resourceTable);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
+
+ void instantiateFromResourceTable(ResourceTable resourceTable) {
+ ResourceTableUtilKt.entriesSequence(resourceTable)
+ .iterator()
+ .forEachRemaining(
+ entryWrapper -> {
+ ResourceType resourceType = ResourceType.fromClassName(entryWrapper.getType());
+ if (resourceType != ResourceType.STYLEABLE) {
+ this.addResource(
+ resourceType,
+ entryWrapper.getPackageName(),
+ ResourcesUtil.resourceNameToFieldName(entryWrapper.getEntry().getName()),
+ entryWrapper.getId());
+ }
+ });
+ }
}
}
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/usages/DexUsageRecorder.kt b/src/resourceshrinker/java/com/android/build/shrinker/usages/DexUsageRecorder.kt
index 3f1a676..5d6a0df 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/usages/DexUsageRecorder.kt
+++ b/src/resourceshrinker/java/com/android/build/shrinker/usages/DexUsageRecorder.kt
@@ -56,7 +56,7 @@
}
}
-private class DexFileAnalysisCallback(
+class DexFileAnalysisCallback(
private val path: Path,
private val model: ResourceShrinkerModel
) : AnalysisCallback {
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/usages/ProtoAndroidManifestUsageRecorder.kt b/src/resourceshrinker/java/com/android/build/shrinker/usages/ProtoAndroidManifestUsageRecorder.kt
index 4e6aa3e..77bb8f6 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/usages/ProtoAndroidManifestUsageRecorder.kt
+++ b/src/resourceshrinker/java/com/android/build/shrinker/usages/ProtoAndroidManifestUsageRecorder.kt
@@ -34,25 +34,25 @@
recordUsagesFromNode(root, model)
}
- private fun recordUsagesFromNode(node: XmlNode, model: ResourceShrinkerModel) {
- // Records only resources from element attributes that have reference items with resolved
- // ids or names.
- if (!node.hasElement()) {
- return
- }
- node.element.attributeList.asSequence()
- .filter { it.hasCompiledItem() }
- .map { it.compiledItem }
- .filter { it.hasRef() }
- .map { it.ref }
- .flatMap {
- // If resource id is available prefer this id to name.
- when {
- it.id != 0 -> listOfNotNull(model.resourceStore.getResource(it.id))
- else -> model.resourceStore.getResourcesFromUrl("@${it.name}")
- }.asSequence()
- }
- .forEach { ResourceUsageModel.markReachable(it) }
- node.element.childList.forEach { recordUsagesFromNode(it, model) }
+}
+fun recordUsagesFromNode(node: XmlNode, model: ResourceShrinkerModel) {
+ // Records only resources from element attributes that have reference items with resolved
+ // ids or names.
+ if (!node.hasElement()) {
+ return
}
+ node.element.attributeList.asSequence()
+ .filter { it.hasCompiledItem() }
+ .map { it.compiledItem }
+ .filter { it.hasRef() }
+ .map { it.ref }
+ .flatMap {
+ // If resource id is available prefer this id to name.
+ when {
+ it.id != 0 -> listOfNotNull(model.resourceStore.getResource(it.id))
+ else -> model.resourceStore.getResourcesFromUrl("@${it.name}")
+ }.asSequence()
+ }
+ .forEach { ResourceUsageModel.markReachable(it) }
+ node.element.childList.forEach { recordUsagesFromNode(it, model) }
}
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/usages/ToolsAttributeUsageRecorder.kt b/src/resourceshrinker/java/com/android/build/shrinker/usages/ToolsAttributeUsageRecorder.kt
index 0dae39a..8e43cd8 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/usages/ToolsAttributeUsageRecorder.kt
+++ b/src/resourceshrinker/java/com/android/build/shrinker/usages/ToolsAttributeUsageRecorder.kt
@@ -16,9 +16,11 @@
package com.android.build.shrinker.usages
+import com.android.SdkConstants.TOOLS_NS_NAME
import com.android.SdkConstants.VALUE_STRICT
import com.android.build.shrinker.ResourceShrinkerModel
import com.android.utils.XmlUtils
+import com.google.common.collect.ImmutableMap
import com.google.common.collect.ImmutableMap.copyOf
import java.io.Reader
import java.nio.file.Files
@@ -37,9 +39,6 @@
* @param rawResourcesPath path to folder with resources in raw format.
*/
class ToolsAttributeUsageRecorder(val rawResourcesPath: Path) : ResourceUsageRecorder {
- companion object {
- private val TOOLS_NAMESPACE = "http://schemas.android.com/tools"
- }
override fun recordUsages(model: ResourceShrinkerModel) {
Files.walk(rawResourcesPath)
@@ -48,42 +47,48 @@
}
private fun processRawXml(path: Path, model: ResourceShrinkerModel) {
- processResourceToolsAttributes(path).forEach { key, value ->
- when (key) {
- "keep" -> model.resourceStore.recordKeepToolAttribute(value)
- "discard" -> model.resourceStore.recordDiscardToolAttribute(value)
- "shrinkMode" ->
- if (value == VALUE_STRICT) {
- model.resourceStore.safeMode = false
- }
- }
- }
- }
-
- private fun processResourceToolsAttributes(path: Path): Map<String, String> {
- val toolsAttributes = mutableMapOf<String, String>()
- XmlUtils.getUtfReader(path.toFile()).use { reader: Reader ->
- val factory = XMLInputFactory.newInstance()
- val xmlStreamReader = factory.createXMLStreamReader(reader)
-
- var rootElementProcessed = false
- while (!rootElementProcessed && xmlStreamReader.hasNext()) {
- xmlStreamReader.next()
- if (xmlStreamReader.isStartElement) {
- if (xmlStreamReader.localName == "resources") {
- for (i in 0 until xmlStreamReader.attributeCount) {
- if (xmlStreamReader.getAttributeNamespace(i) == TOOLS_NAMESPACE) {
- toolsAttributes.put(
- xmlStreamReader.getAttributeLocalName(i),
- xmlStreamReader.getAttributeValue(i)
- )
- }
- }
- }
- rootElementProcessed = true
- }
- }
- }
- return copyOf(toolsAttributes)
+ processRawXml(XmlUtils.getUtfReader(path.toFile()), model)
}
}
+
+fun processRawXml(reader: Reader, model: ResourceShrinkerModel) {
+ processResourceToolsAttributes(reader).forEach { key, value ->
+ when (key) {
+ "keep" -> model.resourceStore.recordKeepToolAttribute(value)
+ "discard" -> model.resourceStore.recordDiscardToolAttribute(value)
+ "shrinkMode" ->
+ if (value == VALUE_STRICT) {
+ model.resourceStore.safeMode = false
+ }
+ }
+ }
+}
+
+fun processResourceToolsAttributes(utfReader: Reader?): ImmutableMap<String, String> {
+ val toolsAttributes = mutableMapOf<String, String>()
+ utfReader.use { reader: Reader? ->
+ val factory = XMLInputFactory.newInstance()
+ val xmlStreamReader = factory.createXMLStreamReader(reader)
+
+ var rootElementProcessed = false
+ while (!rootElementProcessed && xmlStreamReader.hasNext()) {
+ xmlStreamReader.next()
+ if (xmlStreamReader.isStartElement) {
+ if (xmlStreamReader.localName == "resources") {
+ for (i in 0 until xmlStreamReader.attributeCount) {
+ val namespace = "http://schemas.android.com/tools"
+ if (xmlStreamReader.getAttributeNamespace(i) == namespace) {
+ toolsAttributes.put(
+ xmlStreamReader.getAttributeLocalName(i),
+ xmlStreamReader.getAttributeValue(i)
+ )
+ }
+ }
+ }
+ rootElementProcessed = true
+ }
+ }
+ }
+ return copyOf(toolsAttributes)
+}
+
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 238594e..d55e5c5 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.R8Command.Builder;
import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource;
import com.android.tools.r8.benchmarks.BenchmarkResults;
import com.android.tools.r8.dexsplitter.SplitterTestBase.RunInterface;
import com.android.tools.r8.dexsplitter.SplitterTestBase.SplitRunner;
@@ -16,6 +17,7 @@
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.keepanno.KeepEdgeAnnotationsTest;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.profile.art.ArtProfileConsumer;
import com.android.tools.r8.profile.art.ArtProfileProvider;
import com.android.tools.r8.profile.art.model.ExternalArtProfile;
@@ -81,6 +83,7 @@
private final List<Path> mainDexRulesFiles = new ArrayList<>();
private final List<String> applyMappingMaps = new ArrayList<>();
private final List<Path> features = new ArrayList<>();
+ private Path resourceShrinkerOutput = null;
private PartitionMapConsumer partitionMapConsumer = null;
@Override
@@ -141,6 +144,7 @@
}
class Box {
+
private List<ProguardConfigurationRule> syntheticProguardRules;
private ProguardConfiguration proguardConfiguration;
}
@@ -166,7 +170,8 @@
graphConsumer,
getMinApiLevel(),
features,
- residualArtProfiles);
+ residualArtProfiles,
+ resourceShrinkerOutput);
switch (allowedDiagnosticMessages) {
case ALL:
compileResult.getDiagnosticMessages().assertAllDiagnosticsMatch(new IsAnything<>());
@@ -868,4 +873,25 @@
this.partitionMapConsumer = partitionMapConsumer;
return self();
}
+
+ public T addAndroidResources(AndroidTestResource testResource) throws IOException {
+ return addAndroidResources(
+ testResource, getState().getNewTempFile("resourceshrinkeroutput.zip"));
+ }
+
+ public T addAndroidResources(AndroidTestResource testResource, Path output) throws IOException {
+ addResourceShrinkerProviderAndConsumer(testResource.getResourceZip(), output);
+ return addProgramClassFileData(testResource.getRClass().getClassFileData());
+ }
+
+ private T addResourceShrinkerProviderAndConsumer(Path resources, Path output) throws IOException {
+ resourceShrinkerOutput = output;
+ getBuilder()
+ .setAndroidResourceProvider(
+ new ArchiveProtoAndroidResourceProvider(resources, new PathOrigin(resources)));
+ getBuilder()
+ .setAndroidResourceConsumer(
+ new ArchiveProtoAndroidResourceConsumer(resourceShrinkerOutput));
+ return self();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
index 1ca26f0..82997e9 100644
--- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -6,8 +6,10 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.ResourceTableInspector;
import com.android.tools.r8.dexsplitter.SplitterTestBase.SplitRunner;
import com.android.tools.r8.profile.art.model.ExternalArtProfile;
import com.android.tools.r8.profile.art.utils.ArtProfileInspector;
@@ -19,6 +21,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThrowingBiConsumer;
import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.ZipUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.graphinspector.GraphInspector;
@@ -36,6 +39,7 @@
private final CollectingGraphConsumer graphConsumer;
private final List<Path> features;
private final List<ExternalArtProfile> residualArtProfiles;
+ private final Path resourceShrinkerOutput;
R8TestCompileResult(
TestState state,
@@ -48,7 +52,8 @@
CollectingGraphConsumer graphConsumer,
int minApiLevel,
List<Path> features,
- List<ExternalArtProfile> residualArtProfiles) {
+ List<ExternalArtProfile> residualArtProfiles,
+ Path resourceShrinkerOutput) {
super(state, app, minApiLevel, outputMode, libraryDesugaringTestConfiguration);
this.proguardConfiguration = proguardConfiguration;
this.syntheticProguardRules = syntheticProguardRules;
@@ -56,6 +61,7 @@
this.graphConsumer = graphConsumer;
this.features = features;
this.residualArtProfiles = residualArtProfiles;
+ this.resourceShrinkerOutput = resourceShrinkerOutput;
}
@Override
@@ -149,6 +155,15 @@
return self();
}
+ public <E extends Throwable> R8TestCompileResult inspectShrunkenResources(
+ Consumer<ResourceTableInspector> consumer) throws IOException {
+ assertNotNull(resourceShrinkerOutput);
+ consumer.accept(
+ new ResourceTableInspector(
+ ZipUtils.readSingleEntry(resourceShrinkerOutput, "resources.pb")));
+ return self();
+ }
+
public GraphInspector graphInspector() throws IOException {
assert graphConsumer != null;
return new GraphInspector(graphConsumer, inspector());
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 4e98e36..84ccfd9 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -136,10 +136,6 @@
return addProgramClasses(classes).addInnerClasses(classes);
}
- public T addAndroidResources(AndroidTestResource testResource) throws IOException {
- return addProgramClassFileData(testResource.getRClass().getClassFileData());
- }
-
public T addInnerClasses(Class<?>... classes) throws IOException {
return addInnerClasses(Arrays.asList(classes));
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index eceaf77..f1f836b 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -212,8 +212,8 @@
public static final String R8_TEST_BUCKET = "r8-test-results";
- public static final String ASM_JAR = BUILD_DIR + "deps/asm-9.5.jar";
- public static final String ASM_UTIL_JAR = BUILD_DIR + "deps/asm-util-9.5.jar";
+ public static final String ASM_JAR = BUILD_DIR + "deps/asm-9.6.jar";
+ public static final String ASM_UTIL_JAR = BUILD_DIR + "deps/asm-util-9.6.jar";
public static final Path API_SAMPLE_JAR =
Paths.get(getProjectRoot(), "tests", "r8_api_usage_sample.jar");
diff --git a/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java b/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
index c1dde31..63de716 100644
--- a/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
+++ b/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
@@ -6,6 +6,10 @@
import static com.android.tools.r8.TestBase.javac;
import static com.android.tools.r8.TestBase.transformer;
+import com.android.aapt.Resources;
+import com.android.aapt.Resources.ConfigValue;
+import com.android.aapt.Resources.Item;
+import com.android.aapt.Resources.ResourceTable;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -16,23 +20,28 @@
import com.android.tools.r8.utils.StreamUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.collect.MoreCollectors;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.stream.Collectors;
+import org.junit.Assert;
import org.junit.rules.TemporaryFolder;
public class AndroidResourceTestingUtils {
enum RClassType {
STRING,
- DRAWABLE;
+ DRAWABLE,
+ XML;
public static RClassType fromClass(Class clazz) {
String type = rClassWithoutNamespaceAndOuter(clazz).substring(2);
@@ -65,6 +74,14 @@
+ "</manifest>\n"
+ "\n";
+ public static String XML_FILE_WITH_STRING_REFERENCE =
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ + "<paths>\n"
+ + " <files-path\n"
+ + " name=\"@string/%s\"\n"
+ + " path=\"let/it/be\" />\n"
+ + "</paths>";
+
public static class AndroidTestRClass {
// The original aapt2 generated R.java class
private final Path javaFilePath;
@@ -103,10 +120,97 @@
}
}
+ // Easy traversable resource table.
+ public static class TestResourceTable {
+ private Map<String, ResourceNameToValueMapping> mapping = new HashMap<>();
+
+ private TestResourceTable(ResourceTable resourceTable) {
+ // For now, we don't have any test that use multiple packages.
+ assert resourceTable.getPackageCount() == 1;
+ for (Resources.Type type : resourceTable.getPackage(0).getTypeList()) {
+ String typeName = type.getName();
+ mapping.put(typeName, new ResourceNameToValueMapping(type));
+ }
+ }
+
+ public static TestResourceTable parseFrom(byte[] bytes) throws InvalidProtocolBufferException {
+ return new TestResourceTable(ResourceTable.parseFrom(bytes));
+ }
+
+ public boolean containsValueFor(String type, String name) {
+ return mapping.containsKey(type) && mapping.get(type).containsValueFor(name);
+ }
+
+ public static class ResourceNameToValueMapping {
+ private final Map<String, List<ResourceValue>> mapping = new HashMap<>();
+
+ public ResourceNameToValueMapping(Resources.Type type) {
+ for (Resources.Entry entry : type.getEntryList()) {
+ String name = entry.getName();
+ List<ResourceValue> entries = new ArrayList<>();
+ for (ConfigValue configValue : entry.getConfigValueList()) {
+ Item item = configValue.getValue().getItem();
+ // Currently supporting files and strings, we just flatten this to strings for easy
+ // testing.
+ if (item.hasFile()) {
+ entries.add(
+ new ResourceValue(item.getFile().getPath(), configValue.getConfig().toString()));
+ } else if (item.hasStr()) {
+ entries.add(
+ new ResourceValue(item.getStr().getValue(), configValue.getConfig().toString()));
+ }
+ mapping.put(name, entries);
+ }
+ }
+ }
+
+ public boolean containsValueFor(String name) {
+ return mapping.containsKey(name);
+ }
+
+ public static class ResourceValue {
+
+ private final String value;
+ private final String config;
+
+ public ResourceValue(String value, String config) {
+ this.value = value;
+ this.config = config;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String getConfig() {
+ return config;
+ }
+ }
+ }
+ }
+
+ public static class ResourceTableInspector {
+
+ private final TestResourceTable testResourceTable;
+
+ public ResourceTableInspector(byte[] bytes) throws InvalidProtocolBufferException {
+ testResourceTable = TestResourceTable.parseFrom(bytes);
+ }
+
+ public void assertContainsResourceWithName(String type, String name) {
+ Assert.assertTrue(testResourceTable.containsValueFor(type, name));
+ }
+
+ public void assertDoesNotContainResourceWithName(String type, String name) {
+ Assert.assertFalse(testResourceTable.containsValueFor(type, name));
+ }
+ }
+
public static class AndroidTestResourceBuilder {
private String manifest;
private final Map<String, String> stringValues = new TreeMap<>();
private final Map<String, byte[]> drawables = new TreeMap<>();
+ private final Map<String, String> xmlFiles = new TreeMap<>();
private final List<Class<?>> classesToRemap = new ArrayList<>();
// Create the android resources from the passed in R classes
@@ -136,6 +240,12 @@
return this;
}
+ AndroidTestResourceBuilder addXmlWithStringReference(
+ String xmlName, String nameOfReferencedString) {
+ xmlFiles.put(xmlName, String.format(XML_FILE_WITH_STRING_REFERENCE, nameOfReferencedString));
+ return this;
+ }
+
AndroidTestResourceBuilder withSimpleManifestAndAppNameString() {
this.manifest = SIMPLE_MANIFEST_WITH_APP_NAME;
addStringValue("app_name", "Most important app ever.");
@@ -160,13 +270,19 @@
FileUtils.writeTextFile(
temp.newFolder("res", "values").toPath().resolve("strings.xml"),
createStringResourceXml());
+
}
if (drawables.size() > 0) {
+ File drawableFolder = temp.newFolder("res", "drawable");
for (Entry<String, byte[]> entry : drawables.entrySet()) {
FileUtils.writeToFile(
- temp.newFolder("res", "drawable").toPath().resolve(entry.getKey()),
- null,
- entry.getValue());
+ drawableFolder.toPath().resolve(entry.getKey()), null, entry.getValue());
+ }
+ }
+ if (xmlFiles.size() > 0) {
+ File xmlFolder = temp.newFolder("res", "xml");
+ for (Entry<String, String> entry : xmlFiles.entrySet()) {
+ FileUtils.writeTextFile(xmlFolder.toPath().resolve(entry.getKey()), entry.getValue());
}
}
@@ -189,7 +305,7 @@
ZipUtils.iter(
rClassClassFileOutput,
(entry, input) -> {
- if (ZipUtils.isClassFile(entry.getName())) {
+ if (ZipUtils.isClassFile(entry.getName()) && !entry.getName().endsWith("R.class")) {
rewrittenRClassFiles.add(
transformer(StreamUtils.streamToByteArrayClose(input), null)
.addClassTransformer(
@@ -215,6 +331,23 @@
superName,
interfaces);
}
+
+ @Override
+ public void visitNestHost(String nestHost) {
+ // Don't make nest host relationsships
+ }
+
+ @Override
+ public void visitOuterClass(
+ String owner, String name, String descriptor) {
+ // Don't make the inner<>outer class connection
+ }
+
+ @Override
+ public void visitInnerClass(
+ String name, String outerName, String innerName, int access) {
+ // Don't make the inner<>outer class connection
+ }
})
.transform());
}
diff --git a/src/test/java/com/android/tools/r8/androidresources/AndroidResourcesPassthroughTest.java b/src/test/java/com/android/tools/r8/androidresources/AndroidResourcesPassthroughTest.java
deleted file mode 100644
index 41754aa..0000000
--- a/src/test/java/com/android/tools/r8/androidresources/AndroidResourcesPassthroughTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-package com.android.tools.r8.androidresources;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertThat;
-
-import com.android.tools.r8.ArchiveProtoAndroidResourceConsumer;
-import com.android.tools.r8.ArchiveProtoAndroidResourceProvider;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource;
-import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResourceBuilder;
-import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.ZipUtils;
-import java.nio.charset.Charset;
-import java.nio.file.Path;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class AndroidResourcesPassthroughTest extends TestBase {
-
- @Parameter(0)
- public TestParameters parameters;
-
- @Parameters(name = "{0}")
- public static TestParametersCollection parameters() {
- return getTestParameters().withDexRuntimes().withAllApiLevels().build();
- }
-
- @Test
- public void testR8() throws Exception {
- String manifestPath = "AndroidManifest.xml";
- String resourcePath = "resources.pb";
- String pngPath = "res/drawable/foo.png";
-
- AndroidTestResource testResource =
- new AndroidTestResourceBuilder()
- .withSimpleManifestAndAppNameString()
- .addDrawable("foo.png", AndroidResourceTestingUtils.TINY_PNG)
- .build(temp);
- Path resources = testResource.getResourceZip();
- Path output = temp.newFile("resources_out.zip").toPath();
- testForR8(parameters.getBackend())
- .addInnerClasses(getClass())
- .setMinApi(parameters)
- .addOptionsModification(
- o -> {
- o.androidResourceProvider =
- new ArchiveProtoAndroidResourceProvider(resources, new PathOrigin(resources));
- o.androidResourceConsumer = new ArchiveProtoAndroidResourceConsumer(output);
- })
- .addKeepMainRule(FooBar.class)
- .run(parameters.getRuntime(), FooBar.class)
- .assertSuccessWithOutputLines("Hello World");
- assertArrayEquals(
- ZipUtils.readSingleEntry(output, manifestPath),
- ZipUtils.readSingleEntry(resources, manifestPath));
- assertArrayEquals(
- ZipUtils.readSingleEntry(output, resourcePath),
- ZipUtils.readSingleEntry(resources, resourcePath));
- assertArrayEquals(
- ZipUtils.readSingleEntry(output, pngPath), ZipUtils.readSingleEntry(resources, pngPath));
- String rClassContent =
- FileUtils.readTextFile(
- testResource.getRClass().getJavaFilePath(), Charset.defaultCharset());
- assertThat(rClassContent, containsString("app_name"));
- assertThat(rClassContent, containsString("foo"));
- }
-
- public static class FooBar {
-
- public static void main(String[] args) {
- System.out.println("Hello World");
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/androidresources/SimpleNoCodeReferenceAndroidResourceTest.java b/src/test/java/com/android/tools/r8/androidresources/SimpleNoCodeReferenceAndroidResourceTest.java
new file mode 100644
index 0000000..34b2b9a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/androidresources/SimpleNoCodeReferenceAndroidResourceTest.java
@@ -0,0 +1,106 @@
+// 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.
+package com.android.tools.r8.androidresources;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResourceBuilder;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.ResourceTableInspector;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.ZipUtils;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SimpleNoCodeReferenceAndroidResourceTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection parameters() {
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ String manifestPath = "AndroidManifest.xml";
+ String resourcePath = "resources.pb";
+ String pngPath = "res/drawable/foo.png";
+
+ AndroidTestResource testResource =
+ new AndroidTestResourceBuilder()
+ .withSimpleManifestAndAppNameString()
+ .addDrawable("foo.png", AndroidResourceTestingUtils.TINY_PNG)
+ .addDrawable("bar.png", AndroidResourceTestingUtils.TINY_PNG)
+ .build(temp);
+ Path resources = testResource.getResourceZip();
+ Path output = temp.newFile("resources_out.zip").toPath();
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .setMinApi(parameters)
+ .addAndroidResources(testResource, output)
+ .addKeepMainRule(FooBar.class)
+ .compile()
+ .inspectShrunkenResources(
+ shrunkenInspector -> {
+ // Reachable from the manifest
+ shrunkenInspector.assertContainsResourceWithName("string", "app_name");
+ // Not reachable from anything
+ shrunkenInspector.assertDoesNotContainResourceWithName("drawable", "foo");
+ shrunkenInspector.assertDoesNotContainResourceWithName("drawable", "bar");
+ try {
+ assertFalse(ZipUtils.containsEntry(output, pngPath));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .run(parameters.getRuntime(), FooBar.class)
+ .assertSuccessWithOutputLines("Hello World");
+ // We don't touch the manifest
+ assertArrayEquals(
+ ZipUtils.readSingleEntry(output, manifestPath),
+ ZipUtils.readSingleEntry(resources, manifestPath));
+
+ String rClassContent =
+ FileUtils.readTextFile(
+ testResource.getRClass().getJavaFilePath(), Charset.defaultCharset());
+ assertFalse(
+ Arrays.equals(
+ ZipUtils.readSingleEntry(output, resourcePath),
+ ZipUtils.readSingleEntry(resources, resourcePath)));
+ assertThat(rClassContent, containsString("app_name"));
+ assertThat(rClassContent, containsString("foo"));
+ assertThat(rClassContent, containsString("bar"));
+ assertTrue(ZipUtils.containsEntry(resources, pngPath));
+ ResourceTableInspector resourceTableInspector =
+ new ResourceTableInspector(
+ ZipUtils.readSingleEntry(testResource.getResourceZip(), resourcePath));
+ resourceTableInspector.assertContainsResourceWithName("string", "app_name");
+ resourceTableInspector.assertContainsResourceWithName("drawable", "foo");
+ resourceTableInspector.assertContainsResourceWithName("drawable", "bar");
+ }
+
+ public static class FooBar {
+
+ public static void main(String[] args) {
+ System.out.println("Hello World");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/androidresources/TestShrinkingWithCodeReferences.java b/src/test/java/com/android/tools/r8/androidresources/TestShrinkingWithCodeReferences.java
new file mode 100644
index 0000000..00b000f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/androidresources/TestShrinkingWithCodeReferences.java
@@ -0,0 +1,84 @@
+// 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.
+package com.android.tools.r8.androidresources;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResourceBuilder;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TestShrinkingWithCodeReferences extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection parameters() {
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ }
+
+ public static AndroidTestResource getTestResources(TemporaryFolder temp) throws Exception {
+ return new AndroidTestResourceBuilder()
+ .withSimpleManifestAndAppNameString()
+ .addRClassInitializeWithDefaultValues(R.string.class, R.drawable.class)
+ .build(temp);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addProgramClasses(FooBar.class)
+ .addAndroidResources(getTestResources(temp))
+ .addKeepMainRule(FooBar.class)
+ .compile()
+ .inspectShrunkenResources(
+ resourceTableInspector -> {
+ resourceTableInspector.assertContainsResourceWithName("string", "bar");
+ resourceTableInspector.assertContainsResourceWithName("string", "foo");
+ resourceTableInspector.assertContainsResourceWithName("drawable", "foobar");
+ resourceTableInspector.assertDoesNotContainResourceWithName(
+ "string", "unused_string");
+ resourceTableInspector.assertDoesNotContainResourceWithName(
+ "drawable", "unused_drawable");
+ })
+ .run(parameters.getRuntime(), FooBar.class)
+ .assertSuccess();
+ }
+
+ public static class FooBar {
+
+ public static void main(String[] args) {
+ if (System.currentTimeMillis() == 0) {
+ System.out.println(R.drawable.foobar);
+ System.out.println(R.string.bar);
+ System.out.println(R.string.foo);
+ }
+ }
+ }
+
+ public static class R {
+
+ public static class string {
+
+ public static int bar;
+ public static int foo;
+ public static int unused_string;
+ }
+
+ public static class drawable {
+
+ public static int foobar;
+ public static int unused_drawable;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/androidresources/XmlFilesWithReferences.java b/src/test/java/com/android/tools/r8/androidresources/XmlFilesWithReferences.java
new file mode 100644
index 0000000..fb43ba7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/androidresources/XmlFilesWithReferences.java
@@ -0,0 +1,80 @@
+// 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.
+package com.android.tools.r8.androidresources;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResourceBuilder;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class XmlFilesWithReferences extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection parameters() {
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ }
+
+ public static AndroidTestResource getTestResources(TemporaryFolder temp) throws Exception {
+ return new AndroidTestResourceBuilder()
+ .withSimpleManifestAndAppNameString()
+ .addRClassInitializeWithDefaultValues(R.string.class, R.xml.class)
+ .addXmlWithStringReference("foo_with_reference", "referenced_from_xml")
+ .build(temp);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addProgramClasses(FooBar.class)
+ .addAndroidResources(getTestResources(temp))
+ .addKeepMainRule(FooBar.class)
+ .compile()
+ .inspectShrunkenResources(
+ resourceTableInspector -> {
+ resourceTableInspector.assertContainsResourceWithName(
+ "string", "referenced_from_xml");
+ resourceTableInspector.assertContainsResourceWithName("xml", "foo_with_reference");
+
+ resourceTableInspector.assertDoesNotContainResourceWithName(
+ "string", "unused_string");
+ })
+ .run(parameters.getRuntime(), FooBar.class)
+ .assertSuccess();
+ }
+
+ public static class FooBar {
+
+ public static void main(String[] args) {
+ if (System.currentTimeMillis() == 0) {
+ // Reference only the xml
+ System.out.println(R.xml.foo_with_reference);
+ }
+ }
+ }
+
+ public static class R {
+
+ public static class string {
+
+ public static int unused_string;
+ public static int referenced_from_xml;
+ }
+
+ public static class xml {
+ public static int foo_with_reference;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/ClassFileVersion66Test.java b/src/test/java/com/android/tools/r8/cf/ClassFileVersion66Test.java
index d97f14c..aabbf04 100644
--- a/src/test/java/com/android/tools/r8/cf/ClassFileVersion66Test.java
+++ b/src/test/java/com/android/tools/r8/cf/ClassFileVersion66Test.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.cf;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -34,8 +33,7 @@
this.parameters = parameters;
}
- // TODO(b/301189814): Update ASM once it has a release with v22 support.
- @Test(expected = CompilationFailedException.class)
+ @Test
public void test() throws Exception {
testForD8(parameters.getBackend())
.addProgramClassFileData(transformer(TestClass.class).setVersion(CfVersion.V22).transform())
diff --git a/src/test/java/com/android/tools/r8/cf/frames/InitBeforeNewInInstructionStreamTest.java b/src/test/java/com/android/tools/r8/cf/frames/InitBeforeNewInInstructionStreamTest.java
index 1d93a7a..c0808d2 100644
--- a/src/test/java/com/android/tools/r8/cf/frames/InitBeforeNewInInstructionStreamTest.java
+++ b/src/test/java/com/android/tools/r8/cf/frames/InitBeforeNewInInstructionStreamTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.frames;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -41,7 +41,7 @@
public void testJvm() throws Exception {
parameters.assumeJvmTestParameters();
testForJvm(parameters)
- .addProgramClassFileData(patchedDump())
+ .addProgramClassFileData(dump())
.run(parameters.getRuntime(), MAIN_CLASS)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
@@ -50,7 +50,7 @@
public void testD8() throws Exception {
parameters.assumeDexRuntime();
testForD8(parameters.getBackend())
- .addProgramClassFileData(patchedDump())
+ .addProgramClassFileData(dump())
.setMinApi(parameters)
.run(parameters.getRuntime(), MAIN_CLASS)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
@@ -60,21 +60,16 @@
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
testForR8(parameters.getBackend())
- .addProgramClassFileData(patchedDump())
+ .addProgramClassFileData(dump())
.addKeepMainRule(MAIN_CLASS)
.setMinApi(parameters)
.run(parameters.getRuntime(), MAIN_CLASS)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
- // This is reproducing b/b274337639, where a new instruction is before the corresponding
- // invokespecial of <init> in the instruction stream. The code is correct as control flow ensures
- // new is called before init, and the stack map encodes this.
- //
- // Writing this code with ASM did not generate the correct stack map, so using javassist to patch
- // it up.
-
- public static byte[] patchedDump() throws Exception {
+ @Test
+ public void checkDump() throws Exception {
+ parameters.assumeJvmTestParameters();
ClassPool classPool = new ClassPool();
classPool.insertClassPath(new ByteArrayClassPath(MAIN_CLASS, dump()));
CtClass clazz = classPool.get(MAIN_CLASS);
@@ -85,24 +80,19 @@
byte[] stackMapTable = stackMapTableAttribute.get();
// Uninitialized has type 8 in the stack map. See
// https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-4.html#jvms-4.7.4.
- // The instruction index 0 generated by ASM is not correct, patch to index 12.
- if (stackMapTable[15] == 8
- && stackMapTable[16] == 0
- && stackMapTable[17] == 0
- && stackMapTable[18] == 8
- && stackMapTable[19] == 0
- && stackMapTable[20] == 0) {
- stackMapTable[17] = 12;
- stackMapTable[20] = 12;
- } else {
- // If an ASM update fails here maybe the stack map is generated correctly and the javassist
- // patching can be removed.
- fail("Unexpected class file*");
- }
- stackMapTableAttribute.set(stackMapTable);
- return clazz.toBytecode();
+ // Keep to validate https://gitlab.ow2.org/asm/asm/-/issues/317995 is fixed.
+ assertTrue(
+ stackMapTable[15] == 8
+ && stackMapTable[16] == 0
+ && stackMapTable[17] == 12
+ && stackMapTable[18] == 8
+ && stackMapTable[19] == 0
+ && stackMapTable[20] == 12);
}
+ // This is reproducing b/274337639, where a new instruction is before the corresponding
+ // invokespecial of <init> in the instruction stream. The code is correct as control flow ensures
+ // new is called before init, and the stack map encodes this.
public static byte[] dump() throws Exception {
ClassWriter classWriter = new ClassWriter(0);
diff --git a/third_party/dependencies.tar.gz.sha1 b/third_party/dependencies.tar.gz.sha1
index 8d3ba4e..c41f552 100644
--- a/third_party/dependencies.tar.gz.sha1
+++ b/third_party/dependencies.tar.gz.sha1
@@ -1 +1 @@
-a8ce32b32965771099a4e91fedf13abfda7ffbed
+0276892a18f142c7399e09f5dada5e5f98857114
\ No newline at end of file
diff --git a/third_party/dependencies_new.tar.gz.sha1 b/third_party/dependencies_new.tar.gz.sha1
deleted file mode 100644
index 01f988b..0000000
--- a/third_party/dependencies_new.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d5238791ca8a92b1ea3dcd91b013ef41e1b5ca38
diff --git a/third_party/dependencies_plugin.tar.gz.sha1 b/third_party/dependencies_plugin.tar.gz.sha1
index 08fb793..73510da 100644
--- a/third_party/dependencies_plugin.tar.gz.sha1
+++ b/third_party/dependencies_plugin.tar.gz.sha1
@@ -1 +1 @@
-77f5f4042c4340df908bb39cdb40a67009195cac
\ No newline at end of file
+577ea397b7e8db5975176c059ce1c5e82e2ea085
\ No newline at end of file
diff --git a/tools/asmifier.py b/tools/asmifier.py
index 9af1499..f599876 100755
--- a/tools/asmifier.py
+++ b/tools/asmifier.py
@@ -10,7 +10,7 @@
import sys
import utils
-ASM_VERSION = '9.5'
+ASM_VERSION = '9.6'
ASM_JAR = os.path.join(utils.DEPENDENCIES_DIR, 'org', 'ow2', 'asm', 'asm',
ASM_VERSION, 'asm-' + ASM_VERSION + '.jar')
ASM_UTIL_JAR = os.path.join(utils.DEPENDENCIES_DIR, 'org', 'ow2', 'asm',
diff --git a/tools/create_local_maven_with_dependencies.py b/tools/create_local_maven_with_dependencies.py
index e5d8885..fd06fa4 100755
--- a/tools/create_local_maven_with_dependencies.py
+++ b/tools/create_local_maven_with_dependencies.py
@@ -21,13 +21,12 @@
]
ANDRDID_SUPPORT_VERSION = '25.4.0'
-ASM_VERSION = '9.5'
+ASM_VERSION = '9.6' # When updating update tools/asmifier.py and Toolhelper as well.
ESPRESSO_VERSION = '3.0.0'
FASTUTIL_VERSION = '7.2.1'
KOTLIN_METADATA_VERSION = '0.7.0'
-KOTLIN_VERSION = '1.8.0'
-GUAVA_VERSION = '31.1-jre'
-GUAVA_VERSION_NEW = '32.1.2-jre'
+KOTLIN_VERSION = '1.9.0'
+GUAVA_VERSION = '32.1.2-jre'
GSON_VERSION = '2.10.1'
JAVASSIST_VERSION = '3.29.2-GA'
JUNIT_VERSION = '4.13-beta-2'
@@ -39,17 +38,51 @@
# Resource shrinker dependency versions
AAPT2_PROTO_VERSION = '8.2.0-alpha10-10154469'
PROTOBUF_VERSION = '3.19.3'
-STUDIO_SDK_VERSION = '31.2.0-alpha10'
+STUDIO_SDK_VERSION = '31.2.0-rc01'
BUILD_DEPENDENCIES = [
'com.google.code.gson:gson:{version}'.format(version=GSON_VERSION),
'com.google.guava:guava:{version}'.format(version=GUAVA_VERSION),
'it.unimi.dsi:fastutil:{version}'.format(version=FASTUTIL_VERSION),
- 'org.jetbrains.kotlinx:kotlinx-metadata-jvm:{version}'.format(
- version=KOTLIN_METADATA_VERSION),
+
'org.ow2.asm:asm:{version}'.format(version=ASM_VERSION),
'org.ow2.asm:asm-util:{version}'.format(version=ASM_VERSION),
'org.ow2.asm:asm-commons:{version}'.format(version=ASM_VERSION),
+
+ 'com.google.errorprone:javac:9+181-r4173-1',
+
+ 'com.android.tools.build:aapt2-proto:{version}'.format(
+ version=AAPT2_PROTO_VERSION),
+ 'com.android.tools.layoutlib:layoutlib-api:{version}'.format(
+ version=STUDIO_SDK_VERSION),
+ 'com.android.tools:common:{version}'.format(version=STUDIO_SDK_VERSION),
+ 'com.android.tools:sdk-common:{version}'.format(version=STUDIO_SDK_VERSION),
+ 'com.google.protobuf:protobuf-java:{version}'.format(
+ version=PROTOBUF_VERSION),
+
+ 'org.jetbrains.kotlin:kotlin-assignment-compiler-plugin-embeddable:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-compiler-embeddable:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-gradle-plugin-api:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-gradle-plugin-idea:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-reflect:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin-embeddable:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-script-runtime:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlin:kotlin-tooling-core:{version}'.format(
+ version=KOTLIN_VERSION),
+ 'org.jetbrains.kotlinx:kotlinx-metadata-jvm:{version}'.format(
+ version=KOTLIN_METADATA_VERSION),
+ 'org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:4.1.3',
]
TEST_DEPENDENCIES = [
@@ -60,44 +93,17 @@
'com.google.errorprone:error_prone_core:{version}'.format(
version=ERROR_PRONE_VERSION),
'org.javassist:javassist:{version}'.format(version=JAVASSIST_VERSION),
- 'org.jetbrains.kotlin:kotlin-stdlib:{version}'.format(
- version=KOTLIN_VERSION),
- 'org.jetbrains.kotlin:kotlin-reflect:{version}'.format(
- version=KOTLIN_VERSION),
'org.mockito:mockito-core:{version}'.format(version=MOCKITO_VERSION),
'org.testng:testng:{version}'.format(version=TESTNG_VERSION),
]
-NEW_DEPENDENCIES = [
- 'com.google.guava:guava:{version}'.format(version=GUAVA_VERSION_NEW),
- 'org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:4.0.6',
- 'org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.8.10',
- 'org.jetbrains.kotlin:kotlin-gradle-plugin-idea:1.8.10',
- 'org.jetbrains.kotlin:kotlin-reflect:1.6.10',
- 'org.jetbrains.kotlin:kotlin-reflect:1.8.10',
- 'org.jetbrains.kotlin:kotlin-script-runtime:1.8.10',
- 'org.jetbrains.kotlin:kotlin-tooling-core:1.8.10',
- 'net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:3.0.1',
- 'com.google.errorprone:javac:9+181-r4173-1',
- # Gradle 8.3
- 'org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:4.1.0',
- 'org.jetbrains.kotlin:kotlin-assignment-compiler-plugin-embeddable:1.9.0',
- 'org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.9.0',
- 'org.jetbrains.kotlin:kotlin-reflect:1.9.0',
- 'org.jetbrains.kotlin:kotlin-script-runtime:1.9.0',
- 'org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin-embeddable:1.9.0',
- # Resource shrinker
- 'com.android.tools.build:aapt2-proto:{version}'.format(
- version=AAPT2_PROTO_VERSION),
- 'com.android.tools.layoutlib:layoutlib-api:{version}'.format(
- version=STUDIO_SDK_VERSION),
- 'com.android.tools:common:{version}'.format(version=STUDIO_SDK_VERSION),
- 'com.android.tools:sdk-common:{version}'.format(version=STUDIO_SDK_VERSION),
- 'com.google.protobuf:protobuf-java:{version}'.format(
- version=PROTOBUF_VERSION),
-]
-
PLUGIN_DEPENDENCIES = [
+ 'org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:4.1.0',
+ 'org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.9.10',
+ 'net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:3.0.1',
+
+ # Patched version of org.spdx.sbom:org.spdx.sbom.gradle.plugin:0.2.0.
+ # See commit message for a13217f333cc65fb602502ac446698dd74d10b7f.
'org.spdx.sbom:org.spdx.sbom.gradle.plugin:0.2.0-r8-patch01',
# See https://github.com/FasterXML/jackson-core/issues/999.
'ch.randelshofer:fastdoubleparser:0.8.0',
@@ -204,13 +210,6 @@
args, dependencies_path, repositories, BUILD_DEPENDENCIES + TEST_DEPENDENCIES)
set_utime(dependencies_path)
dependencies.append('dependencies')
- dependencies_new_path = os.path.join(utils.THIRD_PARTY, 'dependencies_new')
- remove_local_maven_repository(dependencies_new_path)
- print("Downloading to " + dependencies_new_path)
- create_local_maven_repository(
- args, dependencies_new_path, repositories, NEW_DEPENDENCIES)
- set_utime(dependencies_new_path)
- dependencies.append('dependencies_new')
upload_cmds = []
for dependency in dependencies:
diff --git a/tools/update_prebuilds_in_android.py b/tools/update_prebuilds_in_android.py
index 31ee23e..623bacd 100755
--- a/tools/update_prebuilds_in_android.py
+++ b/tools/update_prebuilds_in_android.py
@@ -16,7 +16,8 @@
'lib': [(utils.R8LIB, 'r8'),],
}
-OTHER_TARGETS = ["LICENSE"]
+OTHER_TARGETS = ['LICENSE']
+SBOM_TARGETS = ['r8.spdx.json']
KEEPANNO_JAR = 'keepanno-annotations.jar'
@@ -65,7 +66,7 @@
print('Copying: ' + src + '.map -> ' + dest + '.map')
copyfile(src + '.map', dest + '.map')
else:
- print('WARNING: Not copying ' + src + ' -> ' + dest + ', as' +
+ print('WARNING: Not copying ' + src + ' -> ' + dest + ', as ' +
dest + ' does not exist already')
@@ -75,8 +76,8 @@
copy_targets(root, target_root, srcs, dests, maps=maps)
-def copy_other_targets(root, target_root):
- copy_targets(root, target_root, OTHER_TARGETS, OTHER_TARGETS)
+def copy_other_targets(root, target_root, other_targets):
+ copy_targets(root, target_root, other_targets, other_targets)
def download_hash(root, commit_hash, target, quiet=False):
@@ -96,9 +97,16 @@
def main_download(hash, maps, targets, target_root, version, keepanno=False):
+ sbom_targets = []
+ if version:
+ semver = utils.check_basic_semver_version(version, allowPrerelease=True)
+ # Generation of SBOM started from version 8.3.13-dev.
+ if semver.larger_than(utils.SemanticVersion(8, 3, 12, 'dev')):
+ sbom_targets = SBOM_TARGETS
+
jar_targets = JAR_TARGETS_MAP[targets]
final_targets = list(map(
- (lambda t: t[0] + '.jar'), jar_targets)) + OTHER_TARGETS
+ (lambda t: t[0] + '.jar'), jar_targets)) + OTHER_TARGETS + sbom_targets
with utils.TempDir() as root:
for target in final_targets:
if hash:
@@ -110,12 +118,12 @@
else:
assert version
download_version(root, version, target)
- if maps and target not in OTHER_TARGETS:
+ if maps and target not in (OTHER_TARGETS + sbom_targets):
download_version(root, version, target + '.map')
if keepanno:
download_version(root, version, KEEPANNO_JAR)
copy_jar_targets(root, target_root, jar_targets, maps)
- copy_other_targets(root, target_root)
+ copy_other_targets(root, target_root, OTHER_TARGETS + sbom_targets)
if keepanno:
copy_targets(root, target_root, [KEEPANNO_JAR], [KEEPANNO_JAR])
@@ -129,7 +137,7 @@
gradle_args.append('-Dorg.gradle.jvmargs=-Xmx' + max_memory_size)
gradle.RunGradle(gradle_args)
copy_jar_targets(utils.LIBS, target_root, jar_targets, maps)
- copy_other_targets(utils.GENERATED_LICENSE_DIR, target_root)
+ copy_other_targets(utils.GENERATED_LICENSE_DIR, target_root, OTHER_TARGETS)
def main(args):
diff --git a/tools/utils.py b/tools/utils.py
index db9844e..06fc3a7 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -720,8 +720,6 @@
# Build metadata currently not suppported
def larger_than(self, other):
- if self.prerelease or other.prerelease:
- raise Exception("Comparison with prerelease not implemented")
if self.major > other.major:
return True
if self.major == other.major and self.minor > other.minor:
@@ -729,6 +727,12 @@
if self.patch:
return (self.major == other.major and self.minor == other.minor and
self.patch > other.patch)
+ if self.prerelease:
+ if other.prerelease:
+ return self.prerelease > other.prerelease
+ else:
+ return False
+
else:
return False