godot icon indicating copy to clipboard operation
godot copied to clipboard

C#: Fallback to CoreCLR/MonoVM hosting APIs when hostfxr/NativeAOT fails

Open raulsntos opened this issue 1 year ago • 8 comments

Some platforms don't support hostfxr but we can use the coreclr/monosgen library directly to initialize the runtime.

Android exports now use the android runtime identifier instead of linux-bionic, this removes the restrictions we previously had:

  • Adds support for all Android architectures (arm32, arm64, x32, and x64), previously only the 64-bit architectures were supported.
  • Loads System.Security.Cryptography.Native.Android (the .NET library that binds to the Android OS crypto functions).
    • Fixes https://github.com/godotengine/godot/issues/84559.

raulsntos avatar Feb 25 '24 06:02 raulsntos

@raulsntos We'll need to create a separate mono flavor for the app module that includes the mono dependencies.

The addition of that flavor means we'll be able to guard mono specific logic in the java code by checking for the flavor:

if (BuildConfig.FLAVOR.equals("mono")) {
    // load mono library
}

This will also result in the creation of additional build templates specifically for the mono builds. @akien-mga we'll need to update the build tools logic for the mono build templates.

m4gr3d avatar Mar 28 '24 17:03 m4gr3d

Could you explain what this means and how long to wait for corrections, and then review?

Zamir7 avatar Apr 27 '24 18:04 Zamir7

@Zamir7 As explained in the PR description, this adds support for 32-bit Android architectures and Android OS APIs (mainly crypto, see the linked issue) to C# projects.

This PR is marked as a draft, which means it's still a work-in-progress. It is tentatively planned for 4.4 (as you can see in the assigned milestone).

raulsntos avatar Apr 28 '24 00:04 raulsntos

There's one more set of changes that'll be needed to support gradle builds.

export_plugin uses the assemble command for the gradle builds, so that logic will need to be updated to use assembleStandard on standard builds and assembleMono on mono builds.

The crypto jar file will also need to be copied to the build directory after it's downloaded. Alternatively if you know the path where it'll be downloaded, then app/build.gradlecan be updated to look in that path in addition to the path it's checking now.

m4gr3d avatar Apr 30 '24 14:04 m4gr3d

The crypto jar file will also need to be copied to the build directory after it's downloaded. Alternatively if you know the path where it'll be downloaded, then app/build.gradle can be updated to look in that path in addition to the path it's checking now.

It should be copied because this file is retrieved when building the .NET project and it's stored in a temporary directory that will be deleted after the export. We can copy it as part of the ExportPlugin implementation, but I'd need a way to get the path to the gradle build directory as well as a way to detect if the export is part of a gradle build.

It looks like I can check if it's a gradle build with get_option("gradle_build/use_gradle_build"), and then use add_shared_object to copy the .jar file. It copies it to the res://android/libs/{BUILD_TYPE}/{ARCH} directory which I assume is enough for it to be included in the gradle build.

raulsntos avatar May 01 '24 04:05 raulsntos

The crypto jar file will also need to be copied to the build directory after it's downloaded. Alternatively if you know the path where it'll be downloaded, then app/build.gradle can be updated to look in that path in addition to the path it's checking now.

It should be copied because this file is retrieved when building the .NET project and it's stored in a temporary directory that will be deleted after the export. We can copy it as part of the ExportPlugin implementation, but I'd need a way to get the path to the gradle build directory as well as a way to detect if the export is part of a gradle build.

It looks like I can check if it's a gradle build with get_option("gradle_build/use_gradle_build"), and then use add_shared_object to copy the .jar file. It copies it to the res://android/libs/{BUILD_TYPE}/{ARCH} directory which I assume is enough for it to be included in the gradle build.

Yes that should work! EditorExportPlugin#_get_android_libraries(...) is another option as well, as that method only gets invoked by the gradle build.

This option however doesn't copy the jar file, so your current approach may be preferrable.

m4gr3d avatar May 07 '24 10:05 m4gr3d

EditorExportPlugin#_get_android_libraries(...) is another option as well, as that method only gets invoked by the gradle build.

This option however doesn't copy the jar file, so your current approach may be preferrable.

Yeah, I think the current approach is preferable, because the _get_android_libraries requires the jar to be inside res:// which won't be the case.

I did have to modify the app/build.gradle to include .jar files in subdirectories because the files added with add_shared_objects require specifying the architecture and it will include them under a directory with the name of the specified architecture.

https://github.com/godotengine/godot/blob/7b15f3b768eb088b5893579e70511fd21724e69a/platform/android/java/app/build.gradle#L45-L47

raulsntos avatar May 13 '24 15:05 raulsntos

I am currently experiencing an issue with C # using HTTPS and SignalR in godot4.3 byte1, which involves all of my data related content. Is this bug related to SSL? Is there a fixed and usable version available now? Or other methods, thank you.

bestvcboy avatar Jun 18 '24 07:06 bestvcboy

Is there something missing to merge this?

felipejfc avatar Aug 23 '24 23:08 felipejfc

Thanks for the interest in this PR. This is a pretty big change for C# Android exports, so I'd like to be cautious. Testing is appreciated, here's a custom build of the editor you can use to test it:

:checkered_flag: Windows :apple: macOS :penguin: Linux
Editor x86_64 Editor universal Editor x86_64
Editor x86_32 Editor x86_32

And the Android templates you'll need to use to export:

:robot: Android
Templates

raulsntos avatar Aug 29 '24 15:08 raulsntos

Can verify this PR indeed fixed the linked issue on my device

https://github.com/user-attachments/assets/b9800224-607f-4c92-88ba-8432d443130e

Delsin-Yu avatar Aug 29 '24 17:08 Delsin-Yu

Cryptography works as well.

https://github.com/user-attachments/assets/e698e886-76f7-46a0-9f3a-63113b677917

image

Delsin-Yu avatar Aug 31 '24 11:08 Delsin-Yu

I also confirm that this build solves the problem with connecting to MySQl, thank you very much for the work done!

Zamir7 avatar Sep 01 '24 22:09 Zamir7

Thank you everyone for testing. If you could, please also share what was the host OS (the device from where you are exporting the game), the target architectures when exporting the APK, the architecture of the Android device (or emulator) where you run the built APK, and whether you used a gradle build.

Just want to confirm that it's tested in a wide variety of Android devices of different architectures (arm32, arm64, x82, x64). I'm also curious about the usability of the .NET Android workload, hence why I ask about the host OS. I expect Windows users to have no issues here, but I wonder about other OSs.

raulsntos avatar Sep 01 '24 23:09 raulsntos

My device info: Host OS: Harmony OS 4.2.0 / Android Target Arch: aarch64 (arm64) Supported ABI: arm64-v8a armeabi-v7a armeabi CPU: kirin9000s Android Version: Android 12 Snow Cone (API31) GMS Support: false

Delsin-Yu avatar Sep 02 '24 07:09 Delsin-Yu

Hit a crash here building my project with the binaries and template you shared @raulsntos:

Editor OS: OS X (M3/ARM) Target device aarch64 (Google Pixel 6a) Android 15 Target .net 8.0

I do have native android and ios plugins enabled. The iOS one was built with 4.3 headers, would this cause problem?

Stack trace:

09-02 18:56:46.601 22286 22404 E godot   : USER ERROR: hostfxr_initialize_for_dotnet_command_line failed with code: -2147450745
09-02 18:56:46.601 22286 22404 E godot   :    at: initialize_hostfxr_self_contained (modules/mono/mono_gd/gd_mono.cpp:328)
09-02 18:56:46.601 22286 22404 E godot   : USER ERROR: Parameter "load_assembly_and_get_function_pointer" is null.
09-02 18:56:46.601 22286 22404 E godot   :    at: initialize_hostfxr_and_godot_plugins (modules/mono/mono_gd/gd_mono.cpp:395)
09-02 18:56:46.601 22286 22404 E godot   : USER ERROR: Parameter "godot_plugins_initialize" is null.
09-02 18:56:46.601 22286 22404 E godot   :    at: initialize (modules/mono/mono_gd/gd_mono.cpp:536)
09-02 18:56:46.644   549   549 W gralloc4: Unable to set buffer name SurfaceView[com.godot.example/com.godot.game.GodotApp]#1(BLAST Consumer)1: File name too long
09-02 18:56:46.647   549   549 W gralloc4: Unable to set buffer name SurfaceView[com.godot.example/com.godot.game.GodotApp]#1(BLAST Consumer)1: File name too long
09-02 18:56:46.648   549   549 W gralloc4: Unable to set buffer name SurfaceView[com.godot.example/com.godot.game.GodotApp]#1(BLAST Consumer)1: File name too long
09-02 18:56:46.657 22286 22404 F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 22404 (VkThread), pid 22286 (m.godot.example)

09-02 18:56:47.015 22473 22473 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-02 18:56:47.015 22473 22473 F DEBUG   : Build fingerprint: 'google/bluejay_beta/bluejay:15/AP31.240617.015/12207491:user/release-keys'
09-02 18:56:47.015 22473 22473 F DEBUG   : Revision: 'MP1.0'
09-02 18:56:47.015 22473 22473 F DEBUG   : ABI: 'arm64'
09-02 18:56:47.015 22473 22473 F DEBUG   : Timestamp: 2024-09-02 18:56:46.780680780-0300
09-02 18:56:47.015 22473 22473 F DEBUG   : Process uptime: 2s
09-02 18:56:47.015 22473 22473 F DEBUG   : Cmdline: com.godot.example
09-02 18:56:47.015 22473 22473 F DEBUG   : pid: 22286, tid: 22404, name: VkThread  >>> com.godot.example <<<
09-02 18:56:47.015 22473 22473 F DEBUG   : uid: 10379
09-02 18:56:47.015 22473 22473 F DEBUG   : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
09-02 18:56:47.015 22473 22473 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000000
09-02 18:56:47.015 22473 22473 F DEBUG   : Cause: null pointer dereference
09-02 18:56:47.015 22473 22473 F DEBUG   :     x0  b4000076213efb20  x1  00000072ece5d3d0  x2  0000000000000000  x3  0000000000000010
09-02 18:56:47.015 22473 22473 F DEBUG   :     x4  0000000000000037  x5  8000000000800000  x6  ff6160713fff7364  x7  7f7f7f7f7f7f7f7f
09-02 18:56:47.015 22473 22473 F DEBUG   :     x8  0000000000000000  x9  b4000074913b6170  x10 000000000000000a  x11 0000000000000000
09-02 18:56:47.015 22473 22473 F DEBUG   :     x12 b4000074715af7f0  x13 b4000074c178d020  x14 800260800000073b  x15 0000000000000000
09-02 18:56:47.015 22473 22473 F DEBUG   :     x16 00000073807162a0  x17 00000076d8478080  x18 00000072ec84c000  x19 b4000076213efb20
09-02 18:56:47.015 22473 22473 F DEBUG   :     x20 00000072ece5ea80  x21 00000072fa05a800  x22 0000000000000001  x23 b40000746143e1e8
09-02 18:56:47.015 22473 22473 F DEBUG   :     x24 b4000076213efb20  x25 b40000746143e1e8  x26 00000072ece5ea80  x27 0000000000000000
09-02 18:56:47.015 22473 22473 F DEBUG   :     x28 00000072fa06b000  x29 00000072ece5d400
09-02 18:56:47.015 22473 22473 F DEBUG   :     lr  00000072f74b7b74  sp  00000072ece5d3b0  pc  0000000000000000  pst 0000000060001000
09-02 18:56:47.015 22473 22473 F DEBUG   : 29 total frames
09-02 18:56:47.015 22473 22473 F DEBUG   : backtrace:
09-02 18:56:47.015 22473 22473 F DEBUG   :       #00 pc 0000000000000000  <unknown>
09-02 18:56:47.015 22473 22473 F DEBUG   :       #01 pc 0000000001458b70  /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk!libgodot_android.so (offset 0xa80000)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #02 pc 0000000001459e6c  /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk!libgodot_android.so (offset 0xa80000)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #03 pc 0000000003853650  /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk!libgodot_android.so (offset 0xa80000)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #04 pc 0000000003853ec8  /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk!libgodot_android.so (offset 0xa80000)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #05 pc 0000000003855418  /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk!libgodot_android.so (offset 0xa80000)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #06 pc 00000000038555b4  /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk!libgodot_android.so (offset 0xa80000)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #07 pc 0000000000f23640  /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk!libgodot_android.so (offset 0xa80000)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #08 pc 0000000000eec2bc  /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk!libgodot_android.so (offset 0xa80000) (Java_org_godotengine_godot_GodotLib_step+172)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #09 pc 0000000000378f70  /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #10 pc 0000000000362a40  /apex/com.android.art/lib64/libart.so (art_quick_invoke_static_stub+640) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #11 pc 000000000035bd94  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+2048) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #12 pc 000000000076df08  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+12208) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #13 pc 000000000037b5d8  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #14 pc 0000000000110a44  [anon:dalvik-classes5.dex extracted in memory from /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk] (org.godotengine.godot.vulkan.VkRenderer.onVkDrawFrame+0)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #15 pc 000000000034e21c  /apex/com.android.art/lib64/libart.so (art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.__uniq.112435418011751916792819755956732575238.llvm.2845697060370838518)+428) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #16 pc 000000000035c5b0  /apex/com.android.art/lib64/libart.so (bool art::interpreter::DoCall<false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, bool, art::JValue*)+4124) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #17 pc 000000000076df08  /apex/com.android.art/lib64/libart.so (void art::interpreter::ExecuteSwitchImplCpp<false>(art::interpreter::SwitchImplContext*)+12208) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #18 pc 000000000037b5d8  /apex/com.android.art/lib64/libart.so (ExecuteSwitchImplAsm+8) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #19 pc 00000000001111f4  [anon:dalvik-classes5.dex extracted in memory from /data/app/~~2zH5GIXjYyB7gNeoXrW8Mw==/com.godot.example-S3lOFmMDdHq6Tv8w5K95DQ==/base.apk] (org.godotengine.godot.vulkan.VkThread.run+0)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #20 pc 000000000034d5a8  /apex/com.android.art/lib64/libart.so (artQuickToInterpreterBridge+1932) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #21 pc 0000000000379098  /apex/com.android.art/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #22 pc 0000000000362774  /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #23 pc 000000000034def0  /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+132) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #24 pc 0000000000943da8  /apex/com.android.art/lib64/libart.so (art::detail::ShortyTraits<(char)86>::Type art::ArtMethod::InvokeInstance<(char)86>(art::Thread*, art::ObjPtr<art::mirror::Object>, art::detail::ShortyTraits<>::Type...)+60) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #25 pc 000000000063eb68  /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+1344) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #26 pc 000000000063e618  /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallbackWithUffdGc(void*)+8) (BuildId: 7300f6c36a74cc43266451736b120528)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #27 pc 000000000006f718  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+200) (BuildId: a923caae2e75861e7a06a23f740068a5)
09-02 18:56:47.015 22473 22473 F DEBUG   :       #28 pc 0000000000060e00  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: a923caae2e75861e7a06a23f740068a5)

felipejfc avatar Sep 02 '24 22:09 felipejfc

@felipejfc Thanks for testing. From that stack trace, it looks like it's trying to use hostfxr to initialize the .NET runtime which shouldn't be possible since the Android export shouldn't contain libhostfxr.so. Can you share the csproj and the APK?

I'd like to see the csproj so I can check if there's anything that could affect the publish process. For example, something like UseMonoRuntime or PublishAot.

And I'd like to see the APK to check what native libraries were included in the lib directory, specifically I'd expect to see libmonosgen-2.0.so there. You can check yourself opening the APK in Android Studio.

I do have native android and ios plugins enabled. The iOS one was built with 4.3 headers, would this cause problem?

I don't think so. It looks like the error is caused by failing to initialize the .NET runtime, not sure what may be causing it. I'd like to see what native libraries are included in the APK. And, if libmonosgen-2.0 is missing, we'd need to investigate why that's the case.

raulsntos avatar Sep 02 '24 22:09 raulsntos

@felipejfc Thanks for testing. From that stack trace, it looks like it's trying to use hostfxr to initialize the .NET runtime which shouldn't be possible since the Android export shouldn't contain libhostfxr.so. Can you share the csproj and the APK?

I'd like to see the csproj so I can check if there's anything that could affect the publish process. For example, something like UseMonoRuntime or PublishAot.

And I'd like to see the APK to check what native libraries were included in the lib directory, specifically I'd expect to see libmonosgen-2.0.so there. You can check yourself opening the APK in Android Studio.

I do have native android and ios plugins enabled. The iOS one was built with 4.3 headers, would this cause problem?

I don't think so. It looks like the error is caused by failing to initialize the .NET runtime, not sure what may be causing it. I'd like to see what native libraries are included in the APK. And, if libmonosgen-2.0 is missing, we'd need to investigate why that's the case.

Sadly I can't share the whole files since this is a private company project, however, I can provide all info you asked for:

<Project Sdk="Godot.NET.Sdk/4.4.0-android-monovm">
  <PropertyGroup>
    <EnableAot>false</EnableAot>
    <EnableAot Condition="'$(GodotTargetPlatform)' == 'ios'">true</EnableAot>
    <PublishAotUsingRuntimePack>$(EnableAot)</PublishAotUsingRuntimePack>
    <PublishAot Condition=" ('$(NETCoreSdkRuntimeIdentifier)' == 'linux-x64' or $(NETCoreSdkRuntimeIdentifier.StartsWith('osx')) ) and ('$(GodotTargetPlatform)' == 'ios' or '$(GodotTargetPlatform)' == 'android') and '$(EnableAot)' == 'true' ">true</PublishAot>
    <TargetFramework>net8.0</TargetFramework>
    <EnableDynamicLoading>true</EnableDynamicLoading>
    <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
    <RootNamespace>RoyalMetagameGodot</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <!-- Root the assemblies to avoid trimming. -->
    <PackageReference Include="Google.Protobuf" Version="3.27.3" />
    <PackageReference Include="UniTask" Version="2.5.5" />
    <TrimmerRootAssembly Include="GodotSharp" />
    <TrimmerRootAssembly Include="$(TargetName)" />
    <!-- Add reference to the source generator project -->
    <ProjectReference Include="sourcegenerator/SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
    <ProjectReference Include="./sharedtypes/sharedtypes.csproj" />
  </ItemGroup>
  <ItemGroup>
    <Compile Remove="sourcegenerator/**/*.cs" />
    <Compile Remove="sharedtypes/**/*.cs" />
  </ItemGroup>
  <Target Name="WarnIfAndroidWithoutAot" BeforeTargets="Build">
    <Warning Text="AOT is not being used in the generated APK. AOT for Android is only supported when building from macOS or Linux. Current Host RuntimeIdentifier: $(NETCoreSdkRuntimeIdentifier)" Condition="'$(GodotTargetPlatform)' == 'android' and '$(EnableAot)' == 'true' and !('$(NETCoreSdkRuntimeIdentifier)' == 'linux-x64' or $(NETCoreSdkRuntimeIdentifier.StartsWith('osx')))" />
  </Target>
  <Import Project="android.targets" />
</Project>%

This is the content of android.targets:

<Project>
  <PropertyGroup>
    <_NdkSysrootAbi Condition=" '$(RuntimeIdentifier)' == 'linux-bionic-arm64' or '$(RuntimeIdentifier)' == 'android-arm64' ">aarch64-linux-android</_NdkSysrootAbi>
    <_NdkClangPrefix Condition=" '$(RuntimeIdentifier)' == 'linux-bionic-arm64' or '$(RuntimeIdentifier)' == 'android-arm64' ">aarch64-linux-android21-</_NdkClangPrefix>
    <_NdkPrebuiltAbi Condition=" $(NETCoreSdkRuntimeIdentifier.StartsWith('osx')) ">darwin-x86_64</_NdkPrebuiltAbi>
    <_NdkPrebuiltAbi Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'linux-x64' ">linux-x86_64</_NdkPrebuiltAbi>
    <_NdkPrebuiltAbi Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'win-x64' ">windows-x86_64</_NdkPrebuiltAbi>
    <_NdkSysrootDir>$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/sysroot/usr/lib/$(_NdkSysrootAbi)</_NdkSysrootDir>
    <_NdkBinDir>$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/bin</_NdkBinDir>
  </PropertyGroup>

  <PropertyGroup Condition="'$(EnableAOT)' == 'true' and ($(RuntimeIdentifier.StartsWith('linux-bionic')) Or $(RuntimeIdentifier.StartsWith('android-arm64')))">
    <CppCompilerAndLinker>$(_NdkBinDir)/$(_NdkClangPrefix)clang++</CppCompilerAndLinker>
    <ObjCopyName>$(_NdkBinDir)/llvm-objcopy</ObjCopyName>
  </PropertyGroup>

  <ItemGroup Condition="'$(EnableAOT)' == 'true' and ($(RuntimeIdentifier.StartsWith('linux-bionic')) Or $(RuntimeIdentifier.StartsWith('android-arm64')))">
    <LinkerArg Include="-Wl,--undefined-version" />
  </ItemGroup>

  <Target Name="_ValidateEnvironment"
      BeforeTargets="Build"
      Condition="'$(EnableAOT)' == 'true' and ($(RuntimeIdentifier.StartsWith('linux-bionic')) or $(RuntimeIdentifier.StartsWith('android-arm64'))) and ('$(NETCoreSdkRuntimeIdentifier)' == 'linux-x64' or $(NETCoreSdkRuntimeIdentifier.StartsWith('osx'))) ">
    <Error
        Condition=" '$(ANDROID_NDK_HOME)' == '' Or !Exists($(ANDROID_NDK_HOME)) "
        Text="Set the %24ANDROID_NDK_HOME environment variable to the path of the Android NDK."
     />
    <Error
        Condition=" !Exists($(_NdkSysrootDir))"
        Text="NDK 'sysroot' dir `$(_NdkSysrootDir)` does not exist. You're on your own."
    />
  </Target>
 </Project>

This should only be used if NativeAOT + Android build which I'm not setting right now as you can see, only for iOS, but it's there as a placeholder once I want to start building android with it.

As for the libs, seems to be there:

image

More logging from debugging with android studio:

  I  Godot Engine v4.4.android-monovm.mono.custom_build.95c5436e3 - https://godotengine.org
2024-09-02 20:29:19.417 30752-30845 godot                   com.example.godot                    I  Vulkan 1.3.274 - Forward Mobile - Using Device #0: ARM - Mali-G78
2024-09-02 20:29:19.420 30752-30845 gralloc4                com.example.godot                    E  ERROR: Format allocation info not found for format: 3b
2024-09-02 20:29:19.420 30752-30845 gralloc4                com.example.godot                    E  ERROR: Format allocation info not found for format: 0
2024-09-02 20:29:19.421 30752-30845 gralloc4                com.example.godot                    E  Invalid base format! req_base_format = (<unrecognized format> 0x0), req_format = (<unrecognized format> 0x3b), type = 0x0
2024-09-02 20:29:19.421 30752-30845 gralloc4                com.example.godot                    E  ERROR: Unrecognized and/or unsupported format (<unrecognized format> 0x3b) and usage (CPU_READ_NEVER|CPU_WRITE_NEVER|GPU_TEXTURE|GPU_RENDER_TARGET|COMPOSER_OVERLAY 0xb00)
2024-09-02 20:29:19.421 30752-30845 gralloc4                com.example.godot                    E  ERROR: Format allocation info not found for format: 3b
2024-09-02 20:29:19.421 30752-30845 gralloc4                com.example.godot                    E  ERROR: Format allocation info not found for format: 0
2024-09-02 20:29:19.421 30752-30845 gralloc4                com.example.godot                    E  Invalid base format! req_base_format = (<unrecognized format> 0x0), req_format = (<unrecognized format> 0x3b), type = 0x0
2024-09-02 20:29:19.421 30752-30845 gralloc4                com.example.godot                    E  ERROR: Unrecognized and/or unsupported format (<unrecognized format> 0x3b) and usage (CPU_READ_NEVER|CPU_WRITE_NEVER|GPU_TEXTURE|GPU_RENDER_TARGET|COMPOSER_OVERLAY 0xb00)
2024-09-02 20:29:19.515 30752-30845 m.example.godot         com.example.godot                    D  PlayerBase::PlayerBase()
2024-09-02 20:29:19.519 30752-30845 m.example.godot         com.example.godot                    D  TrackPlayerBase::TrackPlayerBase()
2024-09-02 20:29:19.519 30752-30845 libOpenSLES             com.example.godot                    I  Emulating old channel mask behavior (ignoring positional mask 0x3, using default mask 0x3 based on channel count of 2)
2024-09-02 20:29:19.532 30752-30845 godot                   com.example.godot                    I  
2024-09-02 20:29:19.656 30752-30752 VkThread                com.example.godot                    W  type=1400 audit(0.0:24003): avc:  granted  { execute } for  path="/data/data/com.example.godot/cache/data_RoyalMetagameGodot_android_arm64/libhostfxr.so" dev="dm-56" ino=40929 scontext=u:r:untrusted_app:s0:c123,c257,c512,c768 tcontext=u:object_r:app_data_file:s0:c123,c257,c512,c768 tclass=file app=com.example.godot
2024-09-02 20:29:19.656 30752-30752 VkThread                com.example.godot                    W  type=1400 audit(0.0:24004): avc:  granted  { execute } for  path="/data/data/com.example.godot/cache/data_RoyalMetagameGodot_android_arm64/libhostpolicy.so" dev="dm-56" ino=37304 scontext=u:r:untrusted_app:s0:c123,c257,c512,c768 tcontext=u:object_r:app_data_file:s0:c123,c257,c512,c768 tclass=file app=com.example.godot
2024-09-02 20:29:19.664 30752-30845 godot                   com.example.godot                    E  USER ERROR: hostfxr_initialize_for_dotnet_command_line failed with code: -2147450745
2024-09-02 20:29:19.664 30752-30845 godot                   com.example.godot                    E     at: initialize_hostfxr_self_contained (modules/mono/mono_gd/gd_mono.cpp:328)
2024-09-02 20:29:19.664 30752-30845 godot                   com.example.godot                    E  USER ERROR: Parameter "load_assembly_and_get_function_pointer" is null.
2024-09-02 20:29:19.664 30752-30845 godot                   com.example.godot                    E     at: initialize_hostfxr_and_godot_plugins (modules/mono/mono_gd/gd_mono.cpp:395)
2024-09-02 20:29:19.664 30752-30845 godot                   com.example.godot                    E  USER ERROR: Parameter "godot_plugins_initialize" is null.
2024-09-02 20:29:19.664 30752-30845 godot                   com.example.godot                    E     at: initialize (modules/mono/mono_gd/gd_mono.cpp:536)
2024-09-02 20:29:19.690 30752-30845 libc                    com.example.godot                    A  Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 30845 (VkThread), pid 30752 (m.example.godot)
2024-09-02 20:29:19.722 30752-30888 ProfileInstaller        com.example.godot                    D  Installing profile for com.example.godot
2024-09-02 20:29:19.789 30752-30752 InteractionJankMonitor  com.example.godot                    W  Initializing without READ_DEVICE_CONFIG permission. enabled=false, interval=1, missedFrameThreshold=3, frameTimeThreshold=64, package=com.example.godot

Same csproj etc works with 4.3, by just reimporting

felipejfc avatar Sep 02 '24 23:09 felipejfc

Thanks for sharing, I don't see anything in the csproj or android.targets files that seems problematic.

From the screenshot you shared of the APK, I'd say the publish process was successful. It's weird that it's trying to use hostfxr since there's no libhostfxr.so.

By any chance have you exported this game before with a previous version of Godot? Since Godot extracts the contents of the APK to a cache directory, it's possible that previously cached files are still there causing issues.

It looks like the cache path is /data/data/com.example.godot/cache/data_RoyalMetagameGodot_android_arm64, could you try to delete that directory before executing the game again? Alternatively, changing the Android application ID before exporting may also work.

raulsntos avatar Sep 03 '24 00:09 raulsntos

Spot on! Deleted cache and uninstalled the app, installed it again and it works! We will do good then adding this disclaimer that the application needs to be installed with a fresh cache if the player had a version generated with an old godot build installed

When building for armv7 I got the following error Unable to find package Microsoft.NETCore.App.Runtime.linux-bionic-arm in some csprojs:

Which was fixed by https://github.com/dotnet/android/issues/8170#issuecomment-1623845666

Tomorrow I will test on the armv7 device and report result

felipejfc avatar Sep 03 '24 00:09 felipejfc

We will do good then adding this disclaimer that the application needs to be installed with a fresh cache if the player had a version generated with an old godot build installed

We'll fix it so it automatically clears those cached files if the extracted .dotnet-publish-manifest file is outdated, so the disclaimer won't be needed.

When building for armv7 I got the following error Unable to find package Microsoft.NETCore.App.Runtime.linux-bionic-arm in some csprojs:

Which was fixed by https://github.com/dotnet/android/issues/8170#issuecomment-1623845666

Thanks a lot, that's really interesting. As mentioned in that issue, I suspect your referenced projects (i.e.: ./sharedtypes/sharedtypes.csproj) are not setting UseMonoRuntime=true.

We set UseMonoRuntime=true in the Godot.NET.Sdk, and I assume your referenced projects are using Microsoft.NET.Sdk. Perhaps we can add the workaround you linked in the Godot.NET.Sdk, as a temporary measure until the issue is fixed upstream.

raulsntos avatar Sep 03 '24 01:09 raulsntos

Thanks a lot, that's really interesting. As mentioned in that issue, I suspect your referenced projects (i.e.: ./sharedtypes/sharedtypes.csproj) are not setting UseMonoRuntime=true.

They are not! Should I reference it?

felipejfc avatar Sep 03 '24 01:09 felipejfc

We'll fix it so it automatically clears those cached files if the extracted .dotnet-publish-manifest file is outdated, so the disclaimer won't be needed.

I want to mention that the Windows Single File export feature, which involves embedding script files, is currently encountering a similar issue. Specifically, the single-file executable stops working after switching to AOT because the outdated managed assemblies inside the cache directory are loaded again upon launching the new AOT executable.

Delsin-Yu avatar Sep 03 '24 07:09 Delsin-Yu

They are not! Should I reference it?

@felipejfc If the workaround mentioned in the issue you linked doesn't work, you could try doing that. Ideally you shouldn't have to do anything manually.

I want to mention that the Windows Single File export feature, which involves embedding script files, is currently encountering a similar issue.

@Delsin-Yu Yeah, this is an existing issue. It's reported in https://github.com/godotengine/godot/issues/96299.

raulsntos avatar Sep 03 '24 23:09 raulsntos

@raulsntos Tested in a Motorola ARMv7 device with Adreno GPU

1 - Build crashed with Mobile rendered (because of vulkan I assume)

godot E  USER ERROR: .NET: Failed to get GodotPlugins initialization function pointer
      E     at: initialize_coreclr_and_godot_plugins (modules/mono/mono_gd/gd_mono.cpp:485)
      E  USER ERROR: .NET: Failed to load hostfxr
      E     at: initialize (modules/mono/mono_gd/gd_mono.cpp:549)
      E  USER ERROR: BUG: Unreferenced static string to 0: ShaderCompilation
      E     at: unref (core/string/string_name.cpp:127)
libc  F  FORTIFY: pthread_mutex_lock called on a destroyed mutex (0x81bb9e74)`

2 - When built with OpenGL the game worked fine!

Idk if the crash has to do with godot or with vulkan driver incompatibility but I would guess the later

felipejfc avatar Sep 04 '24 12:09 felipejfc

I would not expect to see the Failed to load hostfxr error, it sounds like there may be a libhostfxr.so in the cache again^1.

raulsntos avatar Sep 09 '24 02:09 raulsntos

Rebased and made new custom builds to test, the cached data should no longer be an issue since https://github.com/godotengine/godot/pull/96301 was merged:

:checkered_flag: Windows :apple: macOS :penguin: Linux
Editor x86_64 Editor universal Editor x86_64
Editor x86_32 Editor x86_32

And the Android templates you'll need to use to export:

:robot: Android
Templates

[!NOTE] Remember to push the provided nupkgs to a local NuGet source so .NET can find the custom packages, see the documentation for more details.

raulsntos avatar Sep 12 '24 15:09 raulsntos

I’m curious, after the PR is merged, can I still use this change #86791 and export it to Android via aot?

scgm0 avatar Sep 12 '24 15:09 scgm0

NativeAOT should not be affected by this PR. If your csproj contains <PublishAot>true</PublishAot>, then it won't use the Mono runtime, the libmonosgen-2.0.so library won't be in the exported project so the changes in this PR will not take place.

Keep in mind NativeAOT for Android is still experimental upstream, and will likely require more changes to make it work properly but that's outside of the scope of this PR which only focuses on enabling the Mono runtime.

  • https://github.com/dotnet/runtime/issues/106748.

You may also try to enable MonoAOT with <RunAOTCompilation>true</RunAOTCompilation> but I haven't tested it and will likely not work.

raulsntos avatar Sep 12 '24 15:09 raulsntos

Any chance we backport this to 4.3? Using native binding for handling http calls in android is a hassle

felipejfc avatar Sep 13 '24 21:09 felipejfc