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
NoSuchMethodException due to OkHttpChannelProvider default constructor missing after R8 full mode optimization #9611
Comments
So it keeps the class and methods (because the interface methods are used), but it doesn't have any way to construct the class. We've taken the approach of "don't use any Proguard configuration" because it is hard to get used in all environments and have a configuration that is precise for all environments. We want to inform the optimizer via code that stuff is used, because that code may be eliminated. But this behavior from R8 should also break using ManagedChannelBuilder.forTarget() and similar APIs. We'd need to keep the init for all NameResolvers, LoadBalancers, and ManagedChannelProviders. But apparently you didn't... So I guess it saw the META-INF/services/ and recognized those classes needed default constructors? More investigation is needed here. |
The A good amount of grpc (OkHttp Android client) communication seems to work for me without further R8/Proguard configuration than what's referenced in this issue, I don't currently use LoadBalancer stuff AFAIK. I did encounter some intermittent issues in my cursory exploration runs today, but they may or may not be related. I'm not sure if I'll find more time to investigate before next month. Android has default Proguard/R8 configuration files that are commonly used and that I rely on, and there is additional Proguard configuration coming from other libraries I use, and some of my own. Any of these could lead to an unexpected smooth operation of those things. Slapping an explicit |
I've given up on R8 full mode for now; grpc things seemed to work well for me, though, with that one added rule. I got hung up on other hard-to-debug problems. R8 full mode seemed to work for me in the past here and there, but it seems to have moved beyond real world usability. Or the other way round. |
Seems we won't be doing anything here for the moment. Things have changed since we did grpc-android initially; we have a much better understanding of how Cronet fits into things. It might be better to add a direct dependency from grpc-android to grpc-okhttp and reference OkHttpChannelProvider directly instead of reflection. But that's this one case; there are probably other problems that would also need resolving (e.g., all the provider registries). |
@ejona86 Agreed. What you say about avoiding reflection with OkHttpChannelProvider sounds like it would make sense independent of this issue. Reflection is still unusually expensive on Android even today I believe. |
This will likely need revisiting soon, as R8 full mode is becoming the default: https://youtu.be/WZ1A7aoEHSw?t=554 |
Well, I slept better for 3 weeks. |
@bubenheimer, I tried to reproduce what you are seeing using the gRPC I do see Would you happen to have a project I could use to reproduce the problem? |
@temawi what's your R8 version? I print it with my my builds like this:
Reason I'm asking: not sure that current R8 still prints that message in full mode, it's not experimental anymore. I didn't always have this problem in R8 full mode, so you may not see it with an older R8 version. The R8 from Android Studio Giraffe alpha 2 is 8.1.8-dev. The R8 from the latest stable Android Studio (Electric Eel) (AGP 7.4.0) is 4.0.48, I was using nothing more recent than that, so it should suffice for your repro. The client likely needs to be Android, and use OkHttp. I don't have a public project of my own to repro this. |
I expect the R8/toolchain version was just too old. We have been needing to update for a while now. android-interop-testing doesn't use AndroidChannelBuilder. But it does load (indirectly) OkHttpChannelBuilder with reflection. And both use the same reflection methods ( |
Yes, I also understood that that android-interop-testing would use |
In my attempt to reproduce this I upgraded all of grpc-java Android projects to use the 7.4.0 version of the Android Gradle plugin. This introduces a newer R8 that does full mode by default as well as moves us to building with Java 11. I did now see some extra stuff being removed by R8 in android-interop-testing that I had to instruct R8 to keep, but I still did not see the original problem with @bubenheimer, since I don't feel there's anything else I can do on this front I'll go ahead and close this issue. Feel free to open it back up if you still have a problem after these changes and if you can provide a way to reproduce the problem. |
One clarification - 7.4.0 does NOT enable R8 full mode by default. I tested this by adding android.enableR8.fullMode=true to my local gradle.properties. |
Thank you, @temawi. Just to clarify: you explicitly set android.enableR8.fullMode=true and did not see the OkHttpChannelProvider issue? |
I was able to repro it with the helloWorld Android client (AGP 7.4.2). I had to add the grpc-android dependency, and use AndroidChannelBuilder instead of ManagedChannelBuilder, that's the key. Also, for R8 config, add "-shrinkunusedprotofields" to proguard-rules.pro to have R8 do the right magic for protos. Enable full mode, of course. You may need to rework that project a little to get it to run in a current Android Studio environment, I think some of the project config is too old. That would be very helpful for Android users anyway. Also, I noticed that building android-interop-testing seems to require some secret config that is not checked in. At a minimum, |
What version of gRPC-Java are you using?
1.49.2
What is your environment?
Android
What did you see?
When run after R8 full mode optimization, grpc throws an exception during execution:
Failed to construct OkHttpChannelProvider
This is because R8 full mode does not implicitly keep default constructors:
https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md#r8-full-mode
This Proguard/R8 configuration rule avoids the issue and should be added to https://github.com/grpc/grpc-java/blob/master/android/proguard-rules.txt:
There may be additional configuration rules needed to take care of further default constructors accessed via reflection.
The text was updated successfully, but these errors were encountered: