Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

grendello
Copy link
Contributor

@grendello grendello commented Sep 1, 2025

Fixes: #10455

Implements a minimal Android host for NativeAOT applications. The goal is to create
a runtime environment that is as compatible with Xamarin.Android / .NET for Android
applications using MonoVM or CoreCLR as possible. This PR implements the very basics:

  • Support for pre-loading of JNI libraries
  • Support for setting of the application environment variables (via <AndroidEnvironment>)
  • Support for the CoreCLR GC bridge

An important element that's currently missing is linking libc++ statically into the runtime, instead we include the shared libc++ from the NDK. The reason for this is that
NativeAOT build task references a compatibility C++ library which produces conflicts with
the static libc++ one when attempting to link. This issue will be fixed in a separate
PR.

@grendello grendello force-pushed the dev/grendel/naot-runtime branch 2 times, most recently from 443bfb4 to 03d77e5 Compare September 2, 2025 14:15
@grendello
Copy link
Contributor Author

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@grendello grendello force-pushed the dev/grendel/naot-runtime branch from 03d77e5 to 04ca2d9 Compare September 3, 2025 12:17
@jonpryor
Copy link
Contributor

jonpryor commented Sep 3, 2025

Requested feature addition: CoreCLR has logic to use libSystem.Security.Cryptography.Native.Android.a":

It would be handy if similar integration could be done with NativeAOT, such that AndroidCryptoNative_InitLibraryOnLoad() is invoked during app startup when crypto support is required. This would remove the need for the kludge described here:

@grendello
Copy link
Contributor Author

@jonpryor I plan to add support for this, definitely. It'll be the same mechanism as with CoreCLR, just need to implement a bit more things before that

@jkoritzinsky
Copy link
Member

@grendello @jonathanpeppers should I close #10402 if this is intended to replace it?

@grendello
Copy link
Contributor Author

@jkoritzinsky no, please keep it open. I'm not going to put everything in this PR that's in #10402. Once this one is done, you can rebase yours and apply the remaining changes + finetuning + whatnot.

I should be done with this PR next week (need to add two more things)

@grendello grendello force-pushed the dev/grendel/naot-runtime branch from bb04b1e to e6d636a Compare September 9, 2025 13:17
@grendello grendello marked this pull request as ready for review September 10, 2025 14:08
Copy link
Member

@jonathanpeppers jonathanpeppers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NativeAOT test on Windows is failing with:

       (_CollectAssembliesToCompress target) -> 
         C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009: System.InvalidOperationException: Assembly compression info not found for key '__CompressedAssembliesInfo:C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj'. Compression will not be performed. [C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj]
       C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009:    at Xamarin.Android.Tasks.CollectAssemblyFilesToCompress.GetCompressedAssemblyInfo() [C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj]
       C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009:    at Xamarin.Android.Tasks.CollectAssemblyFilesToCompress.RunTask() [C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj]
       C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009:    at Microsoft.Android.Build.Tasks.AndroidTask.Execute() [C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj]

I don't see any new RegisterTaskObject() calls.

So, is the problem specific to Windows? Or maybe the test is doing multiple RIDs?

@@ -110,9 +115,96 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
<ResolvedFileToPublish Include="$(_NdkSysrootDir)libc++_shared.so" RuntimeIdentifier="$(RuntimeIdentifier)" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be removed? Are we statically linking libc++?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not right now because NativeAOT has a compatibility library that conflicts with static libc++. I want to explore a fix for this in a separate PR, since this one is too big already.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it makes sense to split that off into separate PR. I suppose you can remove the shim libc++ from the list and then add the real one instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to keep both references to libc++_shared.so in this PR as we both need to link against it (the <LinkerArg> item) and package it (the ResolvedFileToPublish item)

Comment on lines +86 to +88
if (gref_gc_threshold != int.MaxValue) {
gref_gc_threshold = checked((gref_gc_threshold * 9) / 10);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this taking 90% of this number for all runtimes? Do we need this change?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other runtimes set gref_gc_threshold through different code path but it's still the same value (90% of the max GREF count).

@filipnavara
Copy link
Member

This mostly seems to work, except few build issues and excessive logging.

When doing dotnet publish the build configuration is automatically set to Release and that in turn sets EmbedAssembliesIntoApk=true, which later leads to this build error:

    D:\dotnet-android\android\bin\Debug\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009:
      System.InvalidOperationException: Assembly compression info not found for key '__CompressedAssembliesInfo:D:\emcli
      ent\MailClient.Mobile\MailClient.Mobile.Android\MailClient.Mobile.Android.csproj'. Compression will not be perform
      ed.
         at Xamarin.Android.Tasks.CollectAssemblyFilesToCompress.GetCompressedAssemblyInfo()
         at Xamarin.Android.Tasks.CollectAssemblyFilesToCompress.RunTask()
         at Microsoft.Android.Build.Tasks.AndroidTask.Execute()

Since NativeAOT doesn't operate with assemblies it seems safe to workaround it with -p:EmbedAssembliesIntoApk=false.

When doing multi-RID builds (again, default) I constantly got a variation of this error (for either RID at random):

  MailClient.Mobile.Android failed with 2 error(s) (35.1s)
    ILLink : error IL1011: Failed to write 'obj\Release\net10.0-android\android-x64\linked\Java.Interop.dll'.
    C:\Users\filip\.nuget\packages\microsoft.net.illink.tasks\10.0.0-rc.2.25427.104\build\Microsoft.NET.ILLink.targets(103,5): error NETSDK1144: Optimizing assemblies for size failed.

To get past that I used -r android-x64 and the app was built successfully.

The startup took well over a minute and the whole log was spammed with the following:

09-10 22:00:00.319  5559  5576 W monodroid-assembly: virtual bool BridgeProcessing::maybe_call_gc_user_peerable_add_managed_reference(JNIEnv *, jobject, jobject)
09-10 22:00:00.319  5559  5576 W monodroid-assembly: virtual bool BridgeProcessing::maybe_call_gc_user_peerable_add_managed_reference(JNIEnv *, jobject, jobject)
...
09-10 22:00:00.340  5559  5576 W monodroid-assembly: virtual bool BridgeProcessing::maybe_call_gc_user_peerable_clear_managed_references(JNIEnv *, jobject)
09-10 22:00:00.340  5559  5576 W monodroid-assembly: virtual bool BridgeProcessing::maybe_call_gc_user_peerable_clear_managed_references(JNIEnv *, jobject)

Presumably the slow startup was caused just by the logging but it needs to be verified. Experiments with the previous PR showed similar behavior due to incorrectly set gref_gc_threshold which caused excessive GC triggers, but this seems to be handled correctly in this PR.

@grendello grendello force-pushed the dev/grendel/naot-runtime branch from 493cbd8 to 96113be Compare September 11, 2025 09:17
@grendello
Copy link
Contributor Author

The NativeAOT test on Windows is failing with:

       (_CollectAssembliesToCompress target) -> 
         C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009: System.InvalidOperationException: Assembly compression info not found for key '__CompressedAssembliesInfo:C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj'. Compression will not be performed. [C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj]
       C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009:    at Xamarin.Android.Tasks.CollectAssemblyFilesToCompress.GetCompressedAssemblyInfo() [C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj]
       C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009:    at Xamarin.Android.Tasks.CollectAssemblyFilesToCompress.RunTask() [C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj]
       C:\a\_work\1\s\bin\Release\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009:    at Microsoft.Android.Build.Tasks.AndroidTask.Execute() [C:\a\_work\1\a\TestRelease\09-10_14.27.54\temp\NativeAOT\Hello.csproj]

I don't see any new RegisterTaskObject() calls.

So, is the problem specific to Windows? Or maybe the test is doing multiple RIDs?

The problem was Debug vs Release. I tested only in the former and disabled only part of compressed assembly support. It should work now for Release too.

@filipnavara
Copy link
Member

filipnavara commented Sep 11, 2025

The GREF threshold initialization still seems to be wrong:

...
09-11 15:18:56.370 10555 10555 I NativeAotFromAndroid: APPLICATION Initialize END
09-11 15:18:56.372 10555 10555 D monodroid-gc: 83 outstanding GREFs. Performing a full GC!
09-11 15:18:56.376 10555 10617 D monodroid-gc: 84 outstanding GREFs. Performing a full GC!
09-11 15:18:56.392 10555 10555 D monodroid-gc: 59 outstanding GREFs. Performing a full GC!
09-11 15:18:56.400 10555 10617 D monodroid-gc: 60 outstanding GREFs. Performing a full GC!
09-11 15:18:56.416 10555 10573 I ient.mailclient: Explicit concurrent mark compact GC freed 1132KB AllocSpace bytes, 0(0B) LOS objects, 49% free, 2752KB/5504KB, paused 2.622ms,1.462ms total 35.554ms
09-11 15:18:56.419 10555 10555 D monodroid-gc: 86 outstanding GREFs. Performing a full GC!
09-11 15:18:56.419 10555 10617 D monodroid-gc: 86 outstanding GREFs. Performing a full GC!
09-11 15:18:56.448 10555 10573 I ient.mailclient: Explicit concurrent mark compact GC freed 152KB AllocSpace bytes, 0(0B) LOS objects, 49% free, 2728KB/5456KB, paused 1.917ms,2.356ms total 23.981ms
09-11 15:18:56.455 10555 10555 D monodroid-gc: 87 outstanding GREFs. Performing a full GC!
09-11 15:18:56.482 10555 10573 I ient.mailclient: Explicit concurrent mark compact GC freed 160KB AllocSpace bytes, 0(0B) LOS objects, 49% free, 2696KB/5392KB, paused 1.136ms,1.627ms total 21.812ms
09-11 15:18:56.488 10555 10555 D monodroid-gc: 88 outstanding GREFs. Performing a full GC!
09-11 15:18:56.515 10555 10573 I ient.mailclient: Explicit concurrent mark compact GC freed 96KB AllocSpace bytes, 0(0B) LOS objects, 49% free, 2696KB/5392KB, paused 730us,1.376ms total 22.020ms
09-11 15:18:56.517 10555 10555 D monodroid-gc: 89 outstanding GREFs. Performing a full GC!

Essentially every allocation of bridge object triggers a GC.

Probably a missing call to AndroidSystem::init_max_gref_count (); somewhere.

jonpryor added a commit to unoplatform/uno that referenced this pull request Sep 11, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time, we've decided to introduce a new
stage to build and run these unit tests within an Android+NativeAOT
environment.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit to unoplatform/uno that referenced this pull request Sep 11, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
jonpryor added a commit to unoplatform/uno that referenced this pull request Sep 12, 2025
…droid

Context: #21256 / 52a6f3e
Context: dotnet/android#10461
Context: dotnet/android#10457
Context: dotnet/android#10463

#21256 added support for building with .NET 10, and
one of the new features in .NET 10 is that Android has (very!)
preliminary preview support for [NativeAOT][0].

As building `SamplesApp.Skia.netcoremobile.csproj` with NativeAOT
takes a significant amount of time and disk space, we've decided to
introduce a new `Tests - Android+NativeAOT Skia` stage to build and
run these unit tests within an Android+NativeAOT environment.
To help reduce disk usage, after building the `.apk` we delete the
`obj` directory.

Update `android-run-skia-runtime-tests.sh` to always create
the `$(build.sourcesdirectory)/build/uitests-failure-results` path
before existing with an error, as failure to do so means that the
`PublishBuildArtifacts@1` YAML task fails:

	##[error]Publishing build artifacts failed with an error: Not found PathtoPublish: /agent/_work/1/s/build/uitests-failure-results

which in turn means subsequent `DownloadBuildArtifacts@0` /
**Download previous test runs failed tests** steps *also* always fail:

	##[error]Artifact uitests-android-nativeaot-failure-results not found for build 174635. Please ensure you have published artifacts in any previous phases of the current build.

Update `ApplicationData.GetRoamingFolder()` to explicitly create
`Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)`.
(Apparently this isn't created by default under NativeAOT?)
This avoids a startup assertion:

	I NativeAotFromAndroid: App failed to initialize: System.IO.DirectoryNotFoundException: IO_PathNotFound_Path, /data/user/0/uno.platform.samplesapp.skia/files/.config/b63c4306-f361-42d0-bc1d-5be385a95c78.txt
	I NativeAotFromAndroid:    at System.IO.FileSystem.DeleteFile(String) + 0xe7
	I NativeAotFromAndroid:    at SamplesApp.App.<AssertApplicationData>g__AssertCanCreateFile|32_3(StorageFolder) + 0x10c
	I NativeAotFromAndroid:    at SamplesApp.App.AssertApplicationData() + 0xa5
	I NativeAotFromAndroid:    at SamplesApp.App..ctor() + 0x2a3
	I NativeAotFromAndroid:    at SamplesApp.Droid.Application.<>c.<.ctor>b__0_0() + 0x18
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.NativeApplication.<OnActivityStarted>b__7_0() + 0x12
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.<Run>g__CreateApp|2_10(ApplicationInitializationCallbackParams _) + 0xf
	I NativeAotFromAndroid:    at Microsoft.UI.Xaml.Application.StartPartial(ApplicationInitializationCallback callback) + 0xb5
	I NativeAotFromAndroid:    at Uno.UI.Runtime.Skia.Android.AndroidHost.Run() + 0x306

Enable NativeAOT builds by updating
`SamplesApp.Skia.netcoremobile.csproj` to set the [`$(PublishAot)`][1]
property to the `$(SkiaPublishAot)` MSBuild property.  This allows
us to build a single project for NativeAOT --
`SamplesApp.Skia.netcoremobile.csproj` -- *without* trying to build
every referenced project for NativeAOT, which is what happens if you
instead try `dotnet publish -p:PublishAot=true …`:

	% dotnet build -c Release -p:PublishAot=true src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj -bl
	…
	…/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(121,5): error NETSDK1207: Ahead-of-time compilation is not supported for the target framework.

	% dotnet publish src/SamplesApp/SamplesApp.Skia.netcoremobile/SamplesApp.Skia.netcoremobile.csproj \
	  -c Release -r android-x64 -f net10.0-android -p:UnoTargetFrameworkOverride=net10.0-android -p:SkiaPublishAot=true -bl
	# succeeds… after 15 minutes…

This also requires updating `$(NoWarn)` to ignore the hundreds of
IL trimmer warnings.  We're just trying to see where things stand for now.

Additionally, we need to publish with `-r android-x64` in order to
avoid the build error:

	…/Microsoft.NETCore.Native.Publish.targets(92,5): error MSB3030: Could not copy the file "bin/Release/net10.0-android/native/SamplesApp.so" because it was not found.

Because it's `bin/Release/net10.0-android/android-{arm64,x64}/native/SamplesApp.so`!

Oddly, using `-r android-x64` still results in *both* ABIs being
included, which appears to be a unoplatform/uno "bug":

	% unzip -l src/SamplesApp/SamplesApp.Skia.netcoremobile/bin/Release/net10.0-android/android-x64/publish/uno.platform.samplesapp.skia-Signed.apk | grep SamplesApp.so
	763563120  08-28-2025 19:47   lib/x86_64/libSamplesApp.so
	757982224  08-28-2025 19:48   lib/arm64-v8a/libSamplesApp.so

The need for `-r android-x64` may be related to dotnet/android#10457.

Finally, .NET Crypto support isn't propertly initialized in
Android+NativeAOT apps in .NET 10 RC1; see dotnet/android#10463.
This may be fixed in dotnet/android#10461, but in the meantime we can
manually call `AndroidCryptoNative_InitLibraryOnLoad()` so that
methods such as `SHA1.Create()` won't throw.

Note: Do *not* make Release-config apps [Debuggable][2] under
.NET 10 Preview 7 or earlier; you will run into
[dotnet/java-interop@90ac202e][3].

[0]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/
[1]: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=windows%2Cnet8#publish-native-aot-using-the-cli
[2]: https://developer.android.com/guide/topics/manifest/application-element#debug
[3]: dotnet/java-interop@90ac202
Builds, installs, does nothing yet.
Linking seems to work, not tested yet
NativeAOT sample now links without errors about missing symbols (added
linker options for it to fail if missing symbols are detected)
Disable attempts to collect assemblies for compression to avoid
this error:

    D:\dotnet-android\android\bin\Debug\dotnet\packs\Microsoft.Android.Sdk.Windows\36.0.0-ci.dev-grendel-naot-runtime.323\tools\Xamarin.Android.Common.targets(2258,3): error XACAF7009:
      System.InvalidOperationException: Assembly compression info not found for key '__CompressedAssembliesInfo:D:\emcli
      ent\MailClient.Mobile\MailClient.Mobile.Android\MailClient.Mobile.Android.csproj'. Compression will not be perform
      ed.
         at Xamarin.Android.Tasks.CollectAssemblyFilesToCompress.GetCompressedAssemblyInfo()
         at Xamarin.Android.Tasks.CollectAssemblyFilesToCompress.RunTask()
         at Microsoft.Android.Build.Tasks.AndroidTask.Execute()
@grendello grendello force-pushed the dev/grendel/naot-runtime branch from 251297f to 68b9a88 Compare September 12, 2025 07:57
Comment on lines +105 to +106
// TODO: this shouldn't be public
public class AndroidObjectReferenceManager : JniRuntime.JniObjectReferenceManager {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only thing we'll need to fix ASAP next week.

@grendello grendello merged commit 869b0e0 into main Sep 12, 2025
59 checks passed
@grendello grendello deleted the dev/grendel/naot-runtime branch September 12, 2025 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create our initial native library for NativeAOT
5 participants