Skip to content
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

Crash - Failed to load dynamic library 'librive_text.so' #403

Open
daniel102102 opened this issue Jun 23, 2024 · 18 comments
Open

Crash - Failed to load dynamic library 'librive_text.so' #403

daniel102102 opened this issue Jun 23, 2024 · 18 comments
Labels
bug Something isn't working

Comments

@daniel102102
Copy link

daniel102102 commented Jun 23, 2024

Hi. We are using rive for flutter.

We see a massive crash in firabse on Android 5 and Android 6, see callstack below. It happens on various devices.
librive_text.so is included in compilation for all architectures.

      Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Invalid argument(s): Failed to load dynamic library 'librive_text.so': dlopen failed: library "librive_text.so" not found
   at new DynamicLibrary.open(dart:ffi)
   at ._loadLibrary(rive_audio_ffi.dart:41)
   at .nativeLib(rive_text_ffi.dart:11)
   at .init(rive_text_ffi.dart)
   at .initFont(rive_text_ffi.dart)
   at Font.initialize(rive_text.dart:477)
   at RiveFile.initialize(rive_file.dart:383)
   at EndScreenAnimation.initializeRive(end_screen_animation.dart:15)
   at TapToZoomTutorialState._loadRiveFile(tap_to_zoom_tutorial.dart:32)
   at TapToZoomTutorialState.initState(tap_to_zoom_tutorial.dart:28)
   at StatefulElement._firstBuild(framework.dart:5618)
   at ComponentElement.mount(framework.dart:5463)
   at Element.inflateWidget(framework.dart:4340)
   at MultiChildRenderObjectElement.inflateWidget(framework.dart:6904)
   at MultiChildRenderObjectElement.mount(framework.dart:6916)
   at Element.inflateWidget(framework.dart:4340)
   at Element.updateChild(framework.dart:3849)
   at ComponentElement.performRebuild(framework.dart:5512)
   at Element.rebuild(framework.dart:5203)
   at ComponentElement._firstBuild(framework.dart:5469)
   at ComponentElement.mount(framework.dart:5463)
   at Element.inflateWidget(framework.dart:4340)
   at Element.updateChild(framework.dart:3849)
   at ComponentElement.performRebuild(framework.dart:5512)
   at Element.rebuild(framework.dart:5203)
   at ComponentElement._firstBuild(framework.dart:5469)
   at ComponentElement.mount(framework.dart:5463)
   at Element.inflateWidget(framework.dart:4340)
   at Element.updateChild(framework.dart:3849)
   at _LayoutBuilderElement._layout.layoutCallback(layout_builder.dart:155)
   at BuildOwner.buildScope(framework.dart:2845)
   at _LayoutBuilderElement._layout(layout_builder.dart:173)
   at RenderObject.invokeLayoutCallback.<fn>(object.dart:2688)
   at PipelineOwner._enableMutationsToDirtySubtrees(object.dart:1097)
   at RenderObject.invokeLayoutCallback(object.dart:2688)
   at RenderConstrainedLayoutBuilder.rebuildIfNecessary(layout_builder.dart:248)
   at _RenderLayoutBuilder.performLayout(layout_builder.dart:331)
   at RenderObject.layout(object.dart:2577)
   at MultiChildLayoutDelegate.layoutChild(custom_layout.dart:173)
   at _ScaffoldLayout.performLayout(scaffold.dart:1097)
   at MultiChildLayoutDelegate._callPerformLayout(custom_layout.dart:237)
   at RenderCustomMultiChildLayoutBox.performLayout(custom_layout.dart:404)
   at RenderObject.layout(object.dart:2577)
   at RenderProxyBoxMixin.performLayout(proxy_box.dart:105)
   at RenderObject.layout(object.dart:2577)
   at RenderProxyBoxMixin.performLayout(proxy_box.dart:105)
   at _RenderCustomClip.performLayout(proxy_box.dart:1426)
   at RenderObject.layout(object.dart:2577)
   at RenderPadding.performLayout(shifted_box.dart:239)
   at RenderObject.layout(object.dart:2577)
   at RenderProxyBoxMixin.performLayout(proxy_box.dart:105)
   at RenderObject._layoutWithoutResize(object.dart:2416)
   at PipelineOwner.flushLayout(object.dart:1051)
   at PipelineOwner.flushLayout(object.dart:1064)
   at RendererBinding.drawFrame(binding.dart:577)
   at WidgetsBinding.drawFrame(binding.dart:1138)
   at RendererBinding._handlePersistentFrameCallback(binding.dart:443)
   at SchedulerBinding._invokeFrameCallback(binding.dart:1392)
   at SchedulerBinding.handleDrawFrame(binding.dart:1313)
   at SchedulerBinding._handleDrawFrame(binding.dart:1171)
@daniel102102 daniel102102 added the bug Something isn't working label Jun 23, 2024
@HayesGordon
Copy link
Contributor

Hi @daniel102102, which version of the Rive-Flutter runtime are you using? And did this recently start after updating?

@kaptnkoala
Copy link

kaptnkoala commented Jun 24, 2024

Hi @HayesGordon, we also see this error occur in our production app after updating the rive dependency from 0.13.1 to 0.13.7 (which bumps the rive_common dependency from 0.3.3 to 0.4.9 under the hood). We did not see any problems regarding the Rive-Flutter runtime before, it recently started to occur after the mentioned update.

Like @daniel102102 mentioned this problem happens to 99% on devices running Android 6.

@HayesGordon
Copy link
Contributor

@kaptnkoala I'd just like to confirm a few things.

  • Does your Rive file contain Rive Text or Rive Audio?

  • Are you specifying a buildType or using the defaults? For example:

buildTypes {
    release {
        // other configs
        ndk {
            abiFilters 'armeabi-v7a','arm64-v8a','x86_64', 'x86'
        }
    }
}
  • Are you passing in any additional flags when building the release APK?

  • You mentioned that you verified that the release APK in production contained the .so files?

  • Which version of Flutter are you using?

One potentially relevant issue I've found is: simolus3/drift#895 (comment)

More info here: simolus3/drift#895 (comment)

We could look into doing something similar (it's a bit of a hack) but I'm unable to verify my side if this will work as I cannot reproduce the issue. Can you reproduce this issue on your end, or are you only seeing this in production?

@daniel102102
Copy link
Author

Hi @HayesGordon. We are using rive: 0.13.8 and rive_common: ^0.4.9. Massive crashes started in last days, after switching to new version. Before crash was avialble but was rare.

@HayesGordon
Copy link
Contributor

Could you please confirm if you're Rive file makes use of Rive Text or Rive Audio. Answering this is important to help me pinpoint the issue.

Could you also answer the other questions if possible.

@kaptnkoala
Copy link

kaptnkoala commented Jun 26, 2024

Hey @HayesGordon, please find the answers to your questions attached.

Does your Rive file contain Rive Text or Rive Audio?

No, in our case the affected rive files are not using Rive Text or Rive Audio?

Are you specifying a buildType or using the defaults? For example:

Yes, we are not building our app for the 'x86' architecture, so our release NDK settings look like this:

    buildTypes {
        release {
            ndk {
                abiFilters 'armeabi-v7a','arm64-v8a','x86_64'
                debugSymbolLevel 'FULL'
            }
        }
    }

Are you passing in any additional flags when building the release APK?

We only pass additional --dart-define Flags when building the release APK?

You mentioned that you verified that the release APK in production contained the .so files?

Yes, i can verify that the generated APK contains the librive_text.so in the 'lib/arm64-v8a', 'lib/armabi-v7a' and 'lib/x86_64' directories.

Which version of Flutter are you using?

We are using Flutter 3.19.6

I am not exactly sure what workaround you are suggesting, because you seemed to have referenced the same issue comment twice. We also do not have Apps at Hand here right now and can reproduce the issue, we only see it as error with high volume in our reporting tools. For the moment we have reverted back to rive 0.13.1, which mitigated the problem for the production app.

@HayesGordon
Copy link
Contributor

Thanks for the info @kaptnkoala. The other link I wanted to send was this: https://github.com/simolus3/sqlite3.dart/tree/main/sqlcipher_flutter_libs#problems-on-android-6

In older versions of Flutter, Android 6 caused issues, old documentation mentions:

If you build an App Bundle Edit android/gradle.properties and add the flag: android.bundle.enableUncompressedNativeLibs=false.

If you build an APK Make sure android/app/src/AndroidManifest.xml doesn’t set android:extractNativeLibs=false in the <application> tag.

But I do not know if that is still relevant.

We can push out the same solution that sqlite3 did. It requires loading the library natively from Kotlin and then accessing it through the data directory.

I'll let you know here once that is out.

@kaptnkoala
Copy link

We have set the flag android.bundle.enableUncompressedNativeLibs=false in the android/gradle.properties and not set the android:extractNativeLibs=false Flag in AndroidManifest.

Has anything changed between version 0.13.1 and 0.13.8 how the livrive_text.so is loaded, that this problem is starting to gain track now and not in the previous version. I am not sure, if this is really the best solution to the problem. I will ping a colleague that is more familiar with the native parts of Flutter. @blaugold What do you think about this?

@HayesGordon
Copy link
Contributor

After version 0.13.1 the requirement to load in these libraries changed. Previously the native libraries were only loaded if a .riv file contained Rive Text. We optimistically checked to see if the .riv file had Rive Text in it - if not we would not initliaze the library.

But since then we've introduced more features, specifically a new layout engine, which requires Rive Flutter to always load + initialize the native library.

That is why you're seeing it now and not before.

On the Rive Android runtime we had similar issues in the past where Android has issues linking these libraries. There exists a package for Android called ReLinker which we use to ensure the libraries are linked on older devices.

This is the first/only report about Rive Flutter not working on older Android devices.

@HayesGordon
Copy link
Contributor

Link to the PR that made the change to require the libraries to always be loaded: a22fc5f

@centy
Copy link

centy commented Jun 26, 2024

Have you tried https://github.com/KeepSafe/ReLinker ?

If your app includes native libraries, and your minimum SDK is below API 23 (Marshmallow), you need ReLinker.

There are a number of different bugs addressed by ReLinker; the last of these was resolved as of Marshmallow. As long as your app's min SDK is at or above it, loading libraries via System.loadLibrary("foo") is safe.

@blaugold
Copy link

blaugold commented Jul 1, 2024

We are using minSdkVersion 23, so we should not need ReLinker.

@kaptnkoala Those workarounds feel a bit hacky, but the only solution for those older Android versions. 🫠

rive-engineering pushed a commit that referenced this issue Jul 8, 2024
Refactors the library loading to reuse the same code across the different FFI modules.

Introduces a workaround for Android library loading, potentially fixing [403](#403)

Diffs=
d5ed4ca9b feat: add applyWorkaroundToRiveOnOldAndroidVersions (#7485)
1e7b1c030 add missing validations (#7532)

Co-authored-by: Gordon <[email protected]>
@HayesGordon
Copy link
Contributor

Hi all, this is now available in the latest release v0.13.11.

You can call applyWorkaroundToRiveOnOldAndroidVersions(). This is an experimental workaround for loading native libraries on Android 6. The method should be called before using any Rive APIs.

What this does is load the librive_text.so through native Kotlin code, and if Flutter fails to load the library, we use a fallback to use this already loaded version.

We were unable to reproduce the issue on our side; it may be conditional to other factors. Let us know if you implement this and if it works.

@kaptnkoala
Copy link

@HayesGordon We have just released a new version including the fix. Will keep you updated how it works out!

@kaptnkoala
Copy link

@HayesGordon We have now fully rolled out the version with your workaround and the fix seems work and resolve the problems we had on Android 6 devices. Is it possible to implement this handling in the default library opening process, so that this method does not have to be called explicitly and is handled in the _openAndroidDynamicLibraryWithFallback part?

@HayesGordon
Copy link
Contributor

Thank you for informing us @kaptnkoala, I'm glad it is resolved for you. I'll discuss this with the team. This is the only report that we have had about this, and it may be that this is an isolated incident and that some combination of the plugins or build config you have is what reproduced this. Which makes me hesitant to enable this by default.

@kaptnkoala
Copy link

At least one other user has started this issue for this. Maybe is error is only more prominent to us because our app has a user base of 1.5M DAU and we are monitoring our release apps tightly.

When you would implement this as a fallback option for the _openAndroidDynamicLibraryWithFallback method, this would only kick in when loading the library with the default approach has failed. I would not consider this as enabled by default. Some other libraries like objectbox and moor are also handling this issue under the hood.

@jacekendrick
Copy link

jacekendrick commented Sep 16, 2024

I am actually seeing this same issue on Android API 35 (brand new version, not old). 0.13.1 works fine, 0.13.13 does not

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants