Android bundle and nativeLibraryDir returned by getMainSharedObject()

I’m have build my app using SDL 2.0.8 to app bundle format and publish it to google play for internal testing where bundletool creates different apks automatically.

The proc getMainSharedObject does not changed after SDL 2.0.8 (I’ve checked last sources and I see it)
protected String getMainSharedObject() {
String library;
String[] libraries = SDLActivity.mSingleton.getLibraries();
if (libraries.length > 0) {
library = “lib” + libraries[libraries.length - 1] + “.so”;
} else {
library = “libmain.so”;
}
//return library;
// http://hg.libsdl.org/SDL/rev/d9e69bf4c6d4
return getContext().getApplicationInfo().nativeLibraryDir + “/” + library;
}

After installing and starting app it crashes and i see logs

D:\Repos\Projects\DotLines\proj.android>call adb -s 1bc4e471 logcat   | findstr /i sdl
07-23 17:51:50.938 10407 10407 V SDL     : Device: beryllium
07-23 17:51:50.938 10407 10407 V SDL     : Model: POCOPHONE F1
07-23 17:51:50.938 10407 10407 V SDL     : onCreate()
07-23 17:51:50.944 10407 10407 D SDL     : Relinker library load success: c++_shared
07-23 17:51:50.946 10407 10407 D SDL     : Relinker library load success: SDL2
07-23 17:51:50.949 10407 10407 D SDL     : Relinker library load success: SDL2_image
07-23 17:51:50.954 10407 10407 D SDL     : Relinker library load success: main
07-23 17:51:50.972 10407 10407 V SDL     : onResume()
07-23 17:51:50.975 10407 10407 D SDL     : onResume MainActivity()
07-23 17:51:50.975 10407 10407 D SDL     : signInSilently()
07-23 17:51:51.016 10407 10407 V SDL     : surfaceCreated()
07-23 17:51:51.016 10407 10407 V SDL     : surfaceChanged()
07-23 17:51:51.016 10407 10407 V SDL     : pixel format RGB_565
07-23 17:51:51.018 10407 10407 V SDL     : Window size: 1080x2026
07-23 17:51:51.020 10407 10464 V SDL     : Running main function SDL_main from library /data/app/org.akk0rdsdk.dotlines-Ziozq08gee58-ie5RaPGBA==/lib/arm64/libmain.so
07-23 17:51:51.021 10407 10464 E SDL     : nativeRunMain(): Couldn't load library /data/app/org.akk0rdsdk.dotlines-Ziozq08gee58-ie5RaPGBA==/lib/arm64/libmain.so
07-23 17:51:51.021 10407 10464 V SDL     : Finished main function
07-23 17:51:51.084 10407 10407 V SDL     : onWindowFocusChanged(): true
07-23 17:51:51.087 10407 10407 V SDL     : onPause()
07-23 17:51:51.123 10407 10407 V SDL     : onWindowFocusChanged(): false
07-23 17:51:51.133 10407 10407 V SDL     : surfaceDestroyed()
07-23 17:51:51.709 10407 10407 D SDL     : signInSilently(): success
07-23 17:51:51.709 10407 10407 D SDL     : onConnected(): connected to Google APIs
07-23 17:51:51.858 10407 10407 V SDL     : onDestroy()

This bug becomes on android 6.0 and higher on bundle build compilated by bundleRelease command.

I found useful app https://play.google.com/store/apps/details?id=com.xh.nativelibsmonitor.app Native library monitor and what I see is that in my case libraries does not installed from apk and Relinker can find it inside apk. Because libs does not installed getMainharedObject points to the wrong place and dlopen fails.

Solution for me was returning for previous version of getMainSharedObject function in SDLActivity.java. After that loading not extracted lib from apk generated from app bundle with bundletool works fine.

/**
 * This method returns the name of the shared object with the application entry point
 * It can be overridden by derived classes.
 */
protected String getMainSharedObject() {
    String library;
    String[] libraries = SDLActivity.mSingleton.getLibraries();
    if (libraries.length > 0) {
        library = "lib" + libraries[libraries.length - 1] + ".so";
    } else {
        library = "libmain.so";
    }
    return library;
    // http://hg.libsdl.org/SDL/rev/d9e69bf4c6d4
    //return getContext().getApplicationInfo().nativeLibraryDir + "/" + library;
}

This was added to fix bug 4002 (https://bugzilla.libsdl.org/show_bug.cgi?id=4002 )
And the fix comes from Google/Android support.

Does your issue happen with all phone or only this pocophone f1 ?
Do you use bundletool manually ? What happen if you use gradle ?
Can you debug more ? Print the nativeLibraryDir for instance ?

Hello, Sylvain_Becker.

  1. My environment:
  • Gradle version 5.5.1
  • Android gradle plugin version is com.android.tools.build:gradle:3.4.2
  • android NDK is android-ndk-r19
  • compileSdkVersion = 28 property in build.gradle
  1. I do not use bundletool manually. I use gradle from command line to build my app (DotLines) into app bundle format and get app.aab output file. After that I upload this file to google play console for internal testing. By uploading Google play it automatically run bundletool on it’s environment and creates different apks from my aab.file.

  2. After that I install this app on my phone from google play on pocofone F1 with android 8.1.0. I tried to run it and got the error I said before.

  3. When I used older gradle version (4.10.1) and older android gradle plugin (‘com.android.tools.build:gradle:3.2.1’) everything was ok. But now it seems to be behavior of android build process was changed.

  4. As I posted above nativeLibraryDir returns “/data/app/org.akk0rdsdk.dotlines-Ziozq08gee58-ie5RaPGBA==/lib/arm64”, and this is the correct value I think, but this directory does not contain libs, and next I’ll say why.

  5. I installed Native Libs Monitor (I gave link before) and investigate some apps with native libs on my device. My other apps was built with apk format (not app bundle) have libs in nativeLibraryDir, but DotLines don’t; DotLines app have libs only inside apk.

  6. As far as I see the report (on screenshot I posted above) that no native library installed. Starting with Android 6.0. libs are loaded directly from APK when they’re stored without compression.

  7. Inside SDLActivity.loadLibraries I use static call to ReLinker.loadLibrary(this, libraryName) and it sucessfully find libs in all my cases.

  8. I made a conclusion, that bundleTool didn’t forget add my native libs to apk, but it make them uncompressed and libs do not extracted to filesystem from apk during installaion process;

  9. After that I tried to pass to nativeRunMain “libmain.so” without path, only library name and then I rebiult app again, upload to google play, it automatically created new apks from app bunlde format, I install it from google play and everything is ok.
    dlopen inside nativeRunMain does not return an error and app run normally. I do not know dlopen can open library from apk directly, if library name passed without fullpath or it successfully read library from memory cache after Relinker call.
    You may see my activity class that overrides some functions of SDLActivity:
    https://bitbucket.org/akk0rd87/akk0rdsdk/src/master/framework/core/android/wrapper/AkkordActivity.java

  10. If you have any questions feel free to ask me.

Hi, thanks for the very precise descriptions!

First I haven’t used the android bundle.

It would sound to be regression from (3). Or maybe, because gradle/android adds loading from uncompressed libs as new feature? Maybe this could be reported to Google…

Out of context, looking at your java activity, I think you don’t need to call relinker yourself, it’s already there in the latest SDLActivity.Java

If we revert the commit you mentioned we would fail in some case of bug 4002. But maybe you can try to patch the file:

https://hg.libsdl.org/SDL/file/bc90ce38f1e2/src/core/android/SDL_android.c#l630

So that it tries first to dlopen library_file and if it fails, it fallbacks to dlopen basename(library_file)
(Or simply by pointing to last / ).

That’s some robustness which is worth being added.

  1. I prefer to use static dependency to Relinker calls, because static calls guarantee that I will not forget to include it to my gradle dependencies list, otherwise build process fails.

  2. Ok. I should read this topic How to Patch Official SDL and I’ll try to make a patch in a few days.

I’ve created a bug https://bugzilla.libsdl.org/show_bug.cgi?id=4739 and submitted the patch.