Skip to content

MethodHandle.invoke and MethodHandle.invokeExact are only supported starting with Android O (--min-api 26) #7769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
2 tasks done
JordanLongstaff opened this issue Apr 9, 2025 · 8 comments · Fixed by #7770
Assignees
Labels
P1 type=defect Bug, not working as expected
Milestone

Comments

@JordanLongstaff
Copy link

Guava Version

33.4.7-jre

Description

The latest version of Guava uses MethodHandle which is only available in Android API 26 or later. My app supports API 21 at the minimum, and it uses the latest release of Guava to patch a security vulnerability, only now it won't build because Guava uses methods that are not supported in the minimum SDK version. And I have no desire to increase it in my app.

Example

Any Android app with minimum SDK version lower than 26, using the latest version of Guava, would suffice. Here's a PR build from my repo that failed:
https://github.com/JordanLongstaff/ArtemisAgent/actions/runs/14347309233/job/40219434611?pr=189

Expected Behavior

App should still build as normal.

Actual Behavior

App cannot build because of MethodHandle. See the link in the example for more info.

Packages

No response

Platforms

Android

Checklist

  • I agree to follow the code of conduct.

  • I can reproduce the bug with the latest version of Guava available.

@JordanLongstaff JordanLongstaff added the type=defect Bug, not working as expected label Apr 9, 2025
@cpovirk
Copy link
Member

cpovirk commented Apr 9, 2025

Sorry, our internal toolchain must handle things differently, as we're able to build for minSdkVersion 21 there. (We should ideally set up an external test for this.) Thanks for the fast report of this. I'll look when I start work in an hour or two.

@cpovirk cpovirk added the P1 label Apr 9, 2025
@cpovirk cpovirk self-assigned this Apr 9, 2025
@cpovirk
Copy link
Member

cpovirk commented Apr 9, 2025

I haven't gotten the build running locally yet, though I made a little progress:

/tmp/tmp.wPQ8gN60RZ/ArtemisAgent/keystore.properties (No such file or directory)

So:

printf '%s=X\n' keyAlias keyPassword storePassword storeFile > keystore.properties

But now:

* What went wrong:
A problem occurred configuring project ':IAN:annotations:konsist'.
> Failed to apply plugin 'org.gradle.software-reporting-tasks'.
   > Could not create task ':IAN:annotations:konsist:outgoingVariants'.
      > Could not create task of type 'OutgoingVariantsReportTask'.
         > Could not create an instance of type org.gradle.api.tasks.diagnostics.internal.configurations.ConfigurationReportsImpl.
            > Could not create an instance of type org.gradle.api.reporting.internal.DefaultReportContainer.
               > Type T not present

[edit: This might have been a problem running with JDK 24, specifically in combination with Kotlin (rather than Groovy)?]

But a search got me to a PR for another Android app, which also has the problem, as you'd pointed out. I can reproduce the problem there with JAVA_HOME=$HOME/.m2/jdks/jdk-17.0.13+11 ANDROID_HOME=$HOME/android-sdk-linux ./gradlew build, so I'll iterate with that.

As for what I'll do about this: I might just forget about using VarHandle from guava-android, instead making the code try AtomicReferenceFieldUpdater before Unsafe on the JVM. But I'll see what else I can figure out....

@cpovirk
Copy link
Member

cpovirk commented Apr 9, 2025

Hmm, maybe this is only an issue before AGP 7.4: http://issuetracker.google.com/issues/174733673#comment12?

But no, the app I'm testing with is using 8.3.1: https://github.com/mathisdt/trackworktime/blob/7f38ecc8c0b1f0eb396fec94b47e1ca0cae6b085/build.gradle#L9.

http://issuetracker.google.com/issues/174733673#comment13 suggests that the issue is fixed at the compiler level but needs a change in the plugin itself: http://issuetracker.google.com/issues/320207221.

copybara-service bot pushed a commit that referenced this issue Apr 9, 2025
…android` runs under a JVM.

For much more discussion, see the code comments, especially in the backport copy of `AbstractFutureState`.

I've also updated the tests to better reflect which ones we run only under a JVM, not in an Android emulator. (I should really have done that back in cl/742859752.)

Fixes #7769

RELNOTES=`util.concurrent`: Removed our `VarHandle` code from `guava-android`. While the code was never used at runtime under Android, it was causing [problems under the Android Gradle Plugin](#7769) with a `minSdkVersion` below 26. To continue to avoid `sun.misc.Unsafe` under the JVM, `guava-android` will now always use `AtomicReferenceFieldUpdater` when run there.
PiperOrigin-RevId: 745575600
@cpovirk
Copy link
Member

cpovirk commented Apr 9, 2025

I have to run my change through some further testing (both in our monorepo and against one of the AGP projects), but I expect to be able to submit it later today and hopefully even get a new release out soon after.

@cpovirk cpovirk added this to the 33.4.8 milestone Apr 9, 2025
copybara-service bot pushed a commit that referenced this issue Apr 9, 2025
…android` runs under a JVM.

For much more discussion, see the code comments, especially in the backport copy of `AbstractFutureState`. (For a bit more on performance, see https://shipilev.net/blog/2015/faster-atomic-fu/, including its notes that `Unsafe` is not necessarily faster than `AtomicReferenceFieldUpdater`.)

Now that we no longer use `VarHandle` under Android, we can remove some Proguard rules for it:
- We no longer need the `-dontwarn` rule for `VarHandleAtomicHelper`, since that type no longer exists in `guava-android`.
- We no longer need the `-assumevalues` rule for `mightBeAndroid`, since it served only to strip the `VarHandle` code (to hide it from optimizers that run on the optimized code). And all else being equal, we'd rather _not_ have that rule _just in case_ someone is running `guava-android` through an optimizer and using it under the JVM (in which case we'd like to follow the JVM code path so that we don't try to use `Unsafe`).

I've also updated the tests to better reflect which ones we run only under a JVM, not in an Android emulator. (I should really have done that back in cl/742859752.)

Fixes #7769

RELNOTES=`util.concurrent`: Removed our `VarHandle` code from `guava-android`. While the code was never used at runtime under Android, it was causing [problems under the Android Gradle Plugin](#7769) with a `minSdkVersion` below 26. To continue to avoid `sun.misc.Unsafe` under the JVM, `guava-android` will now always use `AtomicReferenceFieldUpdater` when run there.
PiperOrigin-RevId: 745575600
@cpovirk
Copy link
Member

cpovirk commented Apr 9, 2025

My testing against the AGP project suggests that the fix works, and I've gotten the internal code review that I need for submission. I am still waiting for the internal testing, which won't be done for at least a few hours more. Still, barring surprises, I should be able to publish a release with the fix early in my work day tomorrow.

@cpovirk
Copy link
Member

cpovirk commented Apr 10, 2025

There's been some trouble with the internal testing system, which has affected my multiple attempts to test my change yesterday. The owners of the system have been looking into it. I assume that it will get resolved enough that I can submit my change on Monday.

cpovirk added a commit that referenced this issue Apr 10, 2025
This detects the problem of #7769.

To actually merge this, I'd want to:

- Make it work with the version of Gradle we already use, 8.5, or else
  upgrade the somewhat-standard version of Gradle that's used across a
  handful of Google project, including ours.

- Integrate it into our CI and release processes, including testing with
  the version that we're building, as [in our Gradle integration tests
  for our module
  metadata](https://github.com/google/guava/blob/97c96e00bd8940b45399979cbd4162d3ef362532/integration-tests/gradle/build.gradle.kts#L1).

- Maybe put some patterns into `.gitignore`, as possibly I should have
  along with the previous Gradle integraiotn tests?
cpovirk added a commit that referenced this issue Apr 11, 2025
This detects the problem of #7769.

To actually merge this, I'd want to:

- Make it work with the version of Gradle we already use, 8.5, or else
  upgrade the somewhat-standard version of Gradle that's used across a
  handful of Google project, including ours.

- Integrate it into our CI and release processes, including testing with
  the version that we're building, as [in our Gradle integration tests
  for our module
  metadata](https://github.com/google/guava/blob/97c96e00bd8940b45399979cbd4162d3ef362532/integration-tests/gradle/build.gradle.kts#L1).

- Put some patterns into a `.gitignore` file here, similar to [what we
  already have for the previous Gradle integration
  tests](https://github.com/google/guava/blob/master/integration-tests/gradle/.gitignore).
@JordanLongstaff
Copy link
Author

@cpovirk Just wanted to say, I greatly appreciate your efforts and your transparency in trying to fix this. 👍

copybara-service bot pushed a commit that referenced this issue Apr 12, 2025
…android` runs under a JVM.

For much more discussion, see the code comments, especially in the backport copy of `AbstractFutureState`. (For a bit more on performance, see https://shipilev.net/blog/2015/faster-atomic-fu/, including its notes that `Unsafe` is not necessarily faster than `AtomicReferenceFieldUpdater`.)

Now that we no longer use `VarHandle` under Android, we can remove some Proguard rules for it:
- We no longer need the `-dontwarn` rule for `VarHandleAtomicHelper`, since that type no longer exists in `guava-android`.
- We no longer need the `-assumevalues` rule for `mightBeAndroid`, since it served only to strip the `VarHandle` code (to hide it from optimizers that run on the optimized code). And all else being equal, we'd rather _not_ have that rule _just in case_ someone is running `guava-android` through an optimizer and using it under the JVM (in which case we'd like to follow the JVM code path so that we don't try to use `Unsafe`). (OK, maybe it would be nice to keep the rule just so that Android doesn't have to perform a check of the `java.runtime.name` system property once during `AbstractFutureState` initialization. If anyone finds this to be an issue, please let us know.)

I've also updated the tests to better reflect which ones we run only under a JVM, not in an Android emulator. (I should really have done that back in cl/742859752.)

Fixes #7769

RELNOTES=`util.concurrent`: Removed our `VarHandle` code from `guava-android`. While the code was never used at runtime under Android, it was causing [problems under the Android Gradle Plugin](#7769) with a `minSdkVersion` below 26. To continue to avoid `sun.misc.Unsafe` under the JVM, `guava-android` will now always use `AtomicReferenceFieldUpdater` when run there.
PiperOrigin-RevId: 745575600
@cpovirk
Copy link
Member

cpovirk commented Apr 14, 2025

I published Guava 33.4.8 (release notes, Maven Central) with the fix. May this be the conclusion to the last problem with this series of releases :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P1 type=defect Bug, not working as expected
Projects
None yet
2 participants