Status Update
Comments
aa...@google.com <aa...@google.com>
je...@google.com <je...@google.com> #2
I can reproduce this (thanks for the repro project!)
It looks like the problem is that the desugared api list from r8 contains this entry:
java/util/Collection#removeIf(Ljava/util/function/Predicate;)Z
but the bytecode here doesn't match -- it's java/util/ArrayList. Collection isn't a directly implemented interface or a direct super class, it's an interface on the super super class. The most efficient thing runtime wise would be for the signature list to inline this method on all implemented subclasses. But I should probably at least for now go and make the desugared API lookup do something similar to what it does for API lookup -- search through all super classes and interfaces as well. This isn't a new problem, so I'm very surprised this hasn't come up before (or it has, and I've forgotten).
mi...@google.com <mi...@google.com> #3
(I have a pending CL that was working to improve the handling of fields now that r8 handles desugaring fields, I'll try to dust that off and combine the fix in there.)
se...@exaring.de <se...@exaring.de> #4
I went to implement this, and hooked up inheritance search when analyzing the source file containing the call.
However, lint also handles the case where the library being analyzed is not using core library desugaring (for example, it may be a plain Java library). But when that library is consumed in a downstream app module, where library desugaring is turned on, lint then processes the partial results from the library and filters each violation through the desugaring allowlist.
At this point, it's tricky to do the inheritance search -- this happens when we no longer have a compilation environment and can do class inheritance lookups. So there are three possible solutions.
First, we pay the cost up front -- even when you're not using core library desugaring, we record whether the method is potentially library desugared if turned on. (This is also tricky because at this point we don't know which exact desugaring library version is used, which determines the exact list of APIs).
Or, more expensively, for every API violation of this type we store all the potential super class and interface names for each result...
Or, we handle this in the code which generates the desugaring API list, inlining all subclasses affected. This could be quite a long list, but on the other hand this list is really only intended to be machine readable.
mi...@google.com <mi...@google.com>
se...@exaring.de <se...@exaring.de> #5
This is partially fixed now; it's fully fixed for the sample project, but in the scenario I described in comment 4, it works if you also configure library desugaring to be on in the library.
se...@exaring.de <se...@exaring.de> #6
likely related:
Objects.requireNonNullElse
Objects.requireNonNullElseGet
are now also showing this same false positive warning.
Android Studio Koala | 2023.3.2 Canary 2 gradle 8.6 plugin: 8.3.1
hu...@google.com <hu...@google.com> #7
This seems unrelated. Can you file a new bug?
Specifically, for Objects.requireNonNullElse
I am not seeing a lint API error, but I am seeing a warning from IntelliJ's built-in Java inspections. These should probably not show up in Android modules. I swear we've fixed that before but I'm assuming something changed to break that.
For Objects.requireNonNullElseGet
I do see a lint API warning for that. But, that's not a recent change, right? I looked at R8's desugaring list and that method is not there. So that method does crash at runtime, right?
mi...@google.com <mi...@google.com>
hu...@google.com <hu...@google.com> #8
Can you file a new bug?
fair enough - will do.
I swear we've fixed that before but I'm assuming something changed to break that.
I'm not 100% sure whether it first occurred when I moved to 8.3.1, and/or to Koala Canary 2
So that method does crash at runtime, right?
funnily enough no, even when I run on Android 8.0 (in the emulator); In fact I seem to have been using that method for 2 years now and the first of those 2 years I ran it personally on a physical device (Samsung A5 2017 with Android 8.0 / other users on?) ... and yes, I am flabbergasted as well :)
I'll try and dig a little regarding the requireNonNullElseGet first as indeed I realise it should crash, and then will file a new bug (as requireNonNullElse should work regardless)
I'll add a reference here for your enjoyment :)
an...@google.com <an...@google.com> #9
Actually it looks like D8 is really backporting it; I wrote this test class:
public class JavaTest {
public void test(String s) {
Objects.requireNonNullElse(s, "test");
Objects.requireNonNullElseGet(s, new Supplier<String>() {
@Override
public String get() {
return null;
}
});
}
}
Built the APK and opened the APK analyzer, drilled to this method and invoked Show Bytecode and here's what I get:
# virtual methods
.method public test(Ljava/lang/String;)V
.registers 3
.param p1, "s" # Ljava/lang/String;
.line 8
const-string v0, "test"
invoke-static {p1, v0}, Lcom/example/myapplication/JavaTest$$ExternalSyntheticBackport0;->m(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
.line 9
new-instance v0, Lcom/example/myapplication/JavaTest$1;
invoke-direct {v0, p0}, Lcom/example/myapplication/JavaTest$1;-><init>(Lcom/example/myapplication/JavaTest;)V
invoke-static {p1, v0}, Lcom/example/myapplication/JavaTest$$ExternalSyntheticBackport1;->m(Ljava/lang/Object;Ljava/util/function/Supplier;)Ljava/lang/Object;
.line 15
return-void
.end method
So both methods are desugared.
Clement/Søren, I don't see this in the backport list:
$ java -cp $ANDROID_HOME/cmdline-tools/latest/lib/r8.jar com.android.tools.r8.BackportedMethodList --min-api 15 | grep requireNonNullElse
java/util/Objects#requireNonNullElse(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
(requireNonNullElse
is there, requireNonNullElseGet
is not.)
Description
Note: This is a bug in the Android Gradle Plugin, but I am not allowed to create an issue in the Android Gradle Plugin component.
ISSUE:
The
AidlCompile
Android Gradle Plugin task is rarely, and completly randomly, failing with the exceptionIndexOutOfBoundsException: Index 0 out of bounds for length 0
. See also the below stacktrace.Re-runing the same Gradle command, with the same input, always resolves this issue. Sometime we have to re-run multiple times though.
Because this issue appears randomly, and for a while now, it is hard for us to pinpoint the exact versions when this issue first appeared.
Currently we use APG 8.2.0 with Gradle 8.5 and build-tools 34.0.0.
We experience this issue only on our CI where all builds are running inside a separate docker container, and are therefore de-facto clean builds. However we are re-using the Gradle build-cache across our different stages. But the Gradle daemon is alwas spawned anew.
We only have one AIDL file, which is only in the sourceset of our
AndroidTV
flavor:app/src/androidtv/aidl/com/example/FunInterface.aidl
. And our project has a lot of app variants. There are two buildTypes (debug, release) and four product flavor dimensions (one dimension isplatform
whereAndroidTV
is one of the flavors).Even though we enabled AIDL compilation for all variants it only fails when running
assembleAndroidTV...Release
for theAndroidTV
flavor.From what I understand the cause for this issue is that the AIDL output files are seemingly empty. However, after the job failed there is one valid Java file inside
app/build/generated/aidl_source_output_dir/androidtvInternalStandaloneProdRelease/out/com/example/FunInterface.java
.STEPS TO REPRODUCE:
The build failure happens randomly and rarely, therefore I am not able to provide neither steps to reproduce nor an explicit repro-sample project.
VERSIONS:
Version of Gradle Plugin: 8.2.0
Version of Gradle: 8.5
Version of Java: OpenJDK 64-Bit Temurin-17.0.8+7
OS: Ubuntu 22.04.2 LTS