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()));
+      }
+    }
+  }
+}