diff --git a/src/tools/android/java/com/android/tools/r8/CompatDxSupport.java b/src/tools/android/java/com/android/tools/r8/CompatDxSupport.java index 31141b313f7dd2..e6a305b2a01c6e 100644 --- a/src/tools/android/java/com/android/tools/r8/CompatDxSupport.java +++ b/src/tools/android/java/com/android/tools/r8/CompatDxSupport.java @@ -13,8 +13,6 @@ // limitations under the License. package com.android.tools.r8; -import com.android.tools.r8.utils.AndroidApp; -import com.android.tools.r8.utils.InternalOptions; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -25,30 +23,74 @@ public class CompatDxSupport { public static void run(D8Command command, boolean minimalMainDex) throws CompilationFailedException { - AndroidApp app = command.getInputApp(); - InternalOptions options = command.getInternalOptions(); - // DX allows --multi-dex without specifying a main dex list for legacy devices. - // That is broken, but for CompatDX we do the same to not break existing builds - // that are trying to transition. + try { + // bazel can point to both an full r8.jar and to the shrunken r8.jar (r8lib.jar), as the + // r8.jar is currently referenced from the Android SDK build-tools, where different versions + // have either full or shrunken jar. From build-tools version 30.0.1 the shrunken jar is + // shipped. If the full jar is used some additional internal APIs are used for additional + // configuration of "check main dex" and "minimal main dex" flags which are not + // supported in the public D8 API. + Class androidAppClass = Class.forName("com.android.tools.r8.utils.AndroidApp"); + Class internalOptionsClass = Class.forName("com.android.tools.r8.utils.InternalOptions"); + runOnFullJar(command, minimalMainDex, androidAppClass, internalOptionsClass); + } catch (ClassNotFoundException e) { + D8.run(command); + } + } + + public static void runOnFullJar( + D8Command command, + boolean minimalMainDex, + Class androidAppClass, + Class internalOptionsClass) { + Method getInputAppMethod; + Method getInternalOptionsMethod; + Method runForTestingMethod; + try { + getInputAppMethod = BaseCommand.class.getDeclaredMethod("getInputApp"); + getInternalOptionsMethod = D8Command.class.getDeclaredMethod("getInternalOptions"); + runForTestingMethod = + D8.class.getDeclaredMethod("runForTesting", androidAppClass, internalOptionsClass); + } catch (NoSuchMethodException e) { + throw new AssertionError("Unsupported r8.jar", e); + } + try { // Use reflection for: - // options.enableMainDexListCheck = false; - // as bazel might link to an old r8.jar which does not have this field. - Field enableMainDexListCheck = options.getClass().getField("enableMainDexListCheck"); + // AndroidApp app = command.getInputApp(); + // InternalOptions options = command.getInternalOptions(); + // as bazel might link to a shrunken r8.jar which does not have these APIs. + Object app = getInputAppMethod.invoke(command); + Object options = getInternalOptionsMethod.invoke(command); + // DX allows --multi-dex without specifying a main dex list for legacy devices. + // That is broken, but for CompatDX we do the same to not break existing builds + // that are trying to transition. try { - enableMainDexListCheck.setBoolean(options, false); - } catch (IllegalAccessException e) { - throw new AssertionError(e); + Field enableMainDexListCheckField = internalOptionsClass.getField("enableMainDexListCheck"); + // DX has a minimal main dex flag. In compat mode only do minimal main dex + // if the flag is actually set. + Field minimalMainDexField = internalOptionsClass.getField("minimalMainDex"); + try { + // Use reflection for: + // options.enableMainDexListCheck = false; + // as bazel might link to an old r8.jar which does not have this field. + enableMainDexListCheckField.setBoolean(options, false); + // Use reflection for: + // options.minimalMainDex = minimalMainDex; + // as bazel might link to an old r8.jar which does not have this field. + minimalMainDexField.setBoolean(options, minimalMainDex); + } catch (IllegalAccessException e) { + throw new AssertionError("Unsupported r8.jar", e); + } + } catch (NoSuchFieldException e) { + // Ignore if bazel is linking to an old r8.jar. } - } catch (NoSuchFieldException e) { - // Ignore if bazel is linking to an old r8.jar. - } - - // DX has a minimal main dex flag. In compat mode only do minimal main dex - // if the flag is actually set. - options.minimalMainDex = minimalMainDex; - D8.runForTesting(app, options); + runForTestingMethod.invoke(null, app, options); + } catch (ReflectiveOperationException e) { + // This is an unsupported r8.jar. + throw new AssertionError("Unsupported r8.jar", e); + } } public static void enableDesugarBackportStatics(D8Command.Builder builder) { @@ -61,7 +103,7 @@ public static void enableDesugarBackportStatics(D8Command.Builder builder) { try { enableDesugarBackportStatics.invoke(builder); } catch (ReflectiveOperationException e) { - throw new AssertionError(e); + throw new AssertionError("Unsupported r8.jar", e); } } catch (NoSuchMethodException e) { // Ignore if bazel is linking to an old r8.jar. diff --git a/src/tools/android/java/com/google/devtools/build/android/r8/CompatDx.java b/src/tools/android/java/com/google/devtools/build/android/r8/CompatDx.java index 3adec8f9f79deb..7f0ad8f4bf0517 100644 --- a/src/tools/android/java/com/google/devtools/build/android/r8/CompatDx.java +++ b/src/tools/android/java/com/google/devtools/build/android/r8/CompatDx.java @@ -27,8 +27,6 @@ import com.android.tools.r8.DiagnosticsHandler; import com.android.tools.r8.ProgramConsumer; import com.android.tools.r8.Version; -import com.android.tools.r8.errors.CompilationError; -import com.android.tools.r8.errors.Unimplemented; import com.android.tools.r8.origin.Origin; import com.android.tools.r8.origin.PathOrigin; import com.android.tools.r8.utils.ArchiveResourceProvider; @@ -523,11 +521,11 @@ private static void run(String[] args) } if (dexArgs.verboseDump) { - throw new Unimplemented("verbose dump file not yet supported"); + throw new CompatDxUnimplemented("verbose dump file not yet supported"); } if (dexArgs.methodToDump != null) { - throw new Unimplemented("method-dump not yet supported"); + throw new CompatDxUnimplemented("method-dump not yet supported"); } if (dexArgs.output != null) { @@ -557,7 +555,7 @@ private static void run(String[] args) } if (dexArgs.incremental) { - throw new Unimplemented("incremental merge not supported yet"); + throw new CompatDxUnimplemented("incremental merge not supported yet"); } if (dexArgs.forceJumbo && dexArgs.verbose) { @@ -573,11 +571,11 @@ private static void run(String[] args) } if (dexArgs.optimizeList != null) { - throw new Unimplemented("no support for optimize-method list"); + throw new CompatDxUnimplemented("no support for optimize-method list"); } if (dexArgs.noOptimizeList != null) { - throw new Unimplemented("no support for dont-optimize-method list"); + throw new CompatDxUnimplemented("no support for dont-optimize-method list"); } if (dexArgs.statistics && dexArgs.verbose) { @@ -647,7 +645,7 @@ private static void run(String[] args) setMinimalMainDex.invoke(builder, dexArgs.minimalMainDex); D8.run(builder.build()); } catch (ReflectiveOperationException e) { - // Go through the support support code accessing the internals for the compilation. + // Go through the support code accessing the internals for the compilation. CompatDxSupport.run(builder.build(), dexArgs.minimalMainDex); } } finally { @@ -696,7 +694,7 @@ public SingleDexFileConsumer(DexIndexedConsumer consumer) { public void accept( int fileIndex, ByteDataView data, Set descriptors, DiagnosticsHandler handler) { if (fileIndex > 0) { - throw new CompilationError( + throw new CompatDxCompilationError( "Compilation result could not fit into a single dex file. " + "Reduce the input-program size or run with --multi-dex enabled"); } @@ -870,7 +868,7 @@ private void writeInputClassesToArchive(DiagnosticsHandler handler) throws IOExc private static void processPath(Path path, List files) throws IOException { if (!Files.exists(path)) { - throw new CompilationError("File does not exist: " + path); + throw new CompatDxCompilationError("File does not exist: " + path); } if (Files.isDirectory(path)) { processDirectory(path, files); @@ -881,7 +879,7 @@ private static void processPath(Path path, List files) throws IOException return; } if (FileUtils.isApkFile(path)) { - throw new Unimplemented("apk files not yet supported: " + path); + throw new CompatDxUnimplemented("apk files not yet supported: " + path); } } diff --git a/src/tools/android/java/com/google/devtools/build/android/r8/CompatDxCompilationError.java b/src/tools/android/java/com/google/devtools/build/android/r8/CompatDxCompilationError.java new file mode 100644 index 00000000000000..c7cbbeb3226215 --- /dev/null +++ b/src/tools/android/java/com/google/devtools/build/android/r8/CompatDxCompilationError.java @@ -0,0 +1,24 @@ +// Copyright 2020 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.r8; + +/** Compilation error in CompatDx */ +public class CompatDxCompilationError extends RuntimeException { + + public CompatDxCompilationError() {} + + public CompatDxCompilationError(String message) { + super(message); + } +} diff --git a/src/tools/android/java/com/google/devtools/build/android/r8/CompatDxUnimplemented.java b/src/tools/android/java/com/google/devtools/build/android/r8/CompatDxUnimplemented.java new file mode 100644 index 00000000000000..e03d3269368c6c --- /dev/null +++ b/src/tools/android/java/com/google/devtools/build/android/r8/CompatDxUnimplemented.java @@ -0,0 +1,24 @@ +// Copyright 2020 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.r8; + +/** Unimplemented in CompatDx */ +public class CompatDxUnimplemented extends RuntimeException { + + public CompatDxUnimplemented() {} + + public CompatDxUnimplemented(String message) { + super(message); + } +}