Reland "Use local FileSystem through conversions on high API devices"

This reverts commit 688b2c24f7630758c232801c9cff51d2f78886a6.

Change-Id: Ic07720fd208164a213872a0b40b2a2098326fa84
diff --git a/src/library_desugar/java/j$/nio/file/FileSystem.java b/src/library_desugar/java/j$/nio/file/FileSystem.java
new file mode 100644
index 0000000..a7a49a2
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/FileSystem.java
@@ -0,0 +1,13 @@
+// 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 j$.nio.file;
+
+import j$.nio.file.spi.FileSystemProvider;
+
+public class FileSystem {
+  public FileSystemProvider provider() {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/FileSystems.java b/src/library_desugar/java/j$/nio/file/FileSystems.java
new file mode 100644
index 0000000..d7214ca
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/FileSystems.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 j$.nio.file;
+
+public class FileSystems {
+  public static FileSystem getDefault() {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/Files.java b/src/library_desugar/java/j$/nio/file/Files.java
index 2825d24..f34593b 100644
--- a/src/library_desugar/java/j$/nio/file/Files.java
+++ b/src/library_desugar/java/j$/nio/file/Files.java
@@ -5,10 +5,9 @@
 package j$.nio.file;
 
 import java.io.IOException;
-import java.nio.file.Path;
 
 public class Files {
-  public static String probeContentType(Path path) throws IOException {
+  public static String probeContentType(j$.nio.file.Path path) throws IOException {
     return null;
   }
 }
diff --git a/src/library_desugar/java/j$/nio/file/LinkOption.java b/src/library_desugar/java/j$/nio/file/LinkOption.java
new file mode 100644
index 0000000..b8cf168
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/LinkOption.java
@@ -0,0 +1,15 @@
+// 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 j$.nio.file;
+
+public class LinkOption extends OpenOption {
+  public static java.nio.file.LinkOption wrap_convert(j$.nio.file.LinkOption option) {
+    return null;
+  }
+
+  public static j$.nio.file.LinkOption wrap_convert(java.nio.file.LinkOption option) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/OpenOption.java b/src/library_desugar/java/j$/nio/file/OpenOption.java
new file mode 100644
index 0000000..8b063d1
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/OpenOption.java
@@ -0,0 +1,7 @@
+// 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 j$.nio.file;
+
+public class OpenOption {}
diff --git a/src/library_desugar/java/j$/nio/file/Path.java b/src/library_desugar/java/j$/nio/file/Path.java
new file mode 100644
index 0000000..781ab5f
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/Path.java
@@ -0,0 +1,12 @@
+// 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 j$.nio.file;
+
+public class Path {
+
+  public static j$.nio.file.Path wrap_convert(java.nio.file.Path path) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/StandardOpenOption.java b/src/library_desugar/java/j$/nio/file/StandardOpenOption.java
new file mode 100644
index 0000000..a65da37
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/StandardOpenOption.java
@@ -0,0 +1,18 @@
+// 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 j$.nio.file;
+
+public class StandardOpenOption extends OpenOption {
+
+  public static java.nio.file.StandardOpenOption wrap_convert(
+      j$.nio.file.StandardOpenOption option) {
+    return null;
+  }
+
+  public static j$.nio.file.StandardOpenOption wrap_convert(
+      java.nio.file.StandardOpenOption option) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/WatchEvent.java b/src/library_desugar/java/j$/nio/file/WatchEvent.java
new file mode 100644
index 0000000..fd977e9
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/WatchEvent.java
@@ -0,0 +1,16 @@
+// 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 j$.nio.file;
+
+public class WatchEvent<T> {
+
+  public static java.nio.file.WatchEvent<?> wrap_convert(j$.nio.file.WatchEvent<?> option) {
+    return null;
+  }
+
+  public static j$.nio.file.WatchEvent<?> wrap_convert(java.nio.file.WatchEvent<?> option) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/attribute/BasicFileAttributeView.java b/src/library_desugar/java/j$/nio/file/attribute/BasicFileAttributeView.java
new file mode 100644
index 0000000..774cf2c
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/attribute/BasicFileAttributeView.java
@@ -0,0 +1,17 @@
+// 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 j$.nio.file.attribute;
+
+public class BasicFileAttributeView extends FileAttributeView {
+  public static java.nio.file.attribute.BasicFileAttributeView wrap_convert(
+      j$.nio.file.attribute.BasicFileAttributeView fileAttributeView) {
+    return null;
+  }
+
+  public static j$.nio.file.attribute.BasicFileAttributeView wrap_convert(
+      java.nio.file.attribute.BasicFileAttributeView fileAttributeView) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/attribute/BasicFileAttributes.java b/src/library_desugar/java/j$/nio/file/attribute/BasicFileAttributes.java
new file mode 100644
index 0000000..dd91a95
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/attribute/BasicFileAttributes.java
@@ -0,0 +1,17 @@
+// 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 j$.nio.file.attribute;
+
+public class BasicFileAttributes {
+  public static java.nio.file.attribute.BasicFileAttributes wrap_convert(
+      j$.nio.file.attribute.BasicFileAttributes fileAttributes) {
+    return null;
+  }
+
+  public static j$.nio.file.attribute.BasicFileAttributes wrap_convert(
+      java.nio.file.attribute.BasicFileAttributes fileAttributes) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/attribute/FileAttributeView.java b/src/library_desugar/java/j$/nio/file/attribute/FileAttributeView.java
new file mode 100644
index 0000000..34046eb3
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/attribute/FileAttributeView.java
@@ -0,0 +1,17 @@
+// 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 j$.nio.file.attribute;
+
+public class FileAttributeView {
+  public static java.nio.file.attribute.FileAttributeView wrap_convert(
+      j$.nio.file.attribute.FileAttributeView fileAttributeView) {
+    return null;
+  }
+
+  public static j$.nio.file.attribute.FileAttributeView wrap_convert(
+      java.nio.file.attribute.FileAttributeView fileAttributeView) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/attribute/FileOwnerAttributeView.java b/src/library_desugar/java/j$/nio/file/attribute/FileOwnerAttributeView.java
new file mode 100644
index 0000000..34a637d
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/attribute/FileOwnerAttributeView.java
@@ -0,0 +1,17 @@
+// 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 j$.nio.file.attribute;
+
+public class FileOwnerAttributeView extends FileAttributeView {
+  public static java.nio.file.attribute.FileOwnerAttributeView wrap_convert(
+      j$.nio.file.attribute.FileOwnerAttributeView fileAttributeView) {
+    return null;
+  }
+
+  public static j$.nio.file.attribute.FileOwnerAttributeView wrap_convert(
+      java.nio.file.attribute.FileOwnerAttributeView fileAttributeView) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/attribute/PosixFileAttributeView.java b/src/library_desugar/java/j$/nio/file/attribute/PosixFileAttributeView.java
new file mode 100644
index 0000000..bb24cb7
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/attribute/PosixFileAttributeView.java
@@ -0,0 +1,17 @@
+// 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 j$.nio.file.attribute;
+
+public class PosixFileAttributeView extends FileAttributeView {
+  public static java.nio.file.attribute.PosixFileAttributeView wrap_convert(
+      j$.nio.file.attribute.PosixFileAttributeView fileAttributeView) {
+    return null;
+  }
+
+  public static j$.nio.file.attribute.PosixFileAttributeView wrap_convert(
+      java.nio.file.attribute.PosixFileAttributeView fileAttributeView) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/attribute/PosixFileAttributes.java b/src/library_desugar/java/j$/nio/file/attribute/PosixFileAttributes.java
new file mode 100644
index 0000000..5e61814
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/attribute/PosixFileAttributes.java
@@ -0,0 +1,17 @@
+// 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 j$.nio.file.attribute;
+
+public class PosixFileAttributes extends BasicFileAttributes {
+  public static java.nio.file.attribute.PosixFileAttributes wrap_convert(
+      j$.nio.file.attribute.PosixFileAttributes fileAttributes) {
+    return null;
+  }
+
+  public static j$.nio.file.attribute.PosixFileAttributes wrap_convert(
+      java.nio.file.attribute.PosixFileAttributes fileAttributes) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/attribute/PosixFilePermission.java b/src/library_desugar/java/j$/nio/file/attribute/PosixFilePermission.java
new file mode 100644
index 0000000..94dbcbf
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/attribute/PosixFilePermission.java
@@ -0,0 +1,17 @@
+// 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 j$.nio.file.attribute;
+
+public class PosixFilePermission {
+  public static java.nio.file.attribute.PosixFilePermission wrap_convert(
+      j$.nio.file.attribute.PosixFilePermission permission) {
+    return null;
+  }
+
+  public static j$.nio.file.attribute.PosixFilePermission wrap_convert(
+      java.nio.file.attribute.PosixFilePermission permission) {
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/j$/nio/file/spi/FileSystemProvider.java b/src/library_desugar/java/j$/nio/file/spi/FileSystemProvider.java
new file mode 100644
index 0000000..38152b3
--- /dev/null
+++ b/src/library_desugar/java/j$/nio/file/spi/FileSystemProvider.java
@@ -0,0 +1,12 @@
+// 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 j$.nio.file.spi;
+
+public class FileSystemProvider {
+  public static java.nio.file.spi.FileSystemProvider wrap_convert(FileSystemProvider provider) {
+    // Rewritten in ASM to the wrapper method.
+    return null;
+  }
+}
diff --git a/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java b/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
index 658c351..d02344d 100644
--- a/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
+++ b/src/library_desugar/java/java/adapter/HybridFileSystemProvider.java
@@ -4,13 +4,12 @@
 
 package java.adapter;
 
-import android.os.Build.VERSION;
 import android.os.StrictMode;
 import android.os.StrictMode.ThreadPolicy;
 import desugar.sun.nio.fs.DesugarDefaultFileSystemProvider;
+import j$.nio.file.FileSystems;
 import java.net.URI;
 import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
 import java.nio.file.spi.FileSystemProvider;
 
 /**
@@ -23,20 +22,26 @@
       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();
+    try {
+      // On API 26 and above, FileSystems is present.
+      Class.forName("java.nio.file.FileSystems");
+      j$.nio.file.FileSystem fileSystem = FileSystems.getDefault();
+      j$.nio.file.spi.FileSystemProvider provider = fileSystem.provider();
+      return j$.nio.file.spi.FileSystemProvider.wrap_convert(provider);
+    } catch (ClassNotFoundException ignored) {
+      // We reach this path is API < 26.
     }
+    // The DesugarDefaultFileSystemProvider requires the ThreadPolicy to be set to work correctly.
+    // We cannot set the ThreadPolicy in headless and it should not matter.
+    // In headless, android.os is absent so the following line will throw.
+    // In headfull, android.os is present and we set the thread policy.
+    try {
+      Class.forName("android.os.Build");
+      setThreadPolicy();
+    } catch (ClassNotFoundException ignored) {
+      // Headless mode.
+    }
+    return DesugarDefaultFileSystemProvider.instance();
   }
 
   private static void setThreadPolicy() {
diff --git a/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java b/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
index 1caf2f1..da93736 100644
--- a/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
+++ b/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
@@ -4,7 +4,6 @@
 
 package java.adapter;
 
-import android.os.Build.VERSION;
 import desugar.sun.nio.fs.DesugarDefaultFileTypeDetector;
 import java.io.IOException;
 import java.nio.file.Path;
@@ -18,18 +17,19 @@
   private HybridFileTypeDetector() {}
 
   public static FileTypeDetector create() {
-    if (VERSION.SDK_INT >= 26) {
+    try {
+      // On API 26 and above, java.nio.file.Files is present.
+      Class.forName("java.nio.file.Files");
       return new PlatformFileTypeDetector();
-    } else {
+    } catch (ClassNotFoundException ignored) {
       return DesugarDefaultFileTypeDetector.create();
     }
   }
 
-  static class PlatformFileTypeDetector extends java.nio.file.spi.FileTypeDetector {
+  static class PlatformFileTypeDetector extends FileTypeDetector {
     @Override
     public String probeContentType(Path path) throws IOException {
-      // Relies at runtime on java.nio.file.Files.
-      return j$.nio.file.Files.probeContentType(path);
+      return j$.nio.file.Files.probeContentType(j$.nio.file.Path.wrap_convert(path));
     }
   }
 }
diff --git a/src/library_desugar/java/java/nio/file/FileApiFlips.java b/src/library_desugar/java/java/nio/file/FileApiFlips.java
new file mode 100644
index 0000000..fae6648
--- /dev/null
+++ b/src/library_desugar/java/java/nio/file/FileApiFlips.java
@@ -0,0 +1,170 @@
+// 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.nio.file;
+
+import static java.util.ConversionRuntimeException.exception;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class FileApiFlips {
+
+  public static Class<?> flipFileAttributes(Class<?> attributesClass) {
+    if (attributesClass == null) {
+      return null;
+    }
+    if (attributesClass == j$.nio.file.attribute.BasicFileAttributes.class) {
+      return java.nio.file.attribute.BasicFileAttributes.class;
+    }
+    if (attributesClass == j$.nio.file.attribute.PosixFileAttributes.class) {
+      return java.nio.file.attribute.PosixFileAttributes.class;
+    }
+    if (attributesClass == java.nio.file.attribute.BasicFileAttributes.class) {
+      return j$.nio.file.attribute.BasicFileAttributes.class;
+    }
+    if (attributesClass == java.nio.file.attribute.PosixFileAttributes.class) {
+      return j$.nio.file.attribute.PosixFileAttributes.class;
+    }
+    throw exception("java.nio.file.attribute.BasicFileAttributes", attributesClass);
+  }
+
+  public static Class<?> flipFileAttributeView(Class<?> attributeView) {
+    if (attributeView == null) {
+      return null;
+    }
+    if (attributeView == j$.nio.file.attribute.BasicFileAttributeView.class) {
+      return java.nio.file.attribute.BasicFileAttributeView.class;
+    }
+    if (attributeView == j$.nio.file.attribute.PosixFileAttributeView.class) {
+      return java.nio.file.attribute.PosixFileAttributeView.class;
+    }
+    if (attributeView == j$.nio.file.attribute.FileOwnerAttributeView.class) {
+      return java.nio.file.attribute.FileOwnerAttributeView.class;
+    }
+    if (attributeView == java.nio.file.attribute.BasicFileAttributeView.class) {
+      return j$.nio.file.attribute.BasicFileAttributeView.class;
+    }
+    if (attributeView == java.nio.file.attribute.PosixFileAttributeView.class) {
+      return j$.nio.file.attribute.PosixFileAttributeView.class;
+    }
+    if (attributeView == java.nio.file.attribute.FileOwnerAttributeView.class) {
+      return j$.nio.file.attribute.FileOwnerAttributeView.class;
+    }
+    throw exception("java.nio.file.attribute.FileAttributeView", attributeView);
+  }
+
+  public static RuntimeException exceptionOpenOption(Object suffix) {
+    throw exception("java.nio.file.OpenOption", suffix);
+  }
+
+  public static Set<?> flipOpenOptionSet(Set<?> openOptionSet) {
+    if (openOptionSet == null || openOptionSet.isEmpty()) {
+      return openOptionSet;
+    }
+    HashSet<Object> convertedSet = new HashSet<>();
+    Object guineaPig = openOptionSet.iterator().next();
+    if (guineaPig instanceof java.nio.file.OpenOption) {
+      for (Object item : openOptionSet) {
+        java.nio.file.OpenOption option;
+        try {
+          option = (java.nio.file.OpenOption) item;
+        } catch (ClassCastException cce) {
+          throw exceptionOpenOption(cce);
+        }
+        convertedSet.add(OpenOptionConversions.convert(option));
+      }
+      return convertedSet;
+    }
+    if (guineaPig instanceof j$.nio.file.OpenOption) {
+      for (Object item : openOptionSet) {
+        j$.nio.file.OpenOption option;
+        try {
+          option = (j$.nio.file.OpenOption) item;
+        } catch (ClassCastException cce) {
+          throw exceptionOpenOption(cce);
+        }
+        convertedSet.add(OpenOptionConversions.convert(option));
+      }
+      return convertedSet;
+    }
+    throw exceptionOpenOption(guineaPig.getClass());
+  }
+
+  public static RuntimeException exceptionPosixPermission(Object suffix) {
+    throw exception("java.nio.file.attribute.PosixFilePermission", suffix);
+  }
+
+  public static Set<?> flipPosixPermissionSet(Set<?> posixPermissions) {
+    if (posixPermissions == null || posixPermissions.isEmpty()) {
+      return posixPermissions;
+    }
+    HashSet<Object> convertedSet = new HashSet<>();
+    Object guineaPig = posixPermissions.iterator().next();
+    if (guineaPig instanceof java.nio.file.attribute.PosixFilePermission) {
+      for (Object item : posixPermissions) {
+        java.nio.file.attribute.PosixFilePermission permission;
+        try {
+          permission = (java.nio.file.attribute.PosixFilePermission) item;
+        } catch (ClassCastException cce) {
+          throw exceptionPosixPermission(cce);
+        }
+        convertedSet.add(j$.nio.file.attribute.PosixFilePermission.wrap_convert(permission));
+      }
+      return convertedSet;
+    }
+    if (guineaPig instanceof j$.nio.file.attribute.PosixFilePermission) {
+      for (Object item : posixPermissions) {
+        j$.nio.file.attribute.PosixFilePermission permission;
+        try {
+          permission = (j$.nio.file.attribute.PosixFilePermission) item;
+        } catch (ClassCastException cce) {
+          throw exceptionPosixPermission(cce);
+        }
+        convertedSet.add(j$.nio.file.attribute.PosixFilePermission.wrap_convert(permission));
+      }
+      return convertedSet;
+    }
+    throw exceptionPosixPermission(guineaPig.getClass());
+  }
+
+  public static RuntimeException exceptionWatchEvent(Object suffix) {
+    throw exception("java.nio.file.WatchEvent", suffix);
+  }
+
+  public static List<?> flipWatchEventList(List<?> watchEventList) {
+    if (watchEventList == null || watchEventList.isEmpty()) {
+      return watchEventList;
+    }
+    List<Object> convertedList = new ArrayList<>();
+    Object guineaPig = watchEventList.get(0);
+    if (guineaPig instanceof java.nio.file.WatchEvent) {
+      for (Object item : watchEventList) {
+        java.nio.file.WatchEvent<?> watchEvent;
+        try {
+          watchEvent = (java.nio.file.WatchEvent<?>) item;
+        } catch (ClassCastException cce) {
+          throw exceptionWatchEvent(cce);
+        }
+        convertedList.add(j$.nio.file.WatchEvent.wrap_convert(watchEvent));
+      }
+      return convertedList;
+    }
+    if (guineaPig instanceof j$.nio.file.WatchEvent) {
+      for (Object item : watchEventList) {
+        j$.nio.file.WatchEvent<?> watchEvent;
+        try {
+          watchEvent = (j$.nio.file.WatchEvent<?>) item;
+        } catch (ClassCastException cce) {
+          throw exceptionWatchEvent(cce);
+        }
+        convertedList.add(j$.nio.file.WatchEvent.wrap_convert(watchEvent));
+      }
+      return convertedList;
+    }
+    throw exceptionWatchEvent(guineaPig.getClass());
+  }
+}
diff --git a/src/library_desugar/java/java/nio/file/OpenOptionConversions.java b/src/library_desugar/java/java/nio/file/OpenOptionConversions.java
new file mode 100644
index 0000000..bfe4968
--- /dev/null
+++ b/src/library_desugar/java/java/nio/file/OpenOptionConversions.java
@@ -0,0 +1,35 @@
+// 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.nio.file;
+
+import static java.util.ConversionRuntimeException.exception;
+
+public class OpenOptionConversions {
+  public static java.nio.file.OpenOption convert(j$.nio.file.OpenOption option) {
+    if (option == null) {
+      return null;
+    }
+    if (option instanceof j$.nio.file.StandardOpenOption) {
+      return j$.nio.file.StandardOpenOption.wrap_convert((j$.nio.file.StandardOpenOption) option);
+    }
+    if (option instanceof j$.nio.file.LinkOption) {
+      return j$.nio.file.LinkOption.wrap_convert((j$.nio.file.LinkOption) option);
+    }
+    throw exception("java.nio.file.OpenOption", option);
+  }
+
+  public static j$.nio.file.OpenOption convert(java.nio.file.OpenOption option) {
+    if (option == null) {
+      return null;
+    }
+    if (option instanceof java.nio.file.StandardOpenOption) {
+      return j$.nio.file.StandardOpenOption.wrap_convert((java.nio.file.StandardOpenOption) option);
+    }
+    if (option instanceof java.nio.file.LinkOption) {
+      return j$.nio.file.LinkOption.wrap_convert((java.nio.file.LinkOption) option);
+    }
+    throw exception("java.nio.file.OpenOption", option);
+  }
+}
diff --git a/src/library_desugar/java/java/nio/file/attribute/FileAttributeConversions.java b/src/library_desugar/java/java/nio/file/attribute/FileAttributeConversions.java
index f4c4beb..332c89b 100644
--- a/src/library_desugar/java/java/nio/file/attribute/FileAttributeConversions.java
+++ b/src/library_desugar/java/java/nio/file/attribute/FileAttributeConversions.java
@@ -4,7 +4,10 @@
 
 package java.nio.file.attribute;
 
+import static java.util.ConversionRuntimeException.exception;
+
 public class FileAttributeConversions {
+
   public static java.nio.file.attribute.FileTime convert(j$.nio.file.attribute.FileTime fileTime) {
     if (fileTime == null) {
       return null;
@@ -18,4 +21,68 @@
     }
     return j$.nio.file.attribute.FileTime.fromMillis(fileTime.toMillis());
   }
+
+  public static java.nio.file.attribute.FileAttributeView convert(
+      j$.nio.file.attribute.FileAttributeView fileAttributeView) {
+    if (fileAttributeView == null) {
+      return null;
+    }
+    if (fileAttributeView instanceof j$.nio.file.attribute.PosixFileAttributeView) {
+      return j$.nio.file.attribute.PosixFileAttributeView.wrap_convert(
+          (j$.nio.file.attribute.PosixFileAttributeView) fileAttributeView);
+    }
+    if (fileAttributeView instanceof j$.nio.file.attribute.FileOwnerAttributeView) {
+      return j$.nio.file.attribute.FileOwnerAttributeView.wrap_convert(
+          (j$.nio.file.attribute.FileOwnerAttributeView) fileAttributeView);
+    }
+    if (fileAttributeView instanceof j$.nio.file.attribute.BasicFileAttributeView) {
+      return j$.nio.file.attribute.BasicFileAttributeView.wrap_convert(
+          (j$.nio.file.attribute.BasicFileAttributeView) fileAttributeView);
+    }
+    throw exception("java.nio.file.attribute.FileAttributeView", fileAttributeView);
+  }
+
+  public static j$.nio.file.attribute.FileAttributeView convert(
+      java.nio.file.attribute.FileAttributeView fileAttributeView) {
+    if (fileAttributeView == null) {
+      return null;
+    }
+    if (fileAttributeView instanceof java.nio.file.attribute.PosixFileAttributeView) {
+      return j$.nio.file.attribute.PosixFileAttributeView.wrap_convert(
+          (java.nio.file.attribute.PosixFileAttributeView) fileAttributeView);
+    }
+    if (fileAttributeView instanceof java.nio.file.attribute.FileOwnerAttributeView) {
+      return j$.nio.file.attribute.FileOwnerAttributeView.wrap_convert(
+          (java.nio.file.attribute.FileOwnerAttributeView) fileAttributeView);
+    }
+    if (fileAttributeView instanceof java.nio.file.attribute.BasicFileAttributeView) {
+      return j$.nio.file.attribute.BasicFileAttributeView.wrap_convert(
+          (java.nio.file.attribute.BasicFileAttributeView) fileAttributeView);
+    }
+    throw exception("java.nio.file.attribute.FileAttributeView", fileAttributeView);
+  }
+
+  public static java.nio.file.attribute.BasicFileAttributes convert(
+      j$.nio.file.attribute.BasicFileAttributes fileAttributes) {
+    if (fileAttributes == null) {
+      return null;
+    }
+    if (fileAttributes instanceof j$.nio.file.attribute.PosixFileAttributes) {
+      return j$.nio.file.attribute.PosixFileAttributes.wrap_convert(
+          (j$.nio.file.attribute.PosixFileAttributes) fileAttributes);
+    }
+    return j$.nio.file.attribute.BasicFileAttributes.wrap_convert(fileAttributes);
+  }
+
+  public static j$.nio.file.attribute.BasicFileAttributes convert(
+      java.nio.file.attribute.BasicFileAttributes fileAttributes) {
+    if (fileAttributes == null) {
+      return null;
+    }
+    if (fileAttributes instanceof java.nio.file.attribute.PosixFileAttributes) {
+      return j$.nio.file.attribute.PosixFileAttributes.wrap_convert(
+          (java.nio.file.attribute.PosixFileAttributes) fileAttributes);
+    }
+    return j$.nio.file.attribute.BasicFileAttributes.wrap_convert(fileAttributes);
+  }
 }
diff --git a/src/library_desugar/java/java/util/ConversionRuntimeException.java b/src/library_desugar/java/java/util/ConversionRuntimeException.java
new file mode 100644
index 0000000..896be1e
--- /dev/null
+++ b/src/library_desugar/java/java/util/ConversionRuntimeException.java
@@ -0,0 +1,16 @@
+// 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.util;
+
+public class ConversionRuntimeException extends RuntimeException {
+
+  public ConversionRuntimeException(String message) {
+    super(message);
+  }
+
+  public static RuntimeException exception(String type, Object suffix) {
+    throw new ConversionRuntimeException("Unsupported " + type + " :" + suffix);
+  }
+}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_path.json b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
index 4f0ec65..038efba 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_path.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
@@ -105,11 +105,15 @@
       "retarget_method_with_emulated_dispatch": {
         "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile"
       },
-      "api_conversion_collection": {
-        "java.nio.channels.AsynchronousFileChannel java.nio.file.spi.FileSystemProvider#newAsynchronousFileChannel(java.nio.file.Path, java.util.Set, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute[])" : [1, "OpenOption"],
-        "java.nio.channels.SeekableByteChannel java.nio.file.spi.FileSystemProvider#newByteChannel(java.nio.file.Path, java.util.Set, java.nio.file.attribute.FileAttribute[])" : [1, "OpenOption"],
-        "java.nio.channels.FileChannel java.nio.file.spi.FileSystemProvider#newFileChannel(java.nio.file.Path, java.util.Set, java.nio.file.attribute.FileAttribute[])" : [1, "OpenOption"],
-        "java.util.List java.nio.file.WatchKey#pollEvents()": [-1, "java.nio.file.WatchEvent"]
+      "api_generic_types_conversion": {
+        "java.nio.channels.AsynchronousFileChannel java.nio.file.spi.FileSystemProvider#newAsynchronousFileChannel(java.nio.file.Path, java.util.Set, java.util.concurrent.ExecutorService, java.nio.file.attribute.FileAttribute[])" : [1, "java.util.Set java.nio.file.FileApiFlips#flipOpenOptionSet(java.util.Set)"],
+        "java.nio.channels.SeekableByteChannel java.nio.file.spi.FileSystemProvider#newByteChannel(java.nio.file.Path, java.util.Set, java.nio.file.attribute.FileAttribute[])" : [1, "java.util.Set java.nio.file.FileApiFlips#flipOpenOptionSet(java.util.Set)"],
+        "java.nio.channels.FileChannel java.nio.file.spi.FileSystemProvider#newFileChannel(java.nio.file.Path, java.util.Set, java.nio.file.attribute.FileAttribute[])" : [1, "java.util.Set java.nio.file.FileApiFlips#flipOpenOptionSet(java.util.Set)"],
+        "java.util.List java.nio.file.WatchKey#pollEvents()": [-1, "java.util.List java.nio.file.FileApiFlips#flipWatchEventList(java.util.List)"],
+        "java.nio.file.attribute.FileAttributeView java.nio.file.spi.FileSystemProvider#getFileAttributeView(java.nio.file.Path, java.lang.Class, java.nio.file.LinkOption[])": [1, "java.lang.Class java.nio.file.FileApiFlips#flipFileAttributeView(java.lang.Class)"],
+        "java.nio.file.attribute.BasicFileAttributes java.nio.file.spi.FileSystemProvider#readAttributes(java.nio.file.Path, java.lang.Class, java.nio.file.LinkOption[])": [1, "java.lang.Class java.nio.file.FileApiFlips#flipFileAttributes(java.lang.Class)"],
+        "java.util.Set java.nio.file.attribute.PosixFileAttributes#permissions()": [-1, "java.util.Set java.nio.file.FileApiFlips#flipPosixPermissionSet(java.util.Set)"],
+        "void java.nio.file.attribute.PosixFileAttributeView#setPermissions(java.util.Set)": [0, "java.util.Set java.nio.file.FileApiFlips#flipPosixPermissionSet(java.util.Set)"]
       },
       "wrapper_conversion": [
         "java.nio.channels.AsynchronousChannel",
@@ -117,6 +121,7 @@
         "java.nio.file.Path",
         "java.nio.file.FileSystem",
         "java.nio.file.WatchService",
+        "java.nio.file.WatchEvent",
         "java.nio.file.WatchEvent$Kind",
         "java.nio.file.WatchKey",
         "java.nio.file.Watchable",
@@ -124,19 +129,24 @@
         "java.nio.file.WatchEvent$Modifier",
         "java.nio.file.attribute.UserPrincipalLookupService",
         "java.nio.file.spi.FileSystemProvider",
+        "java.nio.file.spi.FileTypeDetector",
         "java.nio.file.AccessMode",
+        "java.nio.file.StandardOpenOption",
         "java.nio.file.LinkOption",
         "java.nio.file.CopyOption",
         "java.nio.file.attribute.GroupPrincipal",
         "java.nio.file.attribute.FileAttribute",
-        "java.nio.file.attribute.FileAttributeView",
         "java.nio.file.attribute.UserPrincipal",
         "java.nio.file.FileStore",
         "java.nio.file.attribute.FileStoreAttributeView",
         "java.nio.file.DirectoryStream$Filter",
         "java.nio.file.DirectoryStream",
-        "java.nio.file.OpenOption",
-        "java.nio.file.attribute.BasicFileAttributes"
+        "java.nio.file.attribute.PosixFilePermission",
+        "java.nio.file.attribute.BasicFileAttributes",
+        "java.nio.file.attribute.PosixFileAttributes",
+        "java.nio.file.attribute.FileOwnerAttributeView",
+        "java.nio.file.attribute.PosixFileAttributeView",
+        "java.nio.file.attribute.BasicFileAttributeView"
       ],
       "wrapper_conversion_excluding": {
         "java.nio.channels.AsynchronousFileChannel": [
@@ -146,7 +156,10 @@
         ]
       },
       "custom_conversion": {
-        "java.nio.file.attribute.FileTime": "java.nio.file.attribute.FileAttributeConversions"
+        "java.nio.file.OpenOption": "java.nio.file.OpenOptionConversions",
+        "java.nio.file.attribute.FileTime": "java.nio.file.attribute.FileAttributeConversions",
+        "java.nio.file.attribute.BasicFileAttributes": "java.nio.file.attribute.FileAttributeConversions",
+        "java.nio.file.attribute.FileAttributeView": "java.nio.file.attribute.FileAttributeConversions"
       }
     },
     {
@@ -395,14 +408,33 @@
         "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",
-        "java.adapter" : "j$.adapter"
+        "java.adapter" : "j$.adapter",
+        "java.util.ConversionRuntimeException": "j$.util.ConversionRuntimeException"
       },
       "rewrite_derived_prefix": {
-        "java.nio.file.attribute.FileTime": {
-          "j$.nio.file.attribute.FileTime": "java.nio.file.attribute.FileTime"
+        "java.nio.file.attribute.": {
+          "j$.nio.file.attribute.": "java.nio.file.attribute."
+        },
+        "java.nio.file.OpenOption": {
+          "j$.nio.file.OpenOption": "java.nio.file.OpenOption"
+        },
+        "java.nio.file.StandardOpenOption": {
+          "j$.nio.file.StandardOpenOption": "java.nio.file.StandardOpenOption"
+        },
+        "java.nio.file.LinkOption": {
+          "j$.nio.file.LinkOption": "java.nio.file.LinkOption"
         },
         "java.nio.file.Files": {
           "j$.nio.file.Files": "java.nio.file.Files"
+        },
+        "java.nio.file.FileSystem": {
+          "j$.nio.file.FileSystem": "java.nio.file.FileSystem"
+        },
+        "java.nio.file.spi.FileSystemProvider": {
+          "j$.nio.file.spi.FileSystemProvider": "java.nio.file.spi.FileSystemProvider"
+        },
+        "java.nio.file.Path": {
+          "j$.nio.file.Path": "java.nio.file.Path"
         }
       },
       "retarget_method": {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
index 29ecfd2..0e6bd6a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion;
 
 import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.methodWithVivifiedTypeInSignature;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter.vivifiedTypeFor;
 
 import com.android.tools.r8.cf.code.CfArrayLoad;
 import com.android.tools.r8.cf.code.CfArrayStore;
@@ -156,9 +157,12 @@
         computeReturnConversion(method, false, eventConsumer, context, contextSupplier);
     DexMethod[] parameterConversions =
         computeParameterConversions(method, true, eventConsumer, context, contextSupplier);
+    DexType newHolder =
+        appView.typeRewriter.hasRewrittenType(method.getHolderType(), appView)
+            ? vivifiedTypeFor(method.getHolderType(), appView)
+            : method.getHolderType();
     DexMethod forwardMethod =
-        convertedMethod(
-            method, true, returnConversion, parameterConversions, wrapperField.getType());
+        convertedMethod(method, true, returnConversion, parameterConversions, newHolder);
     CfCode cfCode =
         new APIConversionCfCodeProvider(
                 appView,
@@ -467,12 +471,13 @@
 
   private DexMethod internalComputeReturnConversion(
       DexMethod invokedMethod,
-      BiFunction<DexType, DexType, DexMethod> methodSupplier,
+      BiFunction<DexType, DexMethod, DexMethod> methodSupplier,
       ProgramMethod context) {
     DexType returnType = invokedMethod.proto.returnType;
-    if (wrapperSynthesizer.shouldConvert(returnType, invokedMethod, context)) {
-      DexType apiConversionCollection = getReturnApiConversionCollection(invokedMethod);
-      return methodSupplier.apply(returnType, apiConversionCollection);
+    DexMethod apiGenericTypesConversion = getReturnApiGenericConversion(invokedMethod);
+    if (wrapperSynthesizer.shouldConvert(
+        returnType, apiGenericTypesConversion, invokedMethod, context)) {
+      return methodSupplier.apply(returnType, apiGenericTypesConversion);
     }
     return null;
   }
@@ -486,9 +491,9 @@
     return internalComputeParameterConversions(
         invokedMethod,
         wrapperSynthesizer,
-        (argType, apiConversionCollection) ->
+        (argType, apiGenericTypesConversion) ->
             wrapperSynthesizer.ensureConversionMethod(
-                argType, destIsVivified, apiConversionCollection, eventConsumer, contextSupplier),
+                argType, destIsVivified, apiGenericTypesConversion, eventConsumer, contextSupplier),
         context);
   }
 
@@ -501,41 +506,42 @@
     return internalComputeParameterConversions(
         invokedMethod,
         wrapperSynthesizer,
-        (argType, apiConversionCollection) ->
+        (argType, apiGenericTypesConversion) ->
             wrapperSynthesizer.getExistingProgramConversionMethod(
-                argType, destIsVivified, apiConversionCollection, eventConsumer, contextSupplier),
+                argType, destIsVivified, apiGenericTypesConversion, eventConsumer, contextSupplier),
         context);
   }
 
   private DexMethod[] internalComputeParameterConversions(
       DexMethod invokedMethod,
       DesugaredLibraryWrapperSynthesizer wrapperSynthesizor,
-      BiFunction<DexType, DexType, DexMethod> methodSupplier,
+      BiFunction<DexType, DexMethod, DexMethod> methodSupplier,
       ProgramMethod context) {
     DexMethod[] parameterConversions = new DexMethod[invokedMethod.getArity()];
     DexType[] parameters = invokedMethod.proto.parameters.values;
     for (int i = 0; i < parameters.length; i++) {
-      DexType apiConversionCollection = getApiConversionCollection(invokedMethod, i);
+      DexMethod apiGenericTypesConversion = getApiGenericConversion(invokedMethod, i);
       DexType argType = parameters[i];
-      if (wrapperSynthesizor.shouldConvert(argType, invokedMethod, context)) {
-        parameterConversions[i] = methodSupplier.apply(argType, apiConversionCollection);
+      if (wrapperSynthesizor.shouldConvert(
+          argType, apiGenericTypesConversion, invokedMethod, context)) {
+        parameterConversions[i] = methodSupplier.apply(argType, apiGenericTypesConversion);
       }
     }
     return parameterConversions;
   }
 
-  public DexType getReturnApiConversionCollection(DexMethod method) {
-    return getApiConversionCollection(method, method.getArity());
+  public DexMethod getReturnApiGenericConversion(DexMethod method) {
+    return getApiGenericConversion(method, method.getArity());
   }
 
-  public DexType getApiConversionCollection(DexMethod method, int parameterIndex) {
-    DexType[] dexTypes =
+  public DexMethod getApiGenericConversion(DexMethod method, int parameterIndex) {
+    DexMethod[] conversions =
         appView
             .options()
             .machineDesugaredLibrarySpecification
-            .getApiConversionCollection()
+            .getApiGenericConversion()
             .get(method);
-    return dexTypes == null ? null : dexTypes[parameterIndex];
+    return conversions == null ? null : conversions[parameterIndex];
   }
 
   private DexMethod convertedMethod(
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 a930b12..d28ccaf 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
@@ -33,7 +33,6 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.synthetic.apiconverter.NullableConversionCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.apiconverter.NullableConversionCfCodeProvider.ArrayConversionCfCodeProvider;
-import com.android.tools.r8.ir.synthetic.apiconverter.NullableConversionCfCodeProvider.CollectionConversionCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.apiconverter.WrapperConstructorCfCodeProvider;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.MethodPosition;
@@ -118,13 +117,15 @@
         || appView.getSyntheticItems().isSyntheticOfKind(type, kinds -> kinds.VIVIFIED_WRAPPER);
   }
 
-  public boolean shouldConvert(DexType type, DexMethod method) {
-    return shouldConvert(type, method, null);
-  }
-
-  public boolean shouldConvert(DexType type, DexMethod method, ProgramMethod context) {
+  public boolean shouldConvert(
+      DexType type, DexMethod apiGenericTypesConversion, DexMethod method, ProgramMethod context) {
     if (type.isArrayType()) {
-      return shouldConvert(type.toBaseType(appView.dexItemFactory()), method, context);
+      assert apiGenericTypesConversion == null;
+      return shouldConvert(
+          type.toBaseType(appView.dexItemFactory()), apiGenericTypesConversion, method, context);
+    }
+    if (apiGenericTypesConversion != null) {
+      return true;
     }
     if (!appView.typeRewriter.hasRewrittenType(type, appView)) {
       return false;
@@ -139,13 +140,12 @@
   public DexMethod ensureConversionMethod(
       DexType type,
       boolean destIsVivified,
-      DexType apiConversionCollection,
+      DexMethod apiGenericTypesConversion,
       DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer,
       Supplier<UniqueContext> contextSupplier) {
-    if (apiConversionCollection != null) {
+    if (apiGenericTypesConversion != null) {
       assert !type.isArrayType();
-      return ensureCollectionConversionMethod(
-          type, destIsVivified, apiConversionCollection, eventConsumer, contextSupplier);
+      return apiGenericTypesConversion;
     }
     DexType srcType = destIsVivified ? type : vivifiedTypeFor(type);
     DexType destType = destIsVivified ? vivifiedTypeFor(type) : type;
@@ -171,68 +171,6 @@
     return conversion;
   }
 
-  private DexMethod ensureCollectionConversionMethod(
-      DexType type,
-      boolean destIsVivified,
-      DexType apiConversionCollection,
-      DesugaredLibraryClasspathWrapperSynthesizeEventConsumer eventConsumer,
-      Supplier<UniqueContext> contextSupplier) {
-    assert type == factory.setType || type == factory.listType;
-    DexMethod conversion =
-        ensureConversionMethod(
-            apiConversionCollection,
-            destIsVivified,
-            null, // We do not support nested collections.
-            eventConsumer,
-            contextSupplier);
-    return ensureCollectionConversionMethod(type, eventConsumer, contextSupplier, conversion);
-  }
-
-  private DexMethod ensureCollectionConversionMethodFromExistingBaseConversion(
-      DexType type,
-      boolean destIsVivified,
-      DexType apiConversionCollection,
-      DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer,
-      Supplier<UniqueContext> contextSupplier) {
-    assert type == factory.setType || type == factory.listType;
-    DexMethod conversion =
-        getExistingProgramConversionMethod(
-            apiConversionCollection,
-            destIsVivified,
-            null, // We do not support nested collections.
-            eventConsumer,
-            contextSupplier);
-    return ensureCollectionConversionMethod(type, eventConsumer, contextSupplier, conversion);
-  }
-
-  private DexMethod ensureCollectionConversionMethod(
-      DexType collectionType,
-      DesugaredLibraryWrapperSynthesizerEventConsumer eventConsumer,
-      Supplier<UniqueContext> contextSupplier,
-      DexMethod conversion) {
-    ProgramMethod collectionConversion =
-        appView
-            .getSyntheticItems()
-            .createMethod(
-                kinds -> kinds.COLLECTION_CONVERSION,
-                contextSupplier.get(),
-                appView,
-                builder ->
-                    builder
-                        .setProto(factory.createProto(collectionType, collectionType))
-                        .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
-                        .setCode(
-                            codeSynthesizor ->
-                                new CollectionConversionCfCodeProvider(
-                                        appView,
-                                        codeSynthesizor.getHolderType(),
-                                        collectionType,
-                                        conversion)
-                                    .generateCfCode()));
-    eventConsumer.acceptCollectionConversion(collectionConversion);
-    return collectionConversion.getReference();
-  }
-
   private DexMethod ensureArrayConversionMethod(
       DexType type,
       DexType srcType,
@@ -300,13 +238,12 @@
   public DexMethod getExistingProgramConversionMethod(
       DexType type,
       boolean destIsVivified,
-      DexType apiConversionCollection,
+      DexMethod apiGenericTypesConversion,
       DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer eventConsumer,
       Supplier<UniqueContext> contextSupplier) {
-    if (apiConversionCollection != null) {
+    if (apiGenericTypesConversion != null) {
       assert !type.isArrayType();
-      return ensureCollectionConversionMethodFromExistingBaseConversion(
-          type, destIsVivified, apiConversionCollection, eventConsumer, contextSupplier);
+      return apiGenericTypesConversion;
     }
     DexType srcType = destIsVivified ? type : vivifiedTypeFor(type);
     DexType destType = destIsVivified ? vivifiedTypeFor(type) : type;
@@ -699,7 +636,6 @@
         .getWrappers()
         .forEach(
             (type, methods) -> {
-              assert !librarySpecification.getCustomConversions().containsKey(type);
               DexClass validClassToWrap = getValidClassToWrap(type);
               // In broken set-ups we can end up having a json files containing wrappers of non
               // desugared classes. Such wrappers are not required since the class won't be
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index 189dca8..1aa5f62 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -48,7 +48,7 @@
 
   static final String API_LEVEL_BELOW_OR_EQUAL_KEY = "api_level_below_or_equal";
   static final String API_LEVEL_GREATER_OR_EQUAL_KEY = "api_level_greater_or_equal";
-  static final String API_CONVERSION_COLLECTION = "api_conversion_collection";
+  static final String API_GENERIC_TYPES_CONVERSION = "api_generic_types_conversion";
   static final String WRAPPER_CONVERSION_KEY = "wrapper_conversion";
   static final String WRAPPER_CONVERSION_EXCLUDING_KEY = "wrapper_conversion_excluding";
   static final String CUSTOM_CONVERSION_KEY = "custom_conversion";
@@ -264,15 +264,15 @@
         builder.putDontRewritePrefix(dontRewritePrefix.getAsString());
       }
     }
-    if (jsonFlagSet.has(API_CONVERSION_COLLECTION)) {
+    if (jsonFlagSet.has(API_GENERIC_TYPES_CONVERSION)) {
       for (Map.Entry<String, JsonElement> methodAndDescription :
-          jsonFlagSet.get(API_CONVERSION_COLLECTION).getAsJsonObject().entrySet()) {
+          jsonFlagSet.get(API_GENERIC_TYPES_CONVERSION).getAsJsonObject().entrySet()) {
         JsonArray array = methodAndDescription.getValue().getAsJsonArray();
         for (int i = 0; i < array.size(); i += 2) {
-          builder.addApiConversionCollection(
+          builder.addApiGenericTypesConversion(
               parseMethod(methodAndDescription.getKey()),
               array.get(i).getAsInt(),
-              stringDescriptorToDexType(array.get(i + 1).getAsString()));
+              parseMethod(array.get(i + 1).getAsString()));
         }
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
index 94ae8d0..f17235f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -15,13 +15,11 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
-import com.google.common.collect.Sets.SetView;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 public class HumanRewritingFlags {
 
@@ -34,7 +32,7 @@
   private final Map<DexMethod, DexType> covariantRetarget;
   private final Map<DexMethod, DexType> retargetMethod;
   private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch;
-  private final Map<DexMethod, DexType[]> apiConversionCollection;
+  private final Map<DexMethod, DexMethod[]> apiGenericTypesConversion;
   private final Map<DexType, DexType> legacyBackport;
   private final Map<DexType, DexType> customConversions;
   private final Set<DexMethod> dontRewriteInvocation;
@@ -53,7 +51,7 @@
       Map<DexMethod, DexType> covariantRetarget,
       Map<DexMethod, DexType> retargetMethod,
       Map<DexMethod, DexType> retargetMethodEmulatedDispatch,
-      Map<DexMethod, DexType[]> apiConversionCollection,
+      Map<DexMethod, DexMethod[]> apiGenericTypesConversion,
       Map<DexType, DexType> legacyBackport,
       Map<DexType, DexType> customConversion,
       Set<DexMethod> dontRewriteInvocation,
@@ -70,7 +68,7 @@
     this.covariantRetarget = covariantRetarget;
     this.retargetMethod = retargetMethod;
     this.retargetMethodEmulatedDispatch = retargetMethodEmulatedDispatch;
-    this.apiConversionCollection = apiConversionCollection;
+    this.apiGenericTypesConversion = apiGenericTypesConversion;
     this.legacyBackport = legacyBackport;
     this.customConversions = customConversion;
     this.dontRewriteInvocation = dontRewriteInvocation;
@@ -118,7 +116,7 @@
         covariantRetarget,
         retargetMethod,
         retargetMethodEmulatedDispatch,
-        apiConversionCollection,
+        apiGenericTypesConversion,
         legacyBackport,
         customConversions,
         dontRewriteInvocation,
@@ -164,8 +162,8 @@
     return retargetMethodEmulatedDispatch;
   }
 
-  public Map<DexMethod, DexType[]> getApiConversionCollection() {
-    return apiConversionCollection;
+  public Map<DexMethod, DexMethod[]> getApiGenericConversion() {
+    return apiGenericTypesConversion;
   }
 
   public Map<DexType, DexType> getLegacyBackport() {
@@ -221,7 +219,7 @@
     private final Map<DexMethod, DexType> covariantRetarget;
     private final Map<DexMethod, DexType> retargetMethod;
     private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch;
-    private final Map<DexMethod, DexType[]> apiConversionCollection;
+    private final Map<DexMethod, DexMethod[]> apiGenericTypesConversion;
     private final Map<DexType, DexType> legacyBackport;
     private final Map<DexType, DexType> customConversions;
     private final Set<DexMethod> dontRewriteInvocation;
@@ -265,7 +263,7 @@
         Map<DexMethod, DexType> covariantRetarget,
         Map<DexMethod, DexType> retargetMethod,
         Map<DexMethod, DexType> retargetMethodEmulatedDispatch,
-        Map<DexMethod, DexType[]> apiConversionCollection,
+        Map<DexMethod, DexMethod[]> apiConversionCollection,
         Map<DexType, DexType> backportCoreLibraryMember,
         Map<DexType, DexType> customConversions,
         Set<DexMethod> dontRewriteInvocation,
@@ -284,7 +282,7 @@
       this.covariantRetarget = new IdentityHashMap<>(covariantRetarget);
       this.retargetMethod = new IdentityHashMap<>(retargetMethod);
       this.retargetMethodEmulatedDispatch = new IdentityHashMap<>(retargetMethodEmulatedDispatch);
-      this.apiConversionCollection = new IdentityHashMap<>(apiConversionCollection);
+      this.apiGenericTypesConversion = new IdentityHashMap<>(apiConversionCollection);
       this.legacyBackport = new IdentityHashMap<>(backportCoreLibraryMember);
       this.customConversions = new IdentityHashMap<>(customConversions);
       this.dontRewriteInvocation = Sets.newIdentityHashSet();
@@ -406,12 +404,13 @@
       return this;
     }
 
-    public void addApiConversionCollection(DexMethod method, int index, DexType type) {
-      DexType[] types =
-          apiConversionCollection.computeIfAbsent(method, k -> new DexType[method.getArity() + 1]);
+    public void addApiGenericTypesConversion(DexMethod method, int index, DexMethod conversion) {
+      DexMethod[] types =
+          apiGenericTypesConversion.computeIfAbsent(
+              method, k -> new DexMethod[method.getArity() + 1]);
       int actualIndex = index == -1 ? method.getArity() : index;
       assert types[actualIndex] == null;
-      types[actualIndex] = type;
+      types[actualIndex] = conversion;
     }
 
     public Builder putLegacyBackport(DexType backportType, DexType rewrittenBackportType) {
@@ -444,7 +443,6 @@
     }
 
     public HumanRewritingFlags build() {
-      validate();
       return new HumanRewritingFlags(
           ImmutableMap.copyOf(rewritePrefix),
           ImmutableSet.copyOf(dontRewritePrefix),
@@ -455,7 +453,7 @@
           ImmutableMap.copyOf(covariantRetarget),
           ImmutableMap.copyOf(retargetMethod),
           ImmutableMap.copyOf(retargetMethodEmulatedDispatch),
-          ImmutableMap.copyOf(apiConversionCollection),
+          ImmutableMap.copyOf(apiGenericTypesConversion),
           ImmutableMap.copyOf(legacyBackport),
           ImmutableMap.copyOf(customConversions),
           ImmutableSet.copyOf(dontRewriteInvocation),
@@ -464,19 +462,5 @@
           ImmutableMap.copyOf(amendLibraryMethod),
           ImmutableMap.copyOf(amendLibraryField));
     }
-
-    private void validate() {
-      SetView<DexType> dups =
-          Sets.intersection(customConversions.keySet(), wrapperConversions.keySet());
-      if (!dups.isEmpty()) {
-        throw reporter.fatalError(
-            new StringDiagnostic(
-                "Invalid desugared library configuration. "
-                    + "Duplicate types in custom conversions and wrapper conversions: "
-                    + String.join(
-                        ", ", dups.stream().map(DexType::toString).collect(Collectors.toSet())),
-                origin));
-      }
-    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index 4e08dc9..16b0b9f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -120,8 +120,8 @@
     return rewritingFlags.getEmulatedVirtualRetargetThroughEmulatedInterface();
   }
 
-  public Map<DexMethod, DexType[]> getApiConversionCollection() {
-    return rewritingFlags.getApiConversionCollection();
+  public Map<DexMethod, DexMethod[]> getApiGenericConversion() {
+    return rewritingFlags.getApiGenericConversion();
   }
 
   public void forEachRetargetMethod(Consumer<DexMethod> consumer) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
index cafb6c8..e125c53 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -37,7 +37,7 @@
       Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
       Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget,
       Map<DexMethod, DexMethod> emulatedVirtualRetargetThroughEmulatedInterface,
-      Map<DexMethod, DexType[]> apiConversionCollection,
+      Map<DexMethod, DexMethod[]> apiGenericTypesConversion,
       Map<DexType, EmulatedInterfaceDescriptor> emulatedInterfaces,
       Map<DexType, List<DexMethod>> wrappers,
       Map<DexType, DexType> legacyBackport,
@@ -55,7 +55,7 @@
     this.emulatedVirtualRetarget = emulatedVirtualRetarget;
     this.emulatedVirtualRetargetThroughEmulatedInterface =
         emulatedVirtualRetargetThroughEmulatedInterface;
-    this.apiConversionCollection = apiConversionCollection;
+    this.apiGenericTypesConversion = apiGenericTypesConversion;
     this.emulatedInterfaces = emulatedInterfaces;
     this.wrappers = wrappers;
     this.legacyBackport = legacyBackport;
@@ -96,7 +96,7 @@
   private final Map<DexMethod, DexMethod> emulatedVirtualRetargetThroughEmulatedInterface;
 
   // Encodes weither specific parameter collections need to be wrapped differently.
-  private final Map<DexMethod, DexType[]> apiConversionCollection;
+  private final Map<DexMethod, DexMethod[]> apiGenericTypesConversion;
 
   // Emulated interface descriptors.
   private final Map<DexType, EmulatedInterfaceDescriptor> emulatedInterfaces;
@@ -146,8 +146,8 @@
     return emulatedVirtualRetargetThroughEmulatedInterface;
   }
 
-  public Map<DexMethod, DexType[]> getApiConversionCollection() {
-    return apiConversionCollection;
+  public Map<DexMethod, DexMethod[]> getApiGenericConversion() {
+    return apiGenericTypesConversion;
   }
 
   public void forEachRetargetMethod(Consumer<DexMethod> consumer) {
@@ -245,7 +245,7 @@
         emulatedVirtualRetarget = ImmutableMap.builder();
     private final ImmutableMap.Builder<DexMethod, DexMethod>
         emulatedVirtualRetargetThroughEmulatedInterface = ImmutableMap.builder();
-    private final ImmutableMap.Builder<DexMethod, DexType[]> apiConversionCollection =
+    private final ImmutableMap.Builder<DexMethod, DexMethod[]> apiGenericTypesConversion =
         ImmutableMap.builder();
     private final ImmutableMap.Builder<DexType, EmulatedInterfaceDescriptor> emulatedInterfaces =
         ImmutableMap.builder();
@@ -304,8 +304,8 @@
       emulatedVirtualRetargetThroughEmulatedInterface.put(src, dest);
     }
 
-    public void addApiConversionCollection(DexMethod method, DexType[] dexTypes) {
-      apiConversionCollection.put(method, dexTypes);
+    public void addApiGenericTypesConversion(DexMethod method, DexMethod[] conversions) {
+      apiGenericTypesConversion.put(method, conversions);
     }
 
     public void addWrapper(DexType wrapperConversion, List<DexMethod> methods) {
@@ -365,7 +365,7 @@
           nonEmulatedVirtualRetarget.build(),
           emulatedVirtualRetarget.build(),
           emulatedVirtualRetargetThroughEmulatedInterface.build(),
-          apiConversionCollection.build(),
+          apiGenericTypesConversion.build(),
           emulatedInterfaces.build(),
           wrappers.build(),
           legacyBackport.build(),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
index dea440e..1097b06 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -97,7 +97,7 @@
         ComputedApiLevel.unknown());
     rewritingFlags.getAmendLibraryMethod().forEach(builder::amendLibraryMethod);
     rewritingFlags.getAmendLibraryField().forEach(builder::amendLibraryField);
-    rewritingFlags.getApiConversionCollection().forEach(builder::addApiConversionCollection);
+    rewritingFlags.getApiGenericConversion().forEach(builder::addApiGenericTypesConversion);
     new HumanToMachineRetargetConverter(appInfo)
         .convertRetargetFlags(rewritingFlags, builder, this::warnMissingReferences);
     new HumanToMachineEmulatedInterfaceConverter(appInfo)
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
index 10e267b..fb04da0 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
@@ -244,117 +244,4 @@
       return standardCfCodeFromInstructions(instructions);
     }
   }
-
-  public static class CollectionConversionCfCodeProvider extends NullableConversionCfCodeProvider {
-
-    private final DexType collectionType;
-    private final DexMethod conversion;
-
-    public CollectionConversionCfCodeProvider(
-        AppView<?> appView, DexType holder, DexType collectionType, DexMethod conversion) {
-      super(appView, holder);
-      this.collectionType = collectionType;
-      this.conversion = conversion;
-    }
-
-    @Override
-    public CfCode generateCfCode() {
-      DexItemFactory factory = appView.dexItemFactory();
-      List<CfInstruction> instructions = new ArrayList<>();
-
-      // if (arg == null) { return null; }
-      generateNullCheck(instructions);
-      instructions.add(
-          CfFrame.builder().appendLocal(FrameType.initialized(collectionType)).build());
-
-      CfFrame frame =
-          CfFrame.builder()
-              .appendLocal(FrameType.initialized(collectionType))
-              .appendLocal(FrameType.initialized(collectionType))
-              .appendLocal(FrameType.initialized(factory.iteratorType))
-              .build();
-
-      // Collection<E> t1 = new Collection<E>();
-      if (collectionType == factory.setType) {
-        DexType hashSetType = factory.createType("Ljava/util/HashSet;");
-        instructions.add(new CfNew(hashSetType));
-        instructions.add(
-            new CfInvoke(
-                Opcodes.INVOKESPECIAL,
-                factory.createMethod(
-                    hashSetType,
-                    factory.createProto(factory.voidType),
-                    factory.constructorMethodName),
-                false));
-      } else {
-        assert collectionType == factory.listType;
-        DexType arrayListType = factory.createType("Ljava/util/ArrayList;");
-        instructions.add(new CfNew(arrayListType));
-        instructions.add(
-            new CfInvoke(
-                Opcodes.INVOKESPECIAL,
-                factory.createMethod(
-                    arrayListType,
-                    factory.createProto(factory.voidType),
-                    factory.constructorMethodName),
-                false));
-      }
-      instructions.add(new CfStore(ValueType.OBJECT, 1));
-
-      // Iterator<E> t2 = receiver.iterator();
-      instructions.add(new CfLoad(ValueType.OBJECT, 0));
-      instructions.add(
-          new CfInvoke(
-              Opcodes.INVOKEINTERFACE,
-              factory.createMethod(
-                  factory.collectionType, factory.createProto(factory.iteratorType), "iterator"),
-              true));
-      instructions.add(new CfStore(ValueType.OBJECT, 2));
-
-      // while(t2.hasNext())
-      CfLabel returnLabel = new CfLabel();
-      CfLabel loopLabel = new CfLabel();
-      instructions.add(loopLabel);
-      instructions.add(frame);
-      instructions.add(new CfLoad(ValueType.fromDexType(factory.iteratorType), 2));
-      instructions.add(
-          new CfInvoke(
-              Opcodes.INVOKEINTERFACE,
-              factory.createMethod(
-                  factory.iteratorType, factory.createProto(factory.booleanType), "hasNext"),
-              true));
-      instructions.add(new CfConstNumber(0, ValueType.INT));
-      instructions.add(new CfIfCmp(If.Type.EQ, ValueType.INT, returnLabel));
-
-      // {t1.add(convert(t2.next());}
-      instructions.add(new CfLoad(ValueType.fromDexType(collectionType), 1));
-      instructions.add(new CfLoad(ValueType.fromDexType(factory.iteratorType), 2));
-      instructions.add(
-          new CfInvoke(
-              Opcodes.INVOKEINTERFACE,
-              factory.createMethod(
-                  factory.iteratorType,
-                  factory.createProto(conversion.getArgumentType(0, true)),
-                  "next"),
-              true));
-      instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, conversion, false));
-      instructions.add(
-          new CfInvoke(
-              Opcodes.INVOKEINTERFACE,
-              factory.createMethod(
-                  factory.collectionType,
-                  factory.createProto(factory.booleanType, factory.objectType),
-                  "add"),
-              true));
-      instructions.add(new CfGoto(loopLabel));
-
-      // return t1;
-      instructions.add(returnLabel);
-      instructions.add(frame.clone());
-      instructions.add(new CfLoad(ValueType.fromDexType(collectionType), 1));
-      instructions.add(new CfReturn(ValueType.fromDexType(collectionType)));
-
-      return standardCfCodeFromInstructions(instructions);
-    }
-  }
 }
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index c9f0ee8..3186dc1 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -89,6 +89,11 @@
     return this;
   }
 
+  public L8TestBuilder addKeepRules(String keepRule) throws IOException {
+    this.keepRules.add(keepRule);
+    return this;
+  }
+
   public L8TestBuilder addKeepRuleFile(Path keepRuleFile) throws IOException {
     this.keepRules.add(FileUtils.readTextFile(keepRuleFile, StandardCharsets.UTF_8));
     return this;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index b22d6d3..810ea37 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.TestRuntime.CfRuntime;
 import com.android.tools.r8.ToolHelper.DexVm.Kind;
 import com.android.tools.r8.benchmarks.BenchmarkResults;
+import com.android.tools.r8.desugar.desugaredlibrary.jdk11.ConversionConverter;
 import com.android.tools.r8.desugar.desugaredlibrary.jdk11.DesugaredLibraryJDK11Undesugarer;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.errors.Unreachable;
@@ -187,10 +188,13 @@
   public static final Path DESUGARED_JDK_11_LIB_JAR =
       Paths.get(OPEN_JDK_DIR + "desugar_jdk_libs_11/desugar_jdk_libs.jar");
 
+  public static Path getConvertedDesugaredLibConversions() {
+    return ConversionConverter.convertJar(DESUGAR_LIB_CONVERSIONS);
+  }
+
   public static Path getUndesugaredJdk11LibJarForTesting() {
     return DesugaredLibraryJDK11Undesugarer.undesugaredJarJDK11(
-        Paths.get("build/libs"),
-        Paths.get(OPEN_JDK_DIR + "desugar_jdk_libs_11/desugar_jdk_libs.jar"));
+        Paths.get("build/libs"), DESUGARED_JDK_11_LIB_JAR);
   }
 
   public static boolean isLocalDevelopment() {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
index 2a185ea..d303418 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
@@ -15,6 +15,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
 import com.android.tools.r8.dex.code.DexInstruction;
@@ -59,6 +60,7 @@
 
   @Test
   public void testEmulatedInterface() throws Exception {
+    new CodeInspector(ToolHelper.getConvertedDesugaredLibConversions());
     Assume.assumeTrue(libraryDesugaringSpecification.hasEmulatedInterfaceDesugaring(parameters));
     CodeInspector inspector =
         testForL8(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
index 566b0a0..e58134c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
@@ -52,7 +52,7 @@
             "JDK8_CL",
             ImmutableSet.of(
                 DESUGARED_JDK_8_LIB_JAR,
-                ToolHelper.DESUGAR_LIB_CONVERSIONS,
+                ToolHelper.getConvertedDesugaredLibConversions(),
                 ToolHelper.getCoreLambdaStubs()),
             JDK8.getSpecification(),
             ImmutableSet.of(ToolHelper.getAndroidJar(AndroidApiLevel.O)),
@@ -63,7 +63,7 @@
             "JDK11_CL",
             ImmutableSet.of(
                 ToolHelper.getUndesugaredJdk11LibJarForTesting(),
-                ToolHelper.DESUGAR_LIB_CONVERSIONS,
+                ToolHelper.getConvertedDesugaredLibConversions(),
                 ToolHelper.getCoreLambdaStubs()),
             JDK11.getSpecification(),
             ImmutableSet.of(ToolHelper.getAndroidJar(AndroidApiLevel.R)),
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
index da9064b..3afc61c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
@@ -6,13 +6,19 @@
 
 import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
 import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper.DexVm.Version;
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -64,11 +70,23 @@
         .addKeepMainRule(Executor.class)
         .noMinification()
         .compile()
+        .inspectL8(this::assertVersionUID)
         .withArt6Plus64BitsLib()
         .run(parameters.getRuntime(), Executor.class)
         .assertSuccessWithOutput(EXPECTED_RESULT);
   }
 
+  private void assertVersionUID(CodeInspector inspector) {
+    ClassSubject mapClass = inspector.clazz("j$.util.concurrent.ConcurrentHashMap");
+    if (parameters.getApiLevel().isLessThan(AndroidApiLevel.N)) {
+      assertTrue(mapClass.isPresent());
+      FieldSubject serialVersionUID = mapClass.uniqueFieldWithName("serialVersionUID");
+      assertTrue(serialVersionUID.isPresent());
+    } else {
+      assertFalse(mapClass.isPresent());
+    }
+  }
+
   @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
   static class Executor {
     public static void main(String[] args) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ChannelSetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ChannelSetTest.java
index 193507a..91549ff 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ChannelSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ChannelSetTest.java
@@ -45,7 +45,15 @@
   private final LibraryDesugaringSpecification libraryDesugaringSpecification;
   private final CompilationSpecification compilationSpecification;
 
-  private static final String EXPECTED_RESULT =
+  private static final String EXPECTED_RESULT_DESUGARING =
+      StringUtils.lines(
+          "bytes written: 11",
+          "String written: Hello World",
+          "bytes read: 11",
+          "String read: Hello World",
+          "bytes read: 11",
+          "unsupported");
+  private static final String EXPECTED_RESULT_DESUGARING_PLATFORM_FILE_SYSTEM =
       StringUtils.lines(
           "bytes written: 11",
           "String written: Hello World",
@@ -53,8 +61,9 @@
           "String read: Hello World",
           "bytes read: 11",
           "String read: Hello World",
-          "unsupported");
-  private static final String EXPECTED_RESULT_26 =
+          "bytes read: 11",
+          "String read: Hello World");
+  private static final String EXPECTED_RESULT_NO_DESUGARING =
       StringUtils.lines(
           "bytes written: 11",
           "String written: Hello World",
@@ -97,7 +106,7 @@
   }
 
   @Test
-  public void test() throws Exception {
+  public void test() throws Throwable {
     testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addProgramClasses(TestClass.class)
         .setCustomLibrarySpecification(
@@ -113,9 +122,12 @@
   }
 
   private String getExpectedResult() {
-    return parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O)
-        ? EXPECTED_RESULT_26
-        : EXPECTED_RESULT;
+    if (!libraryDesugaringSpecification.hasNioFileDesugaring(parameters)) {
+      return EXPECTED_RESULT_NO_DESUGARING;
+    }
+    return libraryDesugaringSpecification.usesPlatformFileSystem(parameters)
+        ? EXPECTED_RESULT_DESUGARING_PLATFORM_FILE_SYSTEM
+        : EXPECTED_RESULT_DESUGARING;
   }
 
   public static class CustomLib {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ConversionConverter.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ConversionConverter.java
new file mode 100644
index 0000000..5ccb580
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ConversionConverter.java
@@ -0,0 +1,161 @@
+// 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.references.Reference;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.StreamUtils;
+import com.android.tools.r8.utils.ZipUtils;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.objectweb.asm.Opcodes;
+
+public class ConversionConverter {
+
+  private static final Map<String, String> JAVA_WRAP_CONVERT_OWNER = new HashMap<>();
+  private static final Map<String, String> J$_WRAP_CONVERT_OWNER = new HashMap<>();
+
+  static {
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/spi/FileSystemProvider",
+        "java/nio/file/spi/FileSystemProvider$VivifiedWrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/spi/FileTypeDetector", "java/nio/file/spi/FileTypeDetector$VivifiedWrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/StandardOpenOption", "java/nio/file/StandardOpenOption$EnumConversion");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/LinkOption", "java/nio/file/LinkOption$EnumConversion");
+    JAVA_WRAP_CONVERT_OWNER.put("j$/nio/file/Path", "java/nio/file/Path$Wrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/WatchEvent", "java/nio/file/WatchEvent$VivifiedWrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/BasicFileAttributes",
+        "java/nio/file/attribute/BasicFileAttributes$VivifiedWrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/BasicFileAttributeView",
+        "java/nio/file/attribute/BasicFileAttributeView$VivifiedWrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/FileOwnerAttributeView",
+        "java/nio/file/attribute/FileOwnerAttributeView$VivifiedWrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/PosixFileAttributes",
+        "java/nio/file/attribute/PosixFileAttributes$VivifiedWrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/PosixFileAttributeView",
+        "java/nio/file/attribute/PosixFileAttributeView$VivifiedWrapper");
+    JAVA_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/PosixFilePermission",
+        "java/nio/file/attribute/PosixFilePermission$EnumConversion");
+
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/spi/FileSystemProvider", "java/nio/file/spi/FileSystemProvider$Wrapper");
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/spi/FileTypeDetector", "java/nio/file/spi/FileTypeDetector$Wrapper");
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/StandardOpenOption", "java/nio/file/StandardOpenOption$EnumConversion");
+    J$_WRAP_CONVERT_OWNER.put("j$/nio/file/LinkOption", "java/nio/file/LinkOption$EnumConversion");
+    J$_WRAP_CONVERT_OWNER.put("j$/nio/file/Path", "java/nio/file/Path$VivifiedWrapper");
+    J$_WRAP_CONVERT_OWNER.put("j$/nio/file/WatchEvent", "java/nio/file/WatchEvent$Wrapper");
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/BasicFileAttributes",
+        "java/nio/file/attribute/BasicFileAttributes$Wrapper");
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/BasicFileAttributeView",
+        "java/nio/file/attribute/BasicFileAttributeView$Wrapper");
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/FileOwnerAttributeView",
+        "java/nio/file/attribute/FileOwnerAttributeView$Wrapper");
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/PosixFileAttributes",
+        "java/nio/file/attribute/PosixFileAttributes$Wrapper");
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/PosixFileAttributeView",
+        "java/nio/file/attribute/PosixFileAttributeView$Wrapper");
+    J$_WRAP_CONVERT_OWNER.put(
+        "j$/nio/file/attribute/PosixFilePermission",
+        "java/nio/file/attribute/PosixFilePermission$EnumConversion");
+  }
+
+  public static Path convertJar(Path jar) {
+    String fileName = jar.getFileName().toString();
+    String newFileName =
+        fileName.substring(0, fileName.length() - ".jar".length()) + "_converted.jar";
+    Path convertedJar = jar.getParent().resolve(newFileName);
+    return internalConvert(jar, convertedJar);
+  }
+
+  private static synchronized Path internalConvert(Path jar, Path convertedJar) {
+    if (Files.exists(convertedJar)) {
+      return convertedJar;
+    }
+
+    OpenOption[] options =
+        new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING};
+    try (ZipOutputStream out =
+        new ZipOutputStream(
+            new BufferedOutputStream(Files.newOutputStream(convertedJar, options)))) {
+      new ConversionConverter().convert(jar, out);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+    return convertedJar;
+  }
+
+  private void convert(Path desugaredLibraryFiles, ZipOutputStream out) throws IOException {
+    ZipUtils.iter(
+        desugaredLibraryFiles,
+        ((entry, input) -> {
+          if (!entry.getName().endsWith(".class")) {
+            return;
+          }
+          final byte[] bytes = StreamUtils.streamToByteArrayClose(input);
+          final byte[] rewrittenBytes =
+              transformInvoke(entry.getName().substring(0, entry.getName().length() - 6), bytes);
+          ZipUtils.writeToZipStream(out, entry.getName(), rewrittenBytes, ZipEntry.STORED);
+        }));
+  }
+
+  private byte[] transformInvoke(String descriptor, byte[] bytes) {
+    return ClassFileTransformer.create(bytes, Reference.classFromDescriptor(descriptor))
+        .addMethodTransformer(getMethodTransformer())
+        .transform();
+  }
+
+  private MethodTransformer getMethodTransformer() {
+    return new MethodTransformer() {
+      @Override
+      public void visitMethodInsn(
+          int opcode, String owner, String name, String descriptor, boolean isInterface) {
+        if (opcode == Opcodes.INVOKESTATIC && name.equals("wrap_convert")) {
+          if (!JAVA_WRAP_CONVERT_OWNER.containsKey(owner)
+              || !J$_WRAP_CONVERT_OWNER.containsKey(owner)) {
+            throw new RuntimeException("Cannot transform wrap_convert method for " + owner);
+          }
+          if (owner.startsWith("java")) {
+            String newOwner = J$_WRAP_CONVERT_OWNER.get(owner);
+            super.visitMethodInsn(opcode, newOwner, "convert", descriptor, isInterface);
+            return;
+          } else if (owner.startsWith("j$")) {
+            String newOwner = JAVA_WRAP_CONVERT_OWNER.get(owner);
+            super.visitMethodInsn(opcode, newOwner, "convert", descriptor, isInterface);
+            return;
+          } else {
+            throw new RuntimeException("Cannot transform wrap_convert method for " + owner);
+          }
+        }
+        super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+      }
+    };
+  }
+}
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 e2ecec4..c9c9a31 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
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.transformers.ClassFileTransformer;
 import com.android.tools.r8.transformers.MethodTransformer;
 import com.android.tools.r8.utils.StreamUtils;
 import com.android.tools.r8.utils.ZipUtils;
@@ -74,7 +75,7 @@
   }
 
   private byte[] transformInvoke(String descriptor, byte[] bytes) {
-    return transformer(bytes, Reference.classFromDescriptor(descriptor))
+    return ClassFileTransformer.create(bytes, Reference.classFromDescriptor(descriptor))
         .addMethodTransformer(getMethodTransformer())
         .transform();
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileTypeDetectorTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileTypeDetectorTest.java
index 7848f02..c40b5c4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileTypeDetectorTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FileTypeDetectorTest.java
@@ -74,7 +74,7 @@
   }
 
   @Test
-  public void test() throws Exception {
+  public void test() throws Throwable {
     testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addInnerClasses(getClass())
         .addProgramClasses(GoogleIcon.class)
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
index 1e4a04e..673109b 100644
--- 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
@@ -12,7 +12,6 @@
 import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
 import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
 import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
@@ -39,7 +38,7 @@
 @RunWith(Parameterized.class)
 public class FilesTest extends DesugaredLibraryTestBase {
 
-  private static final String EXPECTED_RESULT =
+  private static final String EXPECTED_RESULT_DESUGARING_FILE_SYSTEM =
       StringUtils.lines(
           "bytes written: 11",
           "String written: Hello World",
@@ -50,7 +49,7 @@
           "null",
           "true",
           "unsupported");
-  private static final String EXPECTED_RESULT_24_26 =
+  private static final String EXPECTED_RESULT_DESUGARING_FILE_SYSTEM_PLATFORM_CHANNEL =
       StringUtils.lines(
           "bytes written: 11",
           "String written: Hello World",
@@ -61,7 +60,7 @@
           "null",
           "true",
           "unsupported");
-  private static final String EXPECTED_RESULT_26 =
+  private static final String EXPECTED_RESULT_PLATFORM_FILE_SYSTEM =
       StringUtils.lines(
           "bytes written: 11",
           "String written: Hello World",
@@ -100,16 +99,16 @@
   }
 
   private String getExpectedResult() {
-    if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O)) {
-      return EXPECTED_RESULT_26;
+    if (libraryDesugaringSpecification.usesPlatformFileSystem(parameters)) {
+      return EXPECTED_RESULT_PLATFORM_FILE_SYSTEM;
     }
-    return parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
-        ? EXPECTED_RESULT_24_26
-        : EXPECTED_RESULT;
+    return libraryDesugaringSpecification.hasNioChannelDesugaring(parameters)
+        ? EXPECTED_RESULT_DESUGARING_FILE_SYSTEM
+        : EXPECTED_RESULT_DESUGARING_FILE_SYSTEM_PLATFORM_CHANNEL;
   }
 
   @Test
-  public void test() throws Exception {
+  public void test() throws Throwable {
     testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
         .addInnerClasses(getClass())
         .addKeepMainRule(TestClass.class)
@@ -146,7 +145,7 @@
 
       try {
         PosixFileAttributes posixAttributes = Files.readAttributes(path, PosixFileAttributes.class);
-        if (attributes != null) {
+        if (posixAttributes != null) {
           System.out.println(
               posixAttributes.permissions().contains(PosixFilePermission.OWNER_READ));
         } else {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/PathTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/PathTest.java
index 542ac06..26e16bc 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/PathTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/PathTest.java
@@ -28,7 +28,14 @@
   private final LibraryDesugaringSpecification libraryDesugaringSpecification;
   private final CompilationSpecification compilationSpecification;
 
-  private static final String EXPECTED_RESULT = StringUtils.lines("x.txt", "dir", "dir/x.txt", "/");
+  private static final String EXPECTED_RESULT_DESUGARING =
+      StringUtils.lines(
+          "x.txt", "dir", "dir/x.txt", "/", "class j$.desugar.sun.nio.fs.DesugarLinuxFileSystem");
+  private static final String EXPECTED_RESULT_DESUGARING_PLATFORM_FILE_SYSTEM =
+      StringUtils.lines(
+          "x.txt", "dir", "dir/x.txt", "/", "class j$.nio.file.FileSystem$VivifiedWrapper");
+  private static final String EXPECTED_RESULT_NO_DESUGARING =
+      StringUtils.lines("x.txt", "dir", "dir/x.txt", "/", "class sun.nio.fs.LinuxFileSystem");
 
   @Parameters(name = "{0}, spec: {1}, {2}")
   public static List<Object[]> data() {
@@ -47,13 +54,25 @@
     this.compilationSpecification = compilationSpecification;
   }
 
+  private String getExpectedResult() {
+    if (!libraryDesugaringSpecification.hasNioFileDesugaring(parameters)) {
+      return EXPECTED_RESULT_NO_DESUGARING;
+    }
+    return libraryDesugaringSpecification.usesPlatformFileSystem(parameters)
+        ? EXPECTED_RESULT_DESUGARING_PLATFORM_FILE_SYSTEM
+        : EXPECTED_RESULT_DESUGARING;
+  }
+
   @Test
-  public void test() throws Exception {
+  public void test() throws Throwable {
     testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+        .addL8KeepRules("-keepnames class j$.desugar.sun.nio.fs.**")
+        .addL8KeepRules("-keepnames class j$.nio.file.FileSystem**")
         .addInnerClasses(PathTest.class)
         .addKeepMainRule(TestClass.class)
+        .compile()
         .run(parameters.getRuntime(), TestClass.class)
-        .assertSuccessWithOutput(EXPECTED_RESULT);
+        .assertSuccessWithOutput(getExpectedResult());
   }
 
   public static class TestClass {
@@ -67,6 +86,7 @@
       Path resolve = path2.resolve(path1);
       System.out.println(resolve);
       System.out.println(resolve.getFileSystem().getSeparator());
+      System.out.println(resolve.getFileSystem().getClass());
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11NioFileTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11NioFileTests.java
index 5cb8e57..8168e33 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11NioFileTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11NioFileTests.java
@@ -136,7 +136,6 @@
           "WatchServiceBasic",
           "WatchServiceFileTreeModifier",
           "WatchServiceDeleteInterference",
-          "WatchServiceMayFlies",
           "WatchServiceLotsOfCancels",
           "WatchServiceSensitivityModifier");
   private static final List<String> FAILING_MAIN_TESTS =
@@ -157,6 +156,7 @@
           "FilesTemporaryFiles",
           "FilesCheckPermissions",
           "FilesMisc",
+          "WatchServiceMayFlies", // Works but longest to run by far.
           "WatchServiceWithSecurityManager",
           "WatchServiceUpdateInterference",
           "WatchServiceLotsOfCloses");
@@ -272,10 +272,12 @@
             .compile()
             .withArt6Plus64BitsLib();
     int success = 0;
+    int failures = 0;
     for (String mainTestClass : SUCCESSFUL_MAIN_TESTS) {
       SingleTestRunResult<?> run = compileResult.run(parameters.getRuntime(), mainTestClass);
       if (run.getExitCode() != 0) {
         System.out.println("Main Fail " + mainTestClass);
+        failures++;
       } else {
         success++;
       }
@@ -286,6 +288,7 @@
               parameters.getRuntime(), "TestNGMainRunner", verbosity, testNGTestClass);
       if (!result.getStdOut().contains(StringUtils.lines(testNGTestClass + ": SUCCESS"))) {
         System.out.println("TestNG Fail " + testNGTestClass);
+        failures++;
       } else {
         success++;
       }
@@ -293,7 +296,9 @@
     // TODO(b/234689867): Understand and fix these issues.
     // Most issues seem to come from the missing secure.properties file. This file is not accessed
     // in all tests on all API levels, hence a different number of failures on each level.
-    assertTrue(success >= 15);
+    System.out.println("Successes :" + success + "; failures " + failures);
+    assertTrue(success >= 11);
+    assertTrue(failures <= 20);
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
index b9ca3f1..5a2c8b0 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
@@ -44,6 +44,7 @@
   private final LibraryDesugaringSpecification libraryDesugaringSpecification;
   private final CompilationSpecification compilationSpecification;
   private final TestCompilerBuilder<?, ?, ?, ? extends SingleTestRunResult<?>, ?> builder;
+  private String l8ExtraKeepRules = "";
   private Consumer<InternalOptions> l8OptionModifier = ConsumerUtils.emptyConsumer();
   private boolean l8FinalPrefixVerification = true;
 
@@ -205,6 +206,13 @@
     return this;
   }
 
+  public DesugaredLibraryTestBuilder<T> addL8KeepRules(String keepRules) {
+    if (compilationSpecification.isL8Shrink()) {
+      l8ExtraKeepRules += keepRules + "\n";
+    }
+    return this;
+  }
+
   public DesugaredLibraryTestBuilder<T> addKeepClassAndMembersRules(Class<?>... clazz) {
     withR8TestBuilder(b -> b.addKeepClassAndMembersRules(clazz));
     return this;
@@ -348,7 +356,7 @@
     L8TestCompileResult nonShrunk =
         test.testForL8(parameters.getApiLevel(), Backend.CF)
             .apply(libraryDesugaringSpecification::configureL8TestBuilder)
-            .apply(this::configure)
+            .apply(b -> configure(b, Backend.CF))
             .compile();
     String keepRules =
         collectKeepRulesWithTraceReferences(compile.writeToZip(), nonShrunk.writeToZip());
@@ -362,13 +370,16 @@
             b ->
                 libraryDesugaringSpecification.configureL8TestBuilder(
                     b, compilationSpecification.isL8Shrink(), keepRule))
-        .apply(this::configure)
+        .apply(b -> configure(b, parameters.getBackend()))
         .compile();
   }
 
-  private void configure(L8TestBuilder l8Builder) {
+  private void configure(L8TestBuilder l8Builder, Backend backend) {
     l8Builder
         .applyIf(!l8FinalPrefixVerification, L8TestBuilder::ignoreFinalPrefixVerification)
+        .applyIf(
+            compilationSpecification.isL8Shrink() && !backend.isCf() && !l8ExtraKeepRules.isEmpty(),
+            b -> b.addKeepRules(l8ExtraKeepRules))
         .addOptionsModifier(l8OptionModifier);
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
index 539ad9a..d0b9e66 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.L8TestBuilder;
 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.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -152,7 +153,7 @@
       Descriptor descriptor) {
     this(
         name,
-        ImmutableSet.of(desugarJdkLibs, ToolHelper.DESUGAR_LIB_CONVERSIONS),
+        ImmutableSet.of(desugarJdkLibs, ToolHelper.getConvertedDesugaredLibConversions()),
         Paths.get("src/library_desugar/" + specificationPath),
         ImmutableSet.of(ToolHelper.getAndroidJar(androidJarLevel)),
         descriptor,
@@ -254,6 +255,14 @@
     return parameters.getApiLevel().getLevel() < descriptor.getNioFileDesugaring();
   }
 
+  public boolean hasNioChannelDesugaring(TestParameters parameters) {
+    return hasNioFileDesugaring(parameters) && parameters.getApiLevel().getLevel() < 24;
+  }
+
+  public boolean usesPlatformFileSystem(TestParameters parameters) {
+    return parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V8_1_0);
+  }
+
   public boolean hasAnyDesugaring(TestParameters parameters) {
     return hasAnyDesugaring(parameters.getApiLevel());
   }