Status Update
Comments
rk...@google.com <rk...@google.com>
tn...@google.com <tn...@google.com> #2
The d8 corelibrary desugaring database from D8 (
$ egrep -n "(AsynchronousFileChannel|FileSystem$)" desugared_apis_30_1.txt
20:java/nio/channels/AsynchronousFileChannel
47:java/nio/file/FileSystem
Søren, is this this intended to be handled? If not, should we leave it out of the backport list, or, just handle this with a custom check in lint?
Full repro based on description:
package test.pkg;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
public class NioTest {
public void test() {
Path path = new File("").toPath();
try(AsynchronousFileChannel open = AsynchronousFileChannel.open(path)) {
open.read(ByteBuffer.allocate(1024), 1024);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
an...@steadfastinnovation.com <an...@steadfastinnovation.com> #3
In addition to having lint errors based on minSdk
for any APIs that are intentionally not supported on lower API levels, it would also be helpful if there were lint warnings for APIs that have "potentially behavior-changing modifications" as described in the java.nio
customizations
sg...@google.com <sg...@google.com> #4
Clément can you take a look at how to best handle this? Looking in the configuration file
"api_level_below_or_equal": 25,
"rewrite_prefix": {
"java.io.DesugarFile": "j$.io.DesugarFile",
"java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
"java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
"java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
"java.nio.channels.Desugar": "j$.nio.channels.Desugar",
"java.nio.file.": "j$.nio.file."
},
all of java.nio.channels.AsynchronousChannel
is supported, so it is in the java.lang.UnsupportedOperationException
.
What will be the best way to inform lint that some methods on java.nio.channels.AsynchronousFileChannel
are not supported? Also are there other API's than explicitly using AsynchronousFileChannel.open
which can cause this?
tn...@google.com <tn...@google.com> #5
I looked at the DAC pages that the submitter linked to (thanks!) and yeah it looks like quite a bit of special casing here; I'm not sure simply leaving them out of the backport list and getting API warnings would be the best way to handle this either, so instead I've written a special lint check for this (ag/30645290) which handles what I see mentioned in those notes. Clément, take a look and see whether I've understood correctly which APIs those notes are referring to and whether the error messages makes sense (it should be clearest from the unit tests).
One other thing I saw is that for the following code:
fun setGroup(path: Path, newGroup: GroupPrincipal): Path? = Files.setOwner(path, newGroup)
I'm getting this warning, even with core library desugaring on:
Implicit cast from
GroupPrincipalto
UserPrincipal requires API level 26 (current min is 24)
.
And indeed it looks like both GroupPrincipal and UserPrincipal are not included in the backport API list -- even though when I inspect the compiled dex code, it looks like D8 actually did migrate this code (e.g. the bytecode for the above setGroup method looks like this:
.method public static final setGroup(Lj$/nio/file/Path;Lj$/nio/file/attribute/GroupPrincipal;)Lj$/nio/file/Path;
.registers 3
.param p0, "path" # Lj$/nio/file/Path;
.param p1, "newGroup" # Lj$/nio/file/attribute/GroupPrincipal;
const-string v0, "path"
move-object v0, p1
check-cast v0, Lj$/nio/file/attribute/UserPrincipal;
invoke-static {p0, v0}, Lj$/nio/file/Files;->setOwner(Lj$/nio/file/Path;Lj$/nio/file/attribute/UserPrincipal;)Lj$/nio/file/Path;
move-result-object v0
return-object v0
.end method
I see the cast here is to j$/nio/file/attribute/UserPrincipal
rather than java/nio/file/attribute/UserPrincipal
so it looks like D8 is handling it, so is the backport database wrong?
P.S. Here's the current unit test output from that check since the code isn't visible externally until it's submitted:
src/test/pkg/NioTest.java:16: Error: Using AsynchronousFileChannel is not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
try(AsynchronousFileChannel open = AsynchronousFileChannel.open(path)) { // ERROR 1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/NioTest.java:17: Error: Using AsynchronousFileChannel is not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
open.read(ByteBuffer.allocate(1024), 1024); // ERROR 2
~~~~~~~~~
src/test/pkg/NioTest.java:24: Error: Using a WatchService is not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
fileSystem.newWatchService().poll(); // ERROR 3
~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/NioTest.java:28: Error: POSIX file features are not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
fileSystem.getUserPrincipalLookupService(); // ERROR 4
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/NioTest.java:32: Error: Creating links is not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
fileSystem.provider().createLink(p1, p2); // ERROR 5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/NioTest.java:33: Error: Creating links is not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
fileSystem.provider().createSymbolicLink(p1, p2); // ERROR 6
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/NioTest.java:43: Error: When using core library desugaring on API levels lower than 26, file operations sometimes raise java.io.FileNotFoundException instead of java.nio.file.NoSuchFileException when a file is not found. They are both subclasses of java.io.IOException, so the issue can be mitigated by catching java.io.IOException instead. [NioDesugaring]
} catch (java.nio.file.NoSuchFileException e) { // ERROR 7
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:25: Error: POSIX file features are not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
val newPermissions = PosixFilePermissions.fromString("rwxr-xr-x") // ERROR 8
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:26: Error: POSIX file features are not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
Files.setPosixFilePermissions(path, newPermissions) // ERROR 9
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:29: Error: POSIX file features are not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
val lookupService = path.fileSystem.userPrincipalLookupService // ERROR 10
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:30: Error: POSIX file features are not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
val newOwner = lookupService.lookupPrincipalByName("new_owner_username") // ERROR 11
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:36: Error: POSIX file features are not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
val newGroup: GroupPrincipal = lookupService.lookupPrincipalByGroupName("new_group_name") // ERROR 12
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:46: Error: POSIX file features are not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
val permissions = PosixFilePermissions.asFileAttribute( // ERROR 13
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:63: Error: Option SPARSE is ignored by core library desugaring on API levels lower than 26 [NioDesugaring]
val channel2 = FileChannel.open(path, SPARSE) // ERROR 14
~~~~~~
src/test/pkg/test.kt:65: Error: Using AsynchronousFileChannel is not supported by core library desugaring on API levels lower than 26 [NioDesugaring]
val channel4 = AsynchronousFileChannel.open(path, SPARSE) // ERROR 15
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:56: Warning: With core library desugaring on API levels lower than 26, file copy with the COPY_ATTRIBUTES option does not copy attributes, though it is usually not important to copy basic attributes [NioDesugaring]
Files.copy(path, destination, StandardCopyOption.COPY_ATTRIBUTES) // WARNING 1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/test/pkg/test.kt:64: Warning: With core library desugaring on API levels lower than 26, DELETE_ON_CLOSE is only partially supported; the file is only closed when FileChannel is closed [NioDesugaring]
val channel3 = FileChannel.open(path, DELETE_ON_CLOSE) // WARNING 2
~~~~~~~~~~~~~~~
15 errors, 2 warnings
tn...@google.com <tn...@google.com> #6
This lint check has been integrated now and should show up in a canary soon.
an...@google.com <an...@google.com> #7
Thank you for your patience while our engineering team worked to resolve this issue. A fix for this issue is now available in:
- Android Studio Meerkat | 2024.3.1 Canary 5
- Android Gradle Plugin 8.9.0-alpha05
We encourage you to try the latest update.
If you notice further issues or have questions, please file a new bug report.
Thank you for taking the time to submit feedback — we really appreciate it!
Description
java.nio
APIs can be used below API 26 withcoreLibraryDesugaring "com.android.tools:desugar_jdk_libs_nio:2.1.3"
. However, as described in thejava.nio
customizations documentationFor example, running the following on API 21 produces a
java.lang.UnsupportedOperationException
:This is expected per the documentation, but is not discoverable except at runtime.
However, when using
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.3"
(the non-nio artifact), usages of this API (and all otherjava.nio
APIs) produce lint errors unless wrapped in checks for API 26+.Is it possible to show lint errors just for the APIs that will fail at runtime when they're not wrapped in API checks for API 26+ when using
desugar_jdk_libs_nio
? That way the build will fail rather than discovering this at runtime.