objectbox-java: Crash on ObjectBox initialization. java.lang.UnsatisfiedLinkError
Issue Basics
App crashes when we initialize ObjectBox
- ObjectBox version (are using the latest version?): 2.1.0
- Reproducibility: occurs on some user devices, we could not reproduce it
Reproducing the bug
Description
We initialize the BoxStore on app start when initializing a Dagger graph. And some users experience crash from the start. Just logs in Crashlytics
Code
BoxStore boxStore = MyObjectBox.builder()
.androidContext(appContext)
.name("db_v2")
.build();
if (BuildConfig.DEBUG) {
new AndroidObjectBrowser(boxStore).start(appContext);
}
return boxStore;
Logs & stackstraces
> Fatal Exception: java.lang.UnsatisfiedLinkError
> dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.vyng.android-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libobjectbox.so"
> Fatal Exception: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.vyng.android-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libobjectbox.so"
> at java.lang.Runtime.loadLibrary(Runtime.java:366)
> at java.lang.System.loadLibrary(System.java:988)
> at io.objectbox.internal.NativeLibraryLoader.(NativeLibraryLoader.java:71)
> at io.objectbox.BoxStore.(BoxStore.java:189)
> at io.objectbox.BoxStoreBuilder.build(BoxStoreBuilder.java:352)
> at com.vyng.android.di.modules.AppModule.boxStore(AppModule.java:95)
> at com.vyng.android.di.modules.AppModule_BoxStoreFactory.proxyBoxStore(AppModule_BoxStoreFactory.java:34)
> at com.vyng.android.di.modules.AppModule_BoxStoreFactory.provideInstance(AppModule_BoxStoreFactory.java:25)
> at com.vyng.android.di.modules.AppModule_BoxStoreFactory.get(AppModule_BoxStoreFactory.java:21)
> at com.vyng.android.di.modules.AppModule_BoxStoreFactory.get(AppModule_BoxStoreFactory.java:8)
> at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
> at com.vyng.android.di.modules.AppModule_ChannelDataRepositoryFactory.provideInstance(AppModule_ChannelDataRepositoryFactory.java:152)
> at com.vyng.android.di.modules.AppModule_ChannelDataRepositoryFactory.get(AppModule_ChannelDataRepositoryFactory.java:109)
> at com.vyng.android.di.modules.AppModule_ChannelDataRepositoryFactory.get(AppModule_ChannelDataRepositoryFactory.java:26)
> at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
> at com.vyng.android.video.cache.di.CacheModule_CacheWatcherFactory.provideInstance(CacheModule_CacheWatcherFactory.java:80)
> at com.vyng.android.video.cache.di.CacheModule_CacheWatcherFactory.get(CacheModule_CacheWatcherFactory.java:58)
> at com.vyng.android.video.cache.di.CacheModule_CacheWatcherFactory.get(CacheModule_CacheWatcherFactory.java:16)
> at dagger.internal.DoubleCheck.get(DoubleCheck.java:47)
> at com.vyng.android.di.components.DaggerAppComponent.injectVyngApplication(DaggerAppComponent.java:1632)
> at com.vyng.android.di.components.DaggerAppComponent.inject(DaggerAppComponent.java:1427)
> at com.vyng.android.VyngApplication.initAppComponent(VyngApplication.java:343)
> at com.vyng.android.VyngApplication.onCreate(VyngApplication.java:137)
> at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1012)
> at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4631)
> at android.app.ActivityThread.access$1500(ActivityThread.java:151)
> at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1374)
> at android.os.Handler.dispatchMessage(Handler.java:102)
> at android.os.Looper.loop(Looper.java:135)
> at android.app.ActivityThread.main(ActivityThread.java:5348)
> at java.lang.reflect.Method.invoke(Method.java)
> at java.lang.reflect.Method.invoke(Method.java:372)
> at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:947)
> at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:742)
Entities
Not relevant.
Misc
A screenshot from Crashlytics with device manufacturers and OS versions: https://ibb.co/hb3SSq
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 4
- Comments: 86 (43 by maintainers)
Commits related to this issue
- NativeLibraryLoader: always fall back to Android if not macOS/Windows. https://github.com/objectbox/objectbox-java/issues/605 — committed to objectbox/objectbox-java by greenrobot-team 5 years ago
@shamtay cough https://objectbox.io/app-bundle-and-sideloading-how-to-prevent-crashes/ cough
Edit: latest info about this at https://docs.objectbox.io/android/app-bundle-and-split-apk.
Thanks for the update though!
OK, there is a great medium post about this which basically points to two issues:
To solve 1. the developers created their own native library loading code, based on something similar done for Chromium. It’s called ReLinker.
@greenrobot We should look into switching to this if possible.
edit: even https://developer.android.com/training/articles/perf-jni#native-libraries mentions ReLinker, but only for “older versions of Android”.
-ut
Luckily, we support Android 5+. The build is in internal testing, next week we should get data from prod.
Oops, closed the issue by a mistake. Returned it back for now.
Update to version
2.3.4~2.3.2(use2.3.3which restores Android 4.x support)~ which includes support for ReLinker. https://github.com/KeepSafe/ReLinker/ReLinker will try to load the native library normally, but if that fails tries to extract it from the APK and load it itself. We tested this “workaround loading” on an emulator and real device without issues.
By default ObjectBox will load the native library as before. To use ReLinker you need to add ReLinker to your dependencies:
implementation 'com.getkeepsafe.relinker:relinker:1.3.1'To enable debug logging for ReLinker you can pass a custom
ReLinkerInstancewhen buildingBoxStore:If this works out we will add ReLinker to the
objectbox-androiddependencies by default. So let us know if the above fixes theUnsatisfiedLinkErrors.App Bundles
If users sideload your app they may only install the base APK and not all required config APKs. Instead of detecting if all required APKs are present you can disable splitting App Bundles by ABI:
https://issuetracker.google.com/issues/111233819#comment8 https://developer.android.com/studio/projects/dynamic-delivery#disable_config_apks
Note about sideloading: “Some users sideload APKs […]. These installs can unfortunately still appear as Play installs since this data can easily be spoofed” https://issuetracker.google.com/issues/111233819#comment12
ProGuard
If you are using ProGuard make sure to add a rule to keep ReLinker classes and methods as ObjectBox only accesses them via reflection:
-keep class com.getkeepsafe.relinker.** { *; }Multidex
If you are using multidex make sure that ReLinker and ObjectBox are in the primary dex file. E.g. add a file with the above rule and then configure it as
multiDexKeepProguard:https://developer.android.com/studio/build/multidex#keep
-Uwe
@abdurahmanadilovic, thanks for pointing the article. I’ve heard about such issue previously. But it looks like it’s not the case because the issue happens on armv7 and armv8 devices too, for example here are some from top: Samsung SM-J200G (arm-v7) Samsung SM-J210F (arm-v7) Samsung SM-G610F (arm-v8) Micromax Q402+ (arm-v7) Micromax Q409 Xiaomi MI MAX Xiaomi Redmi Note 4
And other phones from these manufacturers, Motorola, Lenovo…
Here is an updated screenshot with manufacturers: https://ibb.co/ngwk9f
@greenrobot-team, I’ve checked the release build, it contains all 4 variants that you’ve mentioned. We use Android App Bundles to ship the build, I’ll recheck the config too.
However, not all the users on that phones have this problem. We have much more of them who don’t crash. If the problem would be in the way how we configure a build, all of them should start crashing, shouldn’t they?
And we have some test devices that are in the list of models experiencing crashes but we don’t have that issue. As I remember, we got such logs from our tester only once, but reinstallation helped in that case, so we couldn’t check what actually happened.
Worked well, no crash report after using this method. I didn’t checked Google official way!
In addition to the suggestions in https://github.com/objectbox/objectbox-java/issues/605#issuecomment-460539359 here is a code snippet on how to guard the
build()call and display an activity with an info message (e.g. to direct the user to download from Google Play, report the error, etc.):I tested this also with our example. See https://github.com/objectbox/objectbox-examples/commit/e3af09d91181eea11db8959ceddf360f7b35a602 Keep in mind that you may need additional guards in your app if you use ObjectBox in your Application class or other places before the error activity is shown.
-Uwe
Update: Use the official solution from Google instead to detect incorrect app installations when using App Bundles. https://developer.android.com/guide/app-bundle/sideload-check
Original: Potential workaround for App Bundles: apparently you can configure App Bundles to not split by ABI. This is also suggested by one of the Google engineers as an alternative to detecting if all required split APKs are present. https://issuetracker.google.com/issues/111233819#comment8 https://developer.android.com/studio/projects/dynamic-delivery#disable_config_apks
Quote about sideloading: “Some users sideload APKs and only install the base APK without the config splits. These installs can unfortunately still appear as Play installs since this data can easily be spoofed” https://issuetracker.google.com/issues/111233819#comment12
Edit: updated https://github.com/objectbox/objectbox-java/issues/605#issuecomment-460539359.
-Uwe
@cknight OK, so it is a multidex issue.
Try to declare the ObjectBox and ReLinker classes as required in the primary DEX file. https://developer.android.com/studio/build/multidex#keep
Note: As your minSdkVersion is 21 there is no need to use
implementation 'androidx.multidex:multidex:2.0.1'andMultiDexApplication. JustmultiDexEnabled trueis enough. https://developer.android.com/studio/build/multidex#mdex-gradleEdit: again updated the instructions with hints for multidex. https://github.com/objectbox/objectbox-java/issues/605#issuecomment-460539359
-Uwe
First crash on 2.3.4 (with relinker), Nexus 5X, rooted, Android 6.0.1:
Unfortunately, the problem still appears on different OS versions, including Android 7.
7.0 Galaxy S6 Edge 7.1.2 Redmi Y1 5.1.1 Lenovo K5 6.0.1 SM-G610F
I’m also seeing this issue. Below are stack traces and devices for ObjectBox v2.3.3 and v2.1.0.
Here’s a stacktrace from a Nexus 5X (Android 6.0.1), OB v2.3.3:
And a Defy Mini (Android 5.0.2), OB v2.1.0:
And a Google Pixel (Android 9), OB v2.1.0:
And a SM-J600G (Android 8.0), OB v2.1.0:
Same issue of @Gaket And this is from a Google Device, a Nexus 6P @greenrobot-team
@greenrobot-team, yes, I’ve checked the manifest of the prod apk and it is there. We use bundles but I don’t think there should be any difference in Android Manifest.
This issue has 10,358 crashes affecting 3,376 users in the last month. All the Android versions, mostly, Android 5.
https://ibb.co/DCsz2rn
We will try to check the theory about unsupported architectures.
Thank you, next release is in ~2 weeks. Will get back to you with results.
вс, 30 дек. 2018 г. в 13:21, Markus Junginger notifications@github.com: