[Android] GameActivity soLoadLibrary Ordering

Hey there!

I noticed a documentation discrepancy in the UnrealPluginLanguage that seems to be introduced in UE 5.0 (still affects 5.7). `soLoadLibrary` should load the library before libUnreal.so but it appears that it’s loaded after. Is this intended? As an SDK author the order may be relevant.

Providing a bit of context, We are trying to fix the problem described in https://developer.android.com/ndk/guides/jni\-tips\#faq:\-why\-didnt\-findclass\-find\-my\-class where the wrong class loader is used on a background thread that’s attached to the JVM. Initially, we wanted to fix this by caching the application class loader in our own JNI_OnLoad. Currently, our plugin adds our SDK static libraries to PublicAdditionalLibraries with the build system merging them into libUnreal.so. This results in a duplicate symbol linker error as UnrealEngine already defines it.

The cleanest fix is to build our library as an .so instead of .a such that it’s packaged in the apk separately; libUnreal and libSdk.so both have their own JNI_OnLoad symbols. However, this would require quite a bit of work to change our build and publishing pipeline.

Hoping to avoid that, we chose to expose a new API that should be called before making any SDK API calls. This API calls across the JNI so we need to load the necessary native symbols beforehand. The problem is that on Android, we can have multiple components serve as an entry point to our app (e.g. BroadcastReceiver that is registered to respond to a notifications Intent) which may bypass GameActivity, meaning we have to load libUnreal ourselves.

  1. Can you confirm that this doesn’t violate any assumptions made by the engine?
  2. This is where the ordering kind of matters; if we subclass GameApplication and load libUnreal.so there (so it’s handled for all entry points), this invalidates what soLoadLibrary is intended for. If we still want to load a library before libUnreal.so, we have to do it in our Application class (see code snippet).
  3. Do you have any recommendations as to which direction to take here? Any other things to consider?
https://github.com/EpicGames/UnrealEngine/blob/4.18/Engine/Source/Programs/UnrealBuildTool/System/UnrealPluginLanguage.cs

* 	<!-- optional libraries to load in GameActivity.java before libUE4.so -->
	 * 	<soLoadLibrary>	</soLoadLibrary>

https://github.com/EpicGames/UnrealEngine/blob/4.18/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java

static
	{
		System.loadLibrary("gnustl_shared");
//$${soLoadLibrary}$$
		System.loadLibrary("UE4");
	}

https://github.com/EpicGames/UnrealEngine/blob/5.0/Engine/Source/Programs/UnrealBuildTool/System/UnrealPluginLanguage.cs
* 	<!-- optional libraries to load in GameActivity.java before libUnreal.so -->
	 * 	<soLoadLibrary>	</soLoadLibrary>

https://github.com/EpicGames/UnrealEngine/blob/5.0/Engine/Build/Android/Java/src/com/epicgames/unreal/GameActivity.java.template
static
	{
		System.loadLibrary("Unreal");
//$${soLoadLibrary}$$
		System.loadLibrary("c++_shared");
	}


// Example integration
package com.ea.nimble.unreal.android.exampleapp;

import com.epicgames.unreal.GameApplication;
import com.my.package;

import android.util.Log;

public class DemoApplication extends GameApplication
{
    @Override
    public void onCreate()
    {
        super.onCreate();
        MySdk.notifyApplicationCreated(getApplicationContext());
        Log.d("DemoApplication", "Application created");
    }

    static {
        // If I want to load something before libUnreal.so, it has to happen here.
        System.loadLibrary("Unreal");
    }
}

[Attachment Removed]

Steps to Reproduce
[Attachment Removed]

Hi Ramkumar,

Thanks for pointing out the documentation discrepancy.

Regarding your issue, if you build libSdk.so and have libUnreal.so link against, it should get detected as an SO dependency and added to $${gameApplicationEarlyLoadAdditions}$$ which loads the Librares in GameApplication prior to libUnreal.so in GameActivity.

Best regards.

[Attachment Removed]

Hey [Content removed]

Thanks for pointing that out! I do have a follow up though. Our SDK is separated into multiple modules, at the moment, they are distributed as static libs: libSdkModuleA.a, libSdkModuleB.a, libSdkModuleC.a

Module A defines foundational SDK types that are used across all other modules, it’s also the module where we would ideally export our own JNI_OnLoad.

My understanding is that with UE 5.3, “libc++_shared.so is no longer included in .apk packages on Android by default, as Unreal Engine no longer supports any dynamic libs built against libc++_shared.so.”

I’m considering the following approaches:

Distribute all of our modules as shared libraries: (libSdkModuleA.so, libSdkModuleB.so, libSdkModuleC.so)

  1. Consumer is responsible for library load order
  2. Consumer is responsible for only packaging what they use (as opposed to the linker stripping all unused symbols)
  3. Every library statically links to the C++ runtime

Distribute A as a shared library only (libSdkModuleA.so, libSdkModuleB.a, libSdkModuleC.a).

  1. libUnreal would contain the symbols from B and C and a runtime dependency on A. A would be statically linked with the C++ runtime. As far as I understand, this is dangerous as types defined in A will be used in the API signatures in B and C. Crossing the library boundary is likely to crash.

Keeping everything as a .a

  1. Linker only includes the symbols that are actually used
  2. Uses the C++ runtime that libUnreal.so linked with (gracefully handles pre 5.3 behavior as well)
  3. The one con is that libUnreal.so contains everything, so even if we only need A’s symbols, we need to load Unreal.

Overall, we prefer the last approach.

My question: Is it safe to load libUnreal.so in a subclass of GameApplication before it’s supposed to be loaded in GameActivity. Any insights into the pros and cons of the above approaches would be appreciated as well!

Thanks :slight_smile:

[Attachment Removed]

Hi Ramkumar,

It should be safe to load libUnreal.so early as you propose as long as it is loaded after its dependencies in GameApplication. The additional loadLibrary call from GameActivity should be ignored thereafter as it would already be loaded. However, if linking libUnreal.so against the the SDK .so, you shouldn’t need the UPL soLoadLibrary addition.

Best regards.

[Attachment Removed]