Path working with FileSystem in D8/R8
- Fix super constructor call bug in wrappers.
Bug: 222647019
Change-Id: I7d4bc839a9a668a90d959011c291013db287add5
diff --git a/src/library_desugar/java/android/os/Build.java b/src/library_desugar/java/android/os/Build.java
new file mode 100644
index 0000000..908c94c
--- /dev/null
+++ b/src/library_desugar/java/android/os/Build.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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 android.os;
+
+public class Build {
+ public static class VERSION {
+ public static final int SDK_INT = 0;
+ }
+}
diff --git a/src/library_desugar/java/android/os/StrictMode.java b/src/library_desugar/java/android/os/StrictMode.java
new file mode 100644
index 0000000..5cd5ff1
--- /dev/null
+++ b/src/library_desugar/java/android/os/StrictMode.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2022, 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 android.os;
+
+public class StrictMode {
+
+ public static ThreadPolicy getThreadPolicy() {
+ return null;
+ }
+
+ public static void setThreadPolicy(ThreadPolicy policy) {}
+
+ public static class ThreadPolicy {
+ public static class Builder {
+ public Builder(ThreadPolicy policy) {}
+
+ public Builder permitDiskReads() {
+ return null;
+ }
+
+ public ThreadPolicy build() {
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java b/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java
new file mode 100644
index 0000000..cf36b80
--- /dev/null
+++ b/src/library_desugar/java/desugar/sun/nio/fs/DesugarDefaultFileSystemProvider.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, 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 desugar.sun.nio.fs;
+
+import java.nio.file.spi.FileSystemProvider;
+
+public class DesugarDefaultFileSystemProvider {
+
+ public static FileSystemProvider instance() {
+ return null;
+ }
+}
diff --git a/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java b/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
new file mode 100644
index 0000000..658c351
--- /dev/null
+++ b/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2022, 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 java.adapter;
+
+import android.os.Build.VERSION;
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
+import desugar.sun.nio.fs.DesugarDefaultFileSystemProvider;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.spi.FileSystemProvider;
+
+/**
+ * A hybrid file system provider adapter that delegates different implementations based on the
+ * runtime environment.
+ */
+public final class HybridFileSystemProvider {
+ private static final FileSystemProvider INSTANCE = getFileSystemProvider();
+ private static final FileSystem FILE_SYSTEM_INSTANCE =
+ INSTANCE.getFileSystem(URI.create("file:///"));
+
+ private static FileSystemProvider getFileSystemProvider() {
+ if (VERSION.SDK_INT >= 26) {
+ return FileSystems.getDefault().provider();
+ } else {
+ try {
+ // In headless, android.os is absent so the following line will throw.
+ // We cannot set the ThreadPolicy in headless and it is irrelevant.
+ // If we are not in headless, the class will be found and we can set the thread policy.
+ Class.forName("android.os.Build");
+ setThreadPolicy();
+ } catch (ClassNotFoundException ignored) {
+ // Headless mode.
+ }
+ return DesugarDefaultFileSystemProvider.instance();
+ }
+ }
+
+ private static void setThreadPolicy() {
+ // The references to the android.os methods need to be outlined.
+ // TODO(b/207004118): Fix the strict mode allowlisting.
+ ThreadPolicy threadPolicy = StrictMode.getThreadPolicy();
+ StrictMode.setThreadPolicy(new ThreadPolicy.Builder(threadPolicy).permitDiskReads().build());
+ }
+
+ private HybridFileSystemProvider() {}
+
+ /** Returns the platform's default file system provider. */
+ public static FileSystemProvider instance() {
+ return INSTANCE;
+ }
+
+ /** Returns the platform's default file system. */
+ public static FileSystem theFileSystem() {
+ return FILE_SYSTEM_INSTANCE;
+ }
+}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_path.json b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
index f66d02b..010492e 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_path.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
@@ -53,7 +53,19 @@
},
{
"api_level_below_or_equal": 25,
+ "rewrite_prefix": {
+ "java.io.DesugarFile": "j$.io.DesugarFile",
+ "java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
+ "java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
+ "java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
+ "java.nio.file.": "j$.nio.file."
+ },
+ "retarget_method_with_emulated_dispatch": {
+ "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile"
+ },
"wrapper_conversion": [
+ "java.nio.channels.AsynchronousChannel",
+ "java.nio.channels.CompletionHandler",
"java.nio.file.Path",
"java.nio.file.FileSystem",
"java.nio.file.WatchService",
@@ -78,6 +90,13 @@
"java.nio.file.OpenOption",
"java.nio.file.attribute.BasicFileAttributes"
],
+ "wrapper_conversion_excluding": {
+ "java.nio.channels.AsynchronousFileChannel": [
+ "void java.nio.channels.AsynchronousFileChannel#lock(java.lang.Object, java.nio.channels.CompletionHandler)",
+ "java.util.concurrent.Future java.nio.channels.AsynchronousFileChannel#lock()",
+ "java.nio.channels.FileLock java.nio.channels.AsynchronousFileChannel#tryLock()"
+ ]
+ },
"custom_conversion": {
"java.nio.file.attribute.FileTime": "java.nio.file.attribute.FileAttributeConversions"
}
@@ -93,6 +112,8 @@
"api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader",
+ "java.nio.channels.FileChannel": "j$.nio.channels.FileChannel",
+ "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
"java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
"java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
"java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
@@ -148,6 +169,7 @@
"java.util.Spliterator java.util.LinkedHashSet#spliterator()": "java.util.DesugarLinkedHashSet"
},
"wrapper_conversion": [
+ "java.nio.channels.SeekableByteChannel",
"java.util.function.IntUnaryOperator",
"java.util.function.BiFunction",
"java.util.function.IntConsumer",
@@ -202,6 +224,16 @@
"java.util.Spliterator": [
"boolean java.util.Spliterator#hasCharacteristics(int)",
"long java.util.Spliterator#getExactSizeIfKnown()"
+ ],
+ "java.nio.channels.FileChannel": [
+ "long java.nio.channels.FileChannel#read(java.nio.ByteBuffer[])",
+ "long java.nio.channels.FileChannel#write(java.nio.ByteBuffer[])",
+ "java.nio.channels.FileLock java.nio.channels.FileChannel#lock()",
+ "java.nio.channels.FileLock java.nio.channels.FileChannel#tryLock()",
+ "void java.nio.channels.spi.AbstractInterruptibleChannel#close()",
+ "boolean java.nio.channels.spi.AbstractInterruptibleChannel#isOpen()",
+ "void java.nio.channels.spi.AbstractInterruptibleChannel#begin()",
+ "void java.nio.channels.spi.AbstractInterruptibleChannel#end(boolean)"
]
},
"custom_conversion": {
@@ -293,9 +325,7 @@
{
"api_level_below_or_equal": 25,
"rewrite_prefix": {
- "java.io.DesugarFile": "j$.io.DesugarFile",
"java.nio.channels.Desugar": "j$.nio.channels.Desugar",
- "java.nio.file.": "j$.nio.file.",
"jdk.internal.": "j$.jdk.internal.",
"sun.misc.Desugar": "j$.sun.misc.Desugar",
"sun.nio.cs.": "j$.sun.nio.cs.",
@@ -304,27 +334,16 @@
"sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
"sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
"sun.util.PreHashedMap": "j$.sun.util.PreHashedMap",
- "wrapper." : "j$.wrapper."
+ "java.adapter" : "j$.adapter"
},
"rewrite_derived_prefix": {
"java.nio.file.attribute.FileTime": {
"j$.nio.file.attribute.FileTime": "java.nio.file.attribute.FileTime"
- },
- "java.io.": {
- "__wrapper__.j$.io.": "j$.io.",
- "__wrapper__.java.io.": "java.io."
- },
- "java.nio.": {
- "__wrapper__.j$.nio.": "j$.nio.",
- "__wrapper__.java.nio.": "java.nio."
}
},
"retarget_method": {
"boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)": "java.util.DesugarArrays"
},
- "retarget_method_with_emulated_dispatch": {
- "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile"
- },
"backport": {
"java.lang.DesugarDouble": "java.lang.Double",
"java.lang.DesugarInteger": "java.lang.Integer",
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 888b78b..7bdb3b9 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -986,7 +986,11 @@
internal.setDesugaredLibrarySpecification(desugaredLibrarySpecification);
internal.synthesizedClassPrefix = synthesizedClassPrefix;
// TODO(b/214382176): Enable all the time.
- internal.loadAllClassDefinitions = !synthesizedClassPrefix.isEmpty();
+ boolean l8Shrinking = !synthesizedClassPrefix.isEmpty();
+ internal.loadAllClassDefinitions = l8Shrinking;
+ if (l8Shrinking) {
+ internal.apiModelingOptions().disableSubbingOfClasses();
+ }
internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
// Set up the map and source file providers.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index fa95d25..47f48d4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -520,12 +520,13 @@
.setInterfaces(interfaces)
.setSuperType(superType)
.setInstanceFields(Collections.singletonList(wrapperField))
- .addMethod(methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder));
+ .addMethod(
+ methodBuilder -> buildWrapperConstructor(wrapperField, methodBuilder, superType));
return wrapperField;
}
private void buildWrapperConstructor(
- DexEncodedField wrappedValueField, SyntheticMethodBuilder methodBuilder) {
+ DexEncodedField wrappedValueField, SyntheticMethodBuilder methodBuilder, DexType superType) {
methodBuilder
.setName(factory.constructorMethodName)
.setProto(factory.createProto(factory.voidType, wrappedValueField.getType()))
@@ -536,7 +537,8 @@
.disableAndroidApiLevelCheck()
.setCode(
codeSynthesizor ->
- new APIConverterConstructorCfCodeProvider(appView, wrappedValueField.getReference())
+ new APIConverterConstructorCfCodeProvider(
+ appView, wrappedValueField.getReference(), superType)
.generateCfCode());
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 78fc59f..50a0190 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -102,6 +102,11 @@
}
private void registerClassType(DexType type) {
+ // TODO(b/222647019): To remove, the problem is that the prefix java.nio.channels.FileChannel
+ // matches java.nio.channels.FileChannel$MapMode.
+ if (type.toString().equals("java.nio.channels.FileChannel$MapMode")) {
+ return;
+ }
registerType(type);
registerMaintainType(type);
registerDifferentType(type);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
index 9487210..18147b5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
@@ -12,9 +12,12 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
+import com.android.tools.r8.utils.MethodSignatureEquivalence;
+import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -22,6 +25,7 @@
public class HumanToMachineWrapperConverter {
+ private final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
private final AppInfoWithClassHierarchy appInfo;
private final Set<DexType> missingClasses = Sets.newIdentityHashSet();
@@ -56,6 +60,10 @@
private List<DexMethod> allImplementedMethods(
DexClass wrapperClass, Set<DexMethod> excludedMethods) {
+ HashSet<Wrapper<DexMethod>> wrappers = new HashSet<>();
+ for (DexMethod excludedMethod : excludedMethods) {
+ wrappers.add(equivalence.wrap(excludedMethod));
+ }
LinkedList<DexClass> workList = new LinkedList<>();
List<DexMethod> implementedMethods = new ArrayList<>();
workList.add(wrapperClass);
@@ -64,7 +72,7 @@
for (DexEncodedMethod virtualMethod : dexClass.virtualMethods()) {
if (!virtualMethod.isPrivateMethod()) {
assert virtualMethod.isProtectedMethod() || virtualMethod.isPublicMethod();
- boolean alreadyAdded = excludedMethods.contains(virtualMethod.getReference());
+ boolean alreadyAdded = wrappers.contains(equivalence.wrap(virtualMethod.getReference()));
// This looks quadratic but given the size of the collections met in practice for
// desugared libraries (Max ~15) it does not matter.
if (!alreadyAdded) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index 9402a62..afadf9f 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -576,11 +576,14 @@
public static class APIConverterConstructorCfCodeProvider extends SyntheticCfCodeProvider {
- DexField wrapperField;
+ private final DexField wrapperField;
+ private final DexType superType;
- public APIConverterConstructorCfCodeProvider(AppView<?> appView, DexField wrapperField) {
+ public APIConverterConstructorCfCodeProvider(
+ AppView<?> appView, DexField wrapperField, DexType superType) {
super(appView, wrapperField.holder);
this.wrapperField = wrapperField;
+ this.superType = superType;
}
@Override
@@ -592,9 +595,7 @@
new CfInvoke(
Opcodes.INVOKESPECIAL,
factory.createMethod(
- factory.objectType,
- factory.createProto(factory.voidType),
- factory.constructorMethodName),
+ superType, factory.createProto(factory.voidType), factory.constructorMethodName),
false));
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0));
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.type), 1));
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index cee58c4..f6d8354 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -569,7 +569,7 @@
SynthesizingContext outerContext = internalGetOuterContext(context, appView);
DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
DexClass clazz = appView.definitionFor(type);
- assert clazz != null;
+ assert clazz != null : "Missing existing fixed class " + type;
assert isSyntheticClass(type);
assert clazz.isProgramClass();
return clazz.asProgramClass();
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 2ff4ba6..a2c6aae 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1672,6 +1672,10 @@
public void disableApiCallerIdentification() {
enableApiCallerIdentification = false;
}
+
+ public void disableSubbingOfClasses() {
+ enableStubbingOfClasses = false;
+ }
}
public static class ProtoShrinkingOptions {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DesugaredLibraryJDK11Undesugarer.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DesugaredLibraryJDK11Undesugarer.java
index 0874b57..1331e08 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DesugaredLibraryJDK11Undesugarer.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/DesugaredLibraryJDK11Undesugarer.java
@@ -35,6 +35,7 @@
.put("java/lang/DesugarMath", "java/lang/Math")
.put("java/io/DesugarBufferedReader", "java/io/BufferedReader")
.put("java/io/DesugarInputStream", "java/io/InputStream")
+ .put("wrapper/adapter/HybridFileSystemProvider", "java/adapter/HybridFileSystemProvider")
.build();
public static void main(String[] args) throws Exception {
@@ -47,9 +48,6 @@
return ToolHelper.getDesugarJDKLibsBazelGeneratedFile();
}
Path desugaredLibJDK11Undesugared = Paths.get("build/libs/desugar_jdk_libs_11_undesugared.jar");
- if (Files.exists(desugaredLibJDK11Undesugared)) {
- return desugaredLibJDK11Undesugared;
- }
return generateUndesugaredJar(desugaredLibJDK11Undesugared);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
new file mode 100644
index 0000000..18646ba
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesTest.java
@@ -0,0 +1,121 @@
+// Copyright (c) 2022, 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.desugar.desugaredlibrary.jdk11;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.ByteBuffer;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FilesTest extends DesugaredLibraryTestBase {
+
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines(
+ "bytes written: 11",
+ "String written: Hello World",
+ "bytes read: 11",
+ "String read: Hello World");
+ private final TestParameters parameters;
+ private final boolean shrinkDesugaredLibrary;
+
+ @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ public static List<Object[]> data() {
+ // Skip Android 4.4.4 due to missing libjavacrypto.
+ return buildParameters(
+ BooleanUtils.values(),
+ getTestParameters()
+ .withDexRuntime(Version.V4_0_4)
+ .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
+ .withAllApiLevels()
+ .build());
+ }
+
+ public FilesTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.parameters = parameters;
+ }
+
+ private LibraryDesugaringTestConfiguration pathConfiguration() {
+ return LibraryDesugaringTestConfiguration.builder()
+ .setMinApi(parameters.getApiLevel())
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingWithPath()))
+ .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
+ .withKeepRuleConsumer()
+ .build();
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ Assume.assumeTrue(isJDK11DesugaredLibrary());
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(getLibraryFile())
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(pathConfiguration())
+ .compile()
+ .withArt6Plus64BitsLib()
+ .withArtFrameworks()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ Assume.assumeTrue(isJDK11DesugaredLibrary());
+ testForR8(Backend.DEX)
+ .addLibraryFiles(getLibraryFile())
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(TestClass.class)
+ .enableCoreLibraryDesugaring(pathConfiguration())
+ .compile()
+ .withArt6Plus64BitsLib()
+ .withArtFrameworks()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) throws Throwable {
+ Path path = Files.createTempFile("example", ".txt");
+ try (SeekableByteChannel channel =
+ Files.newByteChannel(path, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
+ String toWrite = "Hello World";
+
+ // Write the String toWrite into the channel.
+ ByteBuffer byteBuffer = ByteBuffer.wrap(toWrite.getBytes());
+ int write = channel.write(byteBuffer);
+ System.out.println("bytes written: " + write);
+ System.out.println("String written: " + toWrite);
+
+ // Read the String toWrite from the channel.
+ channel.position(0);
+ ByteBuffer byteBuffer2 = ByteBuffer.allocate(write);
+ int read = channel.read(byteBuffer2);
+ System.out.println("bytes read: " + read);
+ System.out.println("String read: " + new String(byteBuffer2.array()));
+ }
+ }
+ }
+}