Skip to content

5.17.0 has a crash on Android 6,NoClassDefFoundError #1662

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

Open
shn1233 opened this issue Apr 8, 2025 · 12 comments
Open

5.17.0 has a crash on Android 6,NoClassDefFoundError #1662

shn1233 opened this issue Apr 8, 2025 · 12 comments

Comments

@shn1233
Copy link

shn1233 commented Apr 8, 2025

Release 5.17.0 is out. I wanted to have a look at some other things, but time ran out, so just a small release.

Originally posted by @matthiasblaesing in #1647

Image
5.17.0 has a crash on Android 6

Can it be fixed as soon as possible? Our app is still unusable.

@dbwiddis
Copy link
Contributor

dbwiddis commented Apr 8, 2025

Can it be fixed as soon as possible?

Only if it's possible.

JNA is an open source project that is user-supported. All are welcome to contribute. Those of us who volunteer our time to help do so in our spare time, in addition to our other employment responsibilities. As you are the closest person to this crash, you may be in the best position to fix it, or at least better identify exactly what is wrong.

To fix something, it is helpful to know where the problem resides. You've given a picture of a stack trace showing an error on a particular line of code without any context on how you got there. What is the actual structure being used? Is it in your own code or another open source project where we can inspect the code? If not, I doubt that anyone reading this issue can fix this bug.

There is very little in this issue for anyone to use to attempt to fix anything.

Please give more information than your operating system. What is the rest of the stack trace? (Ideally text, not a picture.) Under what conditions does it appear? Has it occurred in all previous JNA versions or only a recent one?

@shn1233
Copy link
Author

shn1233 commented Apr 9, 2025

Can it be fixed as soon as possible?

Only if it's possible.

JNA is an open source project that is user-supported. All are welcome to contribute. Those of us who volunteer our time to help do so in our spare time, in addition to our other employment responsibilities. As you are the closest person to this crash, you may be in the best position to fix it, or at least better identify exactly what is wrong.

To fix something, it is helpful to know where the problem resides. You've given a picture of a stack trace showing an error on a particular line of code without any context on how you got there. What is the actual structure being used? Is it in your own code or another open source project where we can inspect the code? If not, I doubt that anyone reading this issue can fix this bug.

There is very little in this issue for anyone to use to attempt to fix anything.

Please give more information than your operating system. What is the rest of the stack trace? (Ideally text, not a picture.) Under what conditions does it appear? Has it occurred in all previous JNA versions or only a recent one?

Yes, this is only available in the new version 5.17.0, and it is a new submission 7 months ago. The stack is as follows:
java.lang.NoClassDefFoundError: com.sun.jna.Structure$$ExternalSyntheticLambda2 at com.sun.jna.Structure.validateFields(Structure.java:1323) at com.sun.jna.Structure.<init>(Structure.java:218) at com.sun.jna.Structure.<init>(Structure.java:211) at com.sun.jna.Structure.<init>(Structure.java:198) at com.sun.jna.Structure.<init>(Structure.java:190)
The source code is:
https://github.com/java-native-access/jna/blame/a9db983d2211eab6f073225e3b9ffa82cd00267e/src/com/sun/jna/Structure.java#L1323

Guessed reason:
Lambda expression support on Android:

Android has natively supported Java 8 Lambda since Nougat (API 24, Android 7.0).

On Android 6.0 (API 23) and below, Lambda is implemented through desugaring (Android Gradle Plugin 4.0+ and coreLibraryDesugaring are required).

However, some dynamically generated Lambdas inside JNA may not be desugared correctly, resulting in class loading failure.

Fix solution (replace Lambda writing)
Method 1: Use anonymous inner class (compatible with Android 6.0)
Rewrite Lambda expression to traditional Function anonymous implementation:

validationLock.writeLock().lock();
try {
    validationMap.computeIfAbsent(getClass(), new Function<Class<?>, Boolean>() {
        @Override
        public Boolean apply(Class<?> cls) {
            for (Field f : getFieldList()) {
                validateField(f.getName(), f.getType());
            }
            return true;
        }
    });
} finally {
    validationLock.writeLock().unlock();
}

@matthiasblaesing
Copy link
Member

From my POV this needs some more answers:

  • Why is Android 6.0 still relevant and why can't you then stay with JNA 5.15?
  • Was an issue raised against the android build system generating broken code?
  • Was the performance impact measured? Lambdas are not anonymous classes. If I remember correctly it was a conscious decision not to follow the anonymous classes variant.

@shn1233
Copy link
Author

shn1233 commented Apr 10, 2025

From my POV this needs some more answers:

  • Why is Android 6.0 still relevant and why can't you then stay with JNA 5.15?
  • Was an issue raised against the android build system generating broken code?
  • Was the performance impact measured? Lambdas are not anonymous classes. If I remember correctly it was a conscious decision not to follow the anonymous classes variant.
  1. TikTok has more than 1 billion DAU and has Android 6 users. After online testing, using 5.17.0 jna, this crashed 27,000 users/day and 54,000 crashes/day; and TikTok needs to adapt to 16kb, which is only supported by 5.17.0. Therefore, 5.17.0 needs to be used to fix this problem

  2. Source of the problem: Android 6.0's Java 7 runtime cannot directly execute Lambda bytecode.

Official fix: Compatibility is achieved through Android Studio's Core Library Desugaring. https://developer.android.com/studio/write/java8-support

Temporary solution: Manually replace with anonymous inner class.

We can choose any of the above repair methods

@dbwiddis
Copy link
Contributor

Source of the problem: Android 6.0's Java 7 runtime cannot directly execute Lambda bytecode.

We dropped support for JDK 6 and 7 in JNA 5.14.0.

Android 6.0 is EOL as of 01 Aug 2018.
JDK 7 is EOL as of July 2022.

I see 1.19% usage share for Android 6.0 as of March 2025. I guess that's the 27000 users/day.

16kb, which is only supported by 5.17.0

I'm not in favor of starting down the road of trying to revert current code to support earlier JDKs. What would be the effort involved in releasing a 5.13.1 version with the 16kb change backported?

@shn1233
Copy link
Author

shn1233 commented Apr 10, 2025

Source of the problem: Android 6.0's Java 7 runtime cannot directly execute Lambda bytecode.

We dropped support for JDK 6 and 7 in JNA 5.14.0.

Android 6.0 is EOL as of 01 Aug 2018. JDK 7 is EOL as of July 2022.

I see 1.19% usage share for Android 6.0 as of March 2025. I guess that's the 27000 users/day.

16kb, which is only supported by 5.17.0

I'm not in favor of starting down the road of trying to revert current code to support earlier JDKs. What would be the effort involved in releasing a 5.13.1 version with the 16kb change backported?

OK, this is also a good way. It is very simple to adapt to 16kb. Just add -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384, as here:

LDFLAGS+=-Wl,-shared,-Bsymbolic -Wl,--build-id=sha1 -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384

TikTok used version 5.12.1 before. There is no problem adapting to 16kb based on 5.12.1 or 5.13.1

Thank you for your patience and help~

In addition, do I need to submit the code and update the new version here, or can you help complete it?

@matthiasblaesing
Copy link
Member

You should be able to use the native binaries from JNA 5.17 together with JNA lib 5.15. The JNI interface did not change between these. You can then create your own "franken JNA" jar/aar and publish to an internal repository. Please do not publish something like that to central!

For the rest. It was already established, that this is an issue in the android built system and be fixed there. It should not fail to desugar these trivial cases.

@BugsBeGone
Copy link
Contributor

Would a more recent NDK fix the desugaring? I didn't think there was any urgency in supporting newer NDKs, but if the older ones are this broken, there is really no choice. See my suggested patch here: #1659

@matthiasblaesing
Copy link
Member

Would a more recent NDK fix the desugaring? I didn't think there was any urgency in supporting newer NDKs, but if the older ones are this broken, there is really no choice.

The desugaring is not a problem in the native code, but in the Java code. Before Android 12 the ART runtime (its role is similar to that of the JVM on other platforms, just for DEX code) could not be updated, so the VM could not be updated to support newer features. Developers for these old platforms are now forced to either not use these features or as the built system to translate the new features into a form that can be run on the old VM.

@shn1233 already mentioned, that the Android SDK is broken here, as it generates broken code when this desurgaring happens.

@BugsBeGone
Copy link
Contributor

... the Android SDK is broken here, as it generates broken code when this desurgaring happens.

The wonderful Gradle system does not in fact, just work™? I'm shocked, shocked I tell you...

Sorry for the obvious question, I really don't know much about "new" Java features, since for so long Android refused to update beyond 1.7, so I stopped paying attention to all the new toys I couldn't play with.

I would not be surprised if in part, the move to kill support for old Android versions by Google is entirely because they can/will not fix the build tools to generate bytecode that actually works everywhere. It definitely seemed to me that a large part of the 64-bit native requirement had little to with user security, and was more about the ever-closer Y2038 time_t issue.

@shn1233
Copy link
Author

shn1233 commented Apr 11, 2025

You should be able to use the native binaries from JNA 5.17 together with JNA lib 5.15. The JNI interface did not change between these. You can then create your own "franken JNA" jar/aar and publish to an internal repository. Please do not publish something like that to central!

For the rest. It was already established, that this is an issue in the android built system and be fixed there. It should not fail to desugar these trivial cases.

The native binary files in JNA 5.17 are used together with JNA lib 5.15. This approach is difficult for us and we face complex compliance issues.

  • I want to confirm whether the jar file of 5.15 does not have the problem of Android 6 lamda.

  • When will jna plan to desugar and fix the crash of Android 6? It would be better if 5.17.1 can be released as soon as possible~

@dbwiddis
Copy link
Contributor

This approach is difficult for us and we face complex compliance issues.

I would think supporting software past its EOL which is not getting security updates would be a bigger compliance issue?

When will jna plan to desugar ...

This is not JNA's responsibility, so the answer to that question is "never".

It has been clearly stated the bug is elsewhere and should be fixed elsewhere.

Some projects will offer patch releases for older/post-EOL JDK versions, but that should not be expected. Nobody should be using JDK versions before 8 at this point, and if they are, they should expect things to break. Android 6.0 has several unpatched security vulnerabilities. It is unsupported software. In my personal opinion, support for it should be terminated (for compliance reasons) and users should be required to update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants