Add NativeAOT on Android test - #118037

Merged
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot
Aug 11, 2025
Merged

Add NativeAOT on Android test#118037
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot

Conversation

@jtschuster

@jtschusterjtschuster commented Jul 24, 2025

Copy link
Copy Markdown
Member

Adds a project to run a NativeAOT shared library on Android.

The android test builds a single native library that exports the methods that are expected by the monodroid tests (InitRuntime, SetEnv, ExecEntryPoint, FreeUnmanagedResources). JNI struct definitions are copied to get arg strings from the JNIEnv object.

ApkBuilder no longer needs to compile the monodroid native library, but it does need to add the java .jar from the cryptography library to the apk bundle in order to run crypto operations.

Build targets were updated to account for the new NativeAOT tests, and a new job was added for NativeAOT on android tests.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @akoeplinger, @matouskozak, @simonrozsival
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/tools/Common/CommandLineHelpers.cs Outdated
@risc-vv

Copy link
Copy Markdown

@dotnet/samsung Could you please take a look? These changes may be related to riscv64.

Comment threadsrc/tasks/AndroidAppBuilder/ApkBuilder.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

- Don't use BundleDir for android bundle dir: This is PublishDir when TestSingleFile=true (which it is). Android deletes this dir before packaging, deleting the files that were just published.
- Don't add the singleFileTestRunner.cs when the test sets IsFunctionalTest=true
- Don't run regular nativeaot smoke tests on android yet.
- Enable android tests to publish as libs when TestSingleFile=true (default when TestNativeAOT=true)
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster
jtschuster marked this pull request as ready for review August 5, 2025 17:41
CopilotAI review requested due to automatic review settings August 5, 2025 17:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for running NativeAOT (Native Ahead-of-Time) compiled applications on Android. The implementation creates a shared library that exports the required JNI methods expected by the Android test infrastructure, eliminating the need for the monodroid runtime while maintaining compatibility with existing test frameworks.

Key changes include:

  • Added NativeAOT-specific Android test project and JNI interop layer
  • Updated build infrastructure to support NativeAOT runtime flavor
  • Modified Android app builder to handle NativeAOT library generation and packaging

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Program.csSimple test program that validates console output and cryptography functionality
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csprojProject file configuring NativeAOT compilation with required JNI template inclusion
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.csJNI interop layer implementing required Android runtime interface methods
src/tasks/AndroidAppBuilder/Templates/MonoRunner.javaUpdated Java template to support dynamic library loading statements
src/tasks/AndroidAppBuilder/ApkBuilder.csEnhanced APK builder with NativeAOT runtime support and library packaging
src/mono/msbuild/android/build/AndroidBuild.targetsUpdated build targets to handle NativeAOT runtime flavor and dependencies
src/mono/msbuild/android/build/AndroidBuild.propsAdded Android NDK toolchain configuration and NativeAOT build dependencies
src/libraries/tests.projModified test project inclusion logic for NativeAOT Android tests
src/coreclr/nativeaot/Runtime/interoplibinterface_java.cppAdded missing thread.inl include for Java interop
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targetsExtended cross-compilation support for android- RID prefix
src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targetsAdded Android bionic libc flavor detection
eng/testing/tests.singlefile.targetsConditional OutputType and compilation adjustments for Android NativeAOT
eng/testing/tests.android.targetsRemoved redundant AndroidBundleDir property assignment
eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.ymlAdded CI pipeline job for NativeAOT Android emulator testing
eng/pipelines/extra-platforms/runtime-extra-platforms-android.ymlAdded CI pipeline job for NativeAOT Android device testing

Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

filipnavara commented Aug 6, 2025

Copy link
Copy Markdown
Member

There's one thing that we should still fix:

--- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs+++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs@@ -130,7 +130,9 @@ public override bool Execute()
continue;
}
- if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true)+ if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true &&+ !assemblyFileName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) &&+ !assemblyFileName.EndsWith(".dex", StringComparison.OrdinalIgnoreCase))
{
// Skip the native components of the runtime pack, we don't need them for NativeAOT.
assembliesToSkipPublish.Add(taskItem);

The native assets of the Android runtime files now contain the .jar/.dex files for libSystem.Security.Cryptography.Android. We should not strip them in ComputeManagedAssembliesToCompileToNative build target to keep the HTTP stack working.

@filipnavarafilipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested that it makes the Android runtime pack into functional state that can be consumed on the workload side and used to build a whole app. Obviously there's still work that has to be done on the consumption side (dotnet/android) but having an end-to-end scenrio running is a good start:

image

One thing that still needs to be resolved is who is responsible for exporting the JNI symbol for Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate in case of the builds that link the crypto libraries statically. Presumably that can and will be done on the Android workload side with something like <IlcArg Include="--export-dynamic-symbol:Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate" />.

@vitek-karas

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

@filipnavara

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

Yes, that's part of the solution. There's an issue for CoreCLR integration filed at dotnet/android#10324 that has a bit more context.

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/ba-g failures are unrelated

@jtschuster
jtschuster merged commit 1e322fd into dotnet:mainAug 11, 2025
154 of 162 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Sep 11, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

13 participants

@jtschuster@risc-vv@MichalStrehovsky@filipnavara@vitek-karas@steveisok@agocke@am11@jkotas@kotlarmilos@davidnguyen-tech@NayYeMaram
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add NativeAOT on Android test - #118037

Merged
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot
Aug 11, 2025
Merged

Add NativeAOT on Android test#118037
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot

Conversation

@jtschuster

@jtschusterjtschuster commented Jul 24, 2025

Copy link
Copy Markdown
Member

Adds a project to run a NativeAOT shared library on Android.

The android test builds a single native library that exports the methods that are expected by the monodroid tests (InitRuntime, SetEnv, ExecEntryPoint, FreeUnmanagedResources). JNI struct definitions are copied to get arg strings from the JNIEnv object.

ApkBuilder no longer needs to compile the monodroid native library, but it does need to add the java .jar from the cryptography library to the apk bundle in order to run crypto operations.

Build targets were updated to account for the new NativeAOT tests, and a new job was added for NativeAOT on android tests.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @akoeplinger, @matouskozak, @simonrozsival
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/tools/Common/CommandLineHelpers.cs Outdated
@risc-vv

Copy link
Copy Markdown

@dotnet/samsung Could you please take a look? These changes may be related to riscv64.

Comment threadsrc/tasks/AndroidAppBuilder/ApkBuilder.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

- Don't use BundleDir for android bundle dir: This is PublishDir when TestSingleFile=true (which it is). Android deletes this dir before packaging, deleting the files that were just published.
- Don't add the singleFileTestRunner.cs when the test sets IsFunctionalTest=true
- Don't run regular nativeaot smoke tests on android yet.
- Enable android tests to publish as libs when TestSingleFile=true (default when TestNativeAOT=true)
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster
jtschuster marked this pull request as ready for review August 5, 2025 17:41
CopilotAI review requested due to automatic review settings August 5, 2025 17:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for running NativeAOT (Native Ahead-of-Time) compiled applications on Android. The implementation creates a shared library that exports the required JNI methods expected by the Android test infrastructure, eliminating the need for the monodroid runtime while maintaining compatibility with existing test frameworks.

Key changes include:

  • Added NativeAOT-specific Android test project and JNI interop layer
  • Updated build infrastructure to support NativeAOT runtime flavor
  • Modified Android app builder to handle NativeAOT library generation and packaging

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Program.csSimple test program that validates console output and cryptography functionality
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csprojProject file configuring NativeAOT compilation with required JNI template inclusion
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.csJNI interop layer implementing required Android runtime interface methods
src/tasks/AndroidAppBuilder/Templates/MonoRunner.javaUpdated Java template to support dynamic library loading statements
src/tasks/AndroidAppBuilder/ApkBuilder.csEnhanced APK builder with NativeAOT runtime support and library packaging
src/mono/msbuild/android/build/AndroidBuild.targetsUpdated build targets to handle NativeAOT runtime flavor and dependencies
src/mono/msbuild/android/build/AndroidBuild.propsAdded Android NDK toolchain configuration and NativeAOT build dependencies
src/libraries/tests.projModified test project inclusion logic for NativeAOT Android tests
src/coreclr/nativeaot/Runtime/interoplibinterface_java.cppAdded missing thread.inl include for Java interop
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targetsExtended cross-compilation support for android- RID prefix
src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targetsAdded Android bionic libc flavor detection
eng/testing/tests.singlefile.targetsConditional OutputType and compilation adjustments for Android NativeAOT
eng/testing/tests.android.targetsRemoved redundant AndroidBundleDir property assignment
eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.ymlAdded CI pipeline job for NativeAOT Android emulator testing
eng/pipelines/extra-platforms/runtime-extra-platforms-android.ymlAdded CI pipeline job for NativeAOT Android device testing

Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

filipnavara commented Aug 6, 2025

Copy link
Copy Markdown
Member

There's one thing that we should still fix:

--- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs+++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs@@ -130,7 +130,9 @@ public override bool Execute()
continue;
}
- if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true)+ if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true &&+ !assemblyFileName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) &&+ !assemblyFileName.EndsWith(".dex", StringComparison.OrdinalIgnoreCase))
{
// Skip the native components of the runtime pack, we don't need them for NativeAOT.
assembliesToSkipPublish.Add(taskItem);

The native assets of the Android runtime files now contain the .jar/.dex files for libSystem.Security.Cryptography.Android. We should not strip them in ComputeManagedAssembliesToCompileToNative build target to keep the HTTP stack working.

@filipnavarafilipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested that it makes the Android runtime pack into functional state that can be consumed on the workload side and used to build a whole app. Obviously there's still work that has to be done on the consumption side (dotnet/android) but having an end-to-end scenrio running is a good start:

image

One thing that still needs to be resolved is who is responsible for exporting the JNI symbol for Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate in case of the builds that link the crypto libraries statically. Presumably that can and will be done on the Android workload side with something like <IlcArg Include="--export-dynamic-symbol:Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate" />.

@vitek-karas

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

@filipnavara

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

Yes, that's part of the solution. There's an issue for CoreCLR integration filed at dotnet/android#10324 that has a bit more context.

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/ba-g failures are unrelated

@jtschuster
jtschuster merged commit 1e322fd into dotnet:mainAug 11, 2025
154 of 162 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Sep 11, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

13 participants

@jtschuster@risc-vv@MichalStrehovsky@filipnavara@vitek-karas@steveisok@agocke@am11@jkotas@kotlarmilos@davidnguyen-tech@NayYeMaram
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add NativeAOT on Android test - #118037

Merged
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot
Aug 11, 2025
Merged

Add NativeAOT on Android test#118037
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot

Conversation

@jtschuster

@jtschusterjtschuster commented Jul 24, 2025

Copy link
Copy Markdown
Member

Adds a project to run a NativeAOT shared library on Android.

The android test builds a single native library that exports the methods that are expected by the monodroid tests (InitRuntime, SetEnv, ExecEntryPoint, FreeUnmanagedResources). JNI struct definitions are copied to get arg strings from the JNIEnv object.

ApkBuilder no longer needs to compile the monodroid native library, but it does need to add the java .jar from the cryptography library to the apk bundle in order to run crypto operations.

Build targets were updated to account for the new NativeAOT tests, and a new job was added for NativeAOT on android tests.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @akoeplinger, @matouskozak, @simonrozsival
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/tools/Common/CommandLineHelpers.cs Outdated
@risc-vv

Copy link
Copy Markdown

@dotnet/samsung Could you please take a look? These changes may be related to riscv64.

Comment threadsrc/tasks/AndroidAppBuilder/ApkBuilder.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

- Don't use BundleDir for android bundle dir: This is PublishDir when TestSingleFile=true (which it is). Android deletes this dir before packaging, deleting the files that were just published.
- Don't add the singleFileTestRunner.cs when the test sets IsFunctionalTest=true
- Don't run regular nativeaot smoke tests on android yet.
- Enable android tests to publish as libs when TestSingleFile=true (default when TestNativeAOT=true)
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster
jtschuster marked this pull request as ready for review August 5, 2025 17:41
CopilotAI review requested due to automatic review settings August 5, 2025 17:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for running NativeAOT (Native Ahead-of-Time) compiled applications on Android. The implementation creates a shared library that exports the required JNI methods expected by the Android test infrastructure, eliminating the need for the monodroid runtime while maintaining compatibility with existing test frameworks.

Key changes include:

  • Added NativeAOT-specific Android test project and JNI interop layer
  • Updated build infrastructure to support NativeAOT runtime flavor
  • Modified Android app builder to handle NativeAOT library generation and packaging

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Program.csSimple test program that validates console output and cryptography functionality
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csprojProject file configuring NativeAOT compilation with required JNI template inclusion
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.csJNI interop layer implementing required Android runtime interface methods
src/tasks/AndroidAppBuilder/Templates/MonoRunner.javaUpdated Java template to support dynamic library loading statements
src/tasks/AndroidAppBuilder/ApkBuilder.csEnhanced APK builder with NativeAOT runtime support and library packaging
src/mono/msbuild/android/build/AndroidBuild.targetsUpdated build targets to handle NativeAOT runtime flavor and dependencies
src/mono/msbuild/android/build/AndroidBuild.propsAdded Android NDK toolchain configuration and NativeAOT build dependencies
src/libraries/tests.projModified test project inclusion logic for NativeAOT Android tests
src/coreclr/nativeaot/Runtime/interoplibinterface_java.cppAdded missing thread.inl include for Java interop
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targetsExtended cross-compilation support for android- RID prefix
src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targetsAdded Android bionic libc flavor detection
eng/testing/tests.singlefile.targetsConditional OutputType and compilation adjustments for Android NativeAOT
eng/testing/tests.android.targetsRemoved redundant AndroidBundleDir property assignment
eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.ymlAdded CI pipeline job for NativeAOT Android emulator testing
eng/pipelines/extra-platforms/runtime-extra-platforms-android.ymlAdded CI pipeline job for NativeAOT Android device testing

Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

filipnavara commented Aug 6, 2025

Copy link
Copy Markdown
Member

There's one thing that we should still fix:

--- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs+++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs@@ -130,7 +130,9 @@ public override bool Execute()
continue;
}
- if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true)+ if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true &&+ !assemblyFileName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) &&+ !assemblyFileName.EndsWith(".dex", StringComparison.OrdinalIgnoreCase))
{
// Skip the native components of the runtime pack, we don't need them for NativeAOT.
assembliesToSkipPublish.Add(taskItem);

The native assets of the Android runtime files now contain the .jar/.dex files for libSystem.Security.Cryptography.Android. We should not strip them in ComputeManagedAssembliesToCompileToNative build target to keep the HTTP stack working.

@filipnavarafilipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested that it makes the Android runtime pack into functional state that can be consumed on the workload side and used to build a whole app. Obviously there's still work that has to be done on the consumption side (dotnet/android) but having an end-to-end scenrio running is a good start:

image

One thing that still needs to be resolved is who is responsible for exporting the JNI symbol for Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate in case of the builds that link the crypto libraries statically. Presumably that can and will be done on the Android workload side with something like <IlcArg Include="--export-dynamic-symbol:Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate" />.

@vitek-karas

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

@filipnavara

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

Yes, that's part of the solution. There's an issue for CoreCLR integration filed at dotnet/android#10324 that has a bit more context.

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/ba-g failures are unrelated

@jtschuster
jtschuster merged commit 1e322fd into dotnet:mainAug 11, 2025
154 of 162 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Sep 11, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

13 participants

@jtschuster@risc-vv@MichalStrehovsky@filipnavara@vitek-karas@steveisok@agocke@am11@jkotas@kotlarmilos@davidnguyen-tech@NayYeMaram
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add NativeAOT on Android test - #118037

Merged
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot
Aug 11, 2025
Merged

Add NativeAOT on Android test#118037
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot

Conversation

@jtschuster

@jtschusterjtschuster commented Jul 24, 2025

Copy link
Copy Markdown
Member

Adds a project to run a NativeAOT shared library on Android.

The android test builds a single native library that exports the methods that are expected by the monodroid tests (InitRuntime, SetEnv, ExecEntryPoint, FreeUnmanagedResources). JNI struct definitions are copied to get arg strings from the JNIEnv object.

ApkBuilder no longer needs to compile the monodroid native library, but it does need to add the java .jar from the cryptography library to the apk bundle in order to run crypto operations.

Build targets were updated to account for the new NativeAOT tests, and a new job was added for NativeAOT on android tests.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @akoeplinger, @matouskozak, @simonrozsival
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/tools/Common/CommandLineHelpers.cs Outdated
@risc-vv

Copy link
Copy Markdown

@dotnet/samsung Could you please take a look? These changes may be related to riscv64.

Comment threadsrc/tasks/AndroidAppBuilder/ApkBuilder.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

- Don't use BundleDir for android bundle dir: This is PublishDir when TestSingleFile=true (which it is). Android deletes this dir before packaging, deleting the files that were just published.
- Don't add the singleFileTestRunner.cs when the test sets IsFunctionalTest=true
- Don't run regular nativeaot smoke tests on android yet.
- Enable android tests to publish as libs when TestSingleFile=true (default when TestNativeAOT=true)
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster
jtschuster marked this pull request as ready for review August 5, 2025 17:41
CopilotAI review requested due to automatic review settings August 5, 2025 17:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for running NativeAOT (Native Ahead-of-Time) compiled applications on Android. The implementation creates a shared library that exports the required JNI methods expected by the Android test infrastructure, eliminating the need for the monodroid runtime while maintaining compatibility with existing test frameworks.

Key changes include:

  • Added NativeAOT-specific Android test project and JNI interop layer
  • Updated build infrastructure to support NativeAOT runtime flavor
  • Modified Android app builder to handle NativeAOT library generation and packaging

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Program.csSimple test program that validates console output and cryptography functionality
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csprojProject file configuring NativeAOT compilation with required JNI template inclusion
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.csJNI interop layer implementing required Android runtime interface methods
src/tasks/AndroidAppBuilder/Templates/MonoRunner.javaUpdated Java template to support dynamic library loading statements
src/tasks/AndroidAppBuilder/ApkBuilder.csEnhanced APK builder with NativeAOT runtime support and library packaging
src/mono/msbuild/android/build/AndroidBuild.targetsUpdated build targets to handle NativeAOT runtime flavor and dependencies
src/mono/msbuild/android/build/AndroidBuild.propsAdded Android NDK toolchain configuration and NativeAOT build dependencies
src/libraries/tests.projModified test project inclusion logic for NativeAOT Android tests
src/coreclr/nativeaot/Runtime/interoplibinterface_java.cppAdded missing thread.inl include for Java interop
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targetsExtended cross-compilation support for android- RID prefix
src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targetsAdded Android bionic libc flavor detection
eng/testing/tests.singlefile.targetsConditional OutputType and compilation adjustments for Android NativeAOT
eng/testing/tests.android.targetsRemoved redundant AndroidBundleDir property assignment
eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.ymlAdded CI pipeline job for NativeAOT Android emulator testing
eng/pipelines/extra-platforms/runtime-extra-platforms-android.ymlAdded CI pipeline job for NativeAOT Android device testing

Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

filipnavara commented Aug 6, 2025

Copy link
Copy Markdown
Member

There's one thing that we should still fix:

--- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs+++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs@@ -130,7 +130,9 @@ public override bool Execute()
continue;
}
- if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true)+ if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true &&+ !assemblyFileName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) &&+ !assemblyFileName.EndsWith(".dex", StringComparison.OrdinalIgnoreCase))
{
// Skip the native components of the runtime pack, we don't need them for NativeAOT.
assembliesToSkipPublish.Add(taskItem);

The native assets of the Android runtime files now contain the .jar/.dex files for libSystem.Security.Cryptography.Android. We should not strip them in ComputeManagedAssembliesToCompileToNative build target to keep the HTTP stack working.

@filipnavarafilipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested that it makes the Android runtime pack into functional state that can be consumed on the workload side and used to build a whole app. Obviously there's still work that has to be done on the consumption side (dotnet/android) but having an end-to-end scenrio running is a good start:

image

One thing that still needs to be resolved is who is responsible for exporting the JNI symbol for Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate in case of the builds that link the crypto libraries statically. Presumably that can and will be done on the Android workload side with something like <IlcArg Include="--export-dynamic-symbol:Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate" />.

@vitek-karas

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

@filipnavara

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

Yes, that's part of the solution. There's an issue for CoreCLR integration filed at dotnet/android#10324 that has a bit more context.

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/ba-g failures are unrelated

@jtschuster
jtschuster merged commit 1e322fd into dotnet:mainAug 11, 2025
154 of 162 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Sep 11, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

13 participants

@jtschuster@risc-vv@MichalStrehovsky@filipnavara@vitek-karas@steveisok@agocke@am11@jkotas@kotlarmilos@davidnguyen-tech@NayYeMaram
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add NativeAOT on Android test - #118037

Merged
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot
Aug 11, 2025
Merged

Add NativeAOT on Android test#118037
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot

Conversation

@jtschuster

@jtschusterjtschuster commented Jul 24, 2025

Copy link
Copy Markdown
Member

Adds a project to run a NativeAOT shared library on Android.

The android test builds a single native library that exports the methods that are expected by the monodroid tests (InitRuntime, SetEnv, ExecEntryPoint, FreeUnmanagedResources). JNI struct definitions are copied to get arg strings from the JNIEnv object.

ApkBuilder no longer needs to compile the monodroid native library, but it does need to add the java .jar from the cryptography library to the apk bundle in order to run crypto operations.

Build targets were updated to account for the new NativeAOT tests, and a new job was added for NativeAOT on android tests.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @akoeplinger, @matouskozak, @simonrozsival
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/tools/Common/CommandLineHelpers.cs Outdated
@risc-vv

Copy link
Copy Markdown

@dotnet/samsung Could you please take a look? These changes may be related to riscv64.

Comment threadsrc/tasks/AndroidAppBuilder/ApkBuilder.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

- Don't use BundleDir for android bundle dir: This is PublishDir when TestSingleFile=true (which it is). Android deletes this dir before packaging, deleting the files that were just published.
- Don't add the singleFileTestRunner.cs when the test sets IsFunctionalTest=true
- Don't run regular nativeaot smoke tests on android yet.
- Enable android tests to publish as libs when TestSingleFile=true (default when TestNativeAOT=true)
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster
jtschuster marked this pull request as ready for review August 5, 2025 17:41
CopilotAI review requested due to automatic review settings August 5, 2025 17:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for running NativeAOT (Native Ahead-of-Time) compiled applications on Android. The implementation creates a shared library that exports the required JNI methods expected by the Android test infrastructure, eliminating the need for the monodroid runtime while maintaining compatibility with existing test frameworks.

Key changes include:

  • Added NativeAOT-specific Android test project and JNI interop layer
  • Updated build infrastructure to support NativeAOT runtime flavor
  • Modified Android app builder to handle NativeAOT library generation and packaging

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Program.csSimple test program that validates console output and cryptography functionality
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csprojProject file configuring NativeAOT compilation with required JNI template inclusion
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.csJNI interop layer implementing required Android runtime interface methods
src/tasks/AndroidAppBuilder/Templates/MonoRunner.javaUpdated Java template to support dynamic library loading statements
src/tasks/AndroidAppBuilder/ApkBuilder.csEnhanced APK builder with NativeAOT runtime support and library packaging
src/mono/msbuild/android/build/AndroidBuild.targetsUpdated build targets to handle NativeAOT runtime flavor and dependencies
src/mono/msbuild/android/build/AndroidBuild.propsAdded Android NDK toolchain configuration and NativeAOT build dependencies
src/libraries/tests.projModified test project inclusion logic for NativeAOT Android tests
src/coreclr/nativeaot/Runtime/interoplibinterface_java.cppAdded missing thread.inl include for Java interop
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targetsExtended cross-compilation support for android- RID prefix
src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targetsAdded Android bionic libc flavor detection
eng/testing/tests.singlefile.targetsConditional OutputType and compilation adjustments for Android NativeAOT
eng/testing/tests.android.targetsRemoved redundant AndroidBundleDir property assignment
eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.ymlAdded CI pipeline job for NativeAOT Android emulator testing
eng/pipelines/extra-platforms/runtime-extra-platforms-android.ymlAdded CI pipeline job for NativeAOT Android device testing

Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

filipnavara commented Aug 6, 2025

Copy link
Copy Markdown
Member

There's one thing that we should still fix:

--- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs+++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs@@ -130,7 +130,9 @@ public override bool Execute()
continue;
}
- if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true)+ if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true &&+ !assemblyFileName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) &&+ !assemblyFileName.EndsWith(".dex", StringComparison.OrdinalIgnoreCase))
{
// Skip the native components of the runtime pack, we don't need them for NativeAOT.
assembliesToSkipPublish.Add(taskItem);

The native assets of the Android runtime files now contain the .jar/.dex files for libSystem.Security.Cryptography.Android. We should not strip them in ComputeManagedAssembliesToCompileToNative build target to keep the HTTP stack working.

@filipnavarafilipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested that it makes the Android runtime pack into functional state that can be consumed on the workload side and used to build a whole app. Obviously there's still work that has to be done on the consumption side (dotnet/android) but having an end-to-end scenrio running is a good start:

image

One thing that still needs to be resolved is who is responsible for exporting the JNI symbol for Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate in case of the builds that link the crypto libraries statically. Presumably that can and will be done on the Android workload side with something like <IlcArg Include="--export-dynamic-symbol:Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate" />.

@vitek-karas

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

@filipnavara

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

Yes, that's part of the solution. There's an issue for CoreCLR integration filed at dotnet/android#10324 that has a bit more context.

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/ba-g failures are unrelated

@jtschuster
jtschuster merged commit 1e322fd into dotnet:mainAug 11, 2025
154 of 162 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Sep 11, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

13 participants

@jtschuster@risc-vv@MichalStrehovsky@filipnavara@vitek-karas@steveisok@agocke@am11@jkotas@kotlarmilos@davidnguyen-tech@NayYeMaram
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add NativeAOT on Android test - #118037

Merged
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot
Aug 11, 2025
Merged

Add NativeAOT on Android test#118037
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot

Conversation

@jtschuster

@jtschusterjtschuster commented Jul 24, 2025

Copy link
Copy Markdown
Member

Adds a project to run a NativeAOT shared library on Android.

The android test builds a single native library that exports the methods that are expected by the monodroid tests (InitRuntime, SetEnv, ExecEntryPoint, FreeUnmanagedResources). JNI struct definitions are copied to get arg strings from the JNIEnv object.

ApkBuilder no longer needs to compile the monodroid native library, but it does need to add the java .jar from the cryptography library to the apk bundle in order to run crypto operations.

Build targets were updated to account for the new NativeAOT tests, and a new job was added for NativeAOT on android tests.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @akoeplinger, @matouskozak, @simonrozsival
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/tools/Common/CommandLineHelpers.cs Outdated
@risc-vv

Copy link
Copy Markdown

@dotnet/samsung Could you please take a look? These changes may be related to riscv64.

Comment threadsrc/tasks/AndroidAppBuilder/ApkBuilder.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

- Don't use BundleDir for android bundle dir: This is PublishDir when TestSingleFile=true (which it is). Android deletes this dir before packaging, deleting the files that were just published.
- Don't add the singleFileTestRunner.cs when the test sets IsFunctionalTest=true
- Don't run regular nativeaot smoke tests on android yet.
- Enable android tests to publish as libs when TestSingleFile=true (default when TestNativeAOT=true)
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster
jtschuster marked this pull request as ready for review August 5, 2025 17:41
CopilotAI review requested due to automatic review settings August 5, 2025 17:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for running NativeAOT (Native Ahead-of-Time) compiled applications on Android. The implementation creates a shared library that exports the required JNI methods expected by the Android test infrastructure, eliminating the need for the monodroid runtime while maintaining compatibility with existing test frameworks.

Key changes include:

  • Added NativeAOT-specific Android test project and JNI interop layer
  • Updated build infrastructure to support NativeAOT runtime flavor
  • Modified Android app builder to handle NativeAOT library generation and packaging

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Program.csSimple test program that validates console output and cryptography functionality
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csprojProject file configuring NativeAOT compilation with required JNI template inclusion
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.csJNI interop layer implementing required Android runtime interface methods
src/tasks/AndroidAppBuilder/Templates/MonoRunner.javaUpdated Java template to support dynamic library loading statements
src/tasks/AndroidAppBuilder/ApkBuilder.csEnhanced APK builder with NativeAOT runtime support and library packaging
src/mono/msbuild/android/build/AndroidBuild.targetsUpdated build targets to handle NativeAOT runtime flavor and dependencies
src/mono/msbuild/android/build/AndroidBuild.propsAdded Android NDK toolchain configuration and NativeAOT build dependencies
src/libraries/tests.projModified test project inclusion logic for NativeAOT Android tests
src/coreclr/nativeaot/Runtime/interoplibinterface_java.cppAdded missing thread.inl include for Java interop
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targetsExtended cross-compilation support for android- RID prefix
src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targetsAdded Android bionic libc flavor detection
eng/testing/tests.singlefile.targetsConditional OutputType and compilation adjustments for Android NativeAOT
eng/testing/tests.android.targetsRemoved redundant AndroidBundleDir property assignment
eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.ymlAdded CI pipeline job for NativeAOT Android emulator testing
eng/pipelines/extra-platforms/runtime-extra-platforms-android.ymlAdded CI pipeline job for NativeAOT Android device testing

Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

filipnavara commented Aug 6, 2025

Copy link
Copy Markdown
Member

There's one thing that we should still fix:

--- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs+++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs@@ -130,7 +130,9 @@ public override bool Execute()
continue;
}
- if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true)+ if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true &&+ !assemblyFileName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) &&+ !assemblyFileName.EndsWith(".dex", StringComparison.OrdinalIgnoreCase))
{
// Skip the native components of the runtime pack, we don't need them for NativeAOT.
assembliesToSkipPublish.Add(taskItem);

The native assets of the Android runtime files now contain the .jar/.dex files for libSystem.Security.Cryptography.Android. We should not strip them in ComputeManagedAssembliesToCompileToNative build target to keep the HTTP stack working.

@filipnavarafilipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested that it makes the Android runtime pack into functional state that can be consumed on the workload side and used to build a whole app. Obviously there's still work that has to be done on the consumption side (dotnet/android) but having an end-to-end scenrio running is a good start:

image

One thing that still needs to be resolved is who is responsible for exporting the JNI symbol for Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate in case of the builds that link the crypto libraries statically. Presumably that can and will be done on the Android workload side with something like <IlcArg Include="--export-dynamic-symbol:Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate" />.

@vitek-karas

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

@filipnavara

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

Yes, that's part of the solution. There's an issue for CoreCLR integration filed at dotnet/android#10324 that has a bit more context.

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/ba-g failures are unrelated

@jtschuster
jtschuster merged commit 1e322fd into dotnet:mainAug 11, 2025
154 of 162 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Sep 11, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

13 participants

@jtschuster@risc-vv@MichalStrehovsky@filipnavara@vitek-karas@steveisok@agocke@am11@jkotas@kotlarmilos@davidnguyen-tech@NayYeMaram
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add NativeAOT on Android test - #118037

Merged
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot
Aug 11, 2025
Merged

Add NativeAOT on Android test#118037
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot

Conversation

@jtschuster

@jtschusterjtschuster commented Jul 24, 2025

Copy link
Copy Markdown
Member

Adds a project to run a NativeAOT shared library on Android.

The android test builds a single native library that exports the methods that are expected by the monodroid tests (InitRuntime, SetEnv, ExecEntryPoint, FreeUnmanagedResources). JNI struct definitions are copied to get arg strings from the JNIEnv object.

ApkBuilder no longer needs to compile the monodroid native library, but it does need to add the java .jar from the cryptography library to the apk bundle in order to run crypto operations.

Build targets were updated to account for the new NativeAOT tests, and a new job was added for NativeAOT on android tests.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @akoeplinger, @matouskozak, @simonrozsival
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/tools/Common/CommandLineHelpers.cs Outdated
@risc-vv

Copy link
Copy Markdown

@dotnet/samsung Could you please take a look? These changes may be related to riscv64.

Comment threadsrc/tasks/AndroidAppBuilder/ApkBuilder.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

- Don't use BundleDir for android bundle dir: This is PublishDir when TestSingleFile=true (which it is). Android deletes this dir before packaging, deleting the files that were just published.
- Don't add the singleFileTestRunner.cs when the test sets IsFunctionalTest=true
- Don't run regular nativeaot smoke tests on android yet.
- Enable android tests to publish as libs when TestSingleFile=true (default when TestNativeAOT=true)
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster
jtschuster marked this pull request as ready for review August 5, 2025 17:41
CopilotAI review requested due to automatic review settings August 5, 2025 17:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for running NativeAOT (Native Ahead-of-Time) compiled applications on Android. The implementation creates a shared library that exports the required JNI methods expected by the Android test infrastructure, eliminating the need for the monodroid runtime while maintaining compatibility with existing test frameworks.

Key changes include:

  • Added NativeAOT-specific Android test project and JNI interop layer
  • Updated build infrastructure to support NativeAOT runtime flavor
  • Modified Android app builder to handle NativeAOT library generation and packaging

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Program.csSimple test program that validates console output and cryptography functionality
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csprojProject file configuring NativeAOT compilation with required JNI template inclusion
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.csJNI interop layer implementing required Android runtime interface methods
src/tasks/AndroidAppBuilder/Templates/MonoRunner.javaUpdated Java template to support dynamic library loading statements
src/tasks/AndroidAppBuilder/ApkBuilder.csEnhanced APK builder with NativeAOT runtime support and library packaging
src/mono/msbuild/android/build/AndroidBuild.targetsUpdated build targets to handle NativeAOT runtime flavor and dependencies
src/mono/msbuild/android/build/AndroidBuild.propsAdded Android NDK toolchain configuration and NativeAOT build dependencies
src/libraries/tests.projModified test project inclusion logic for NativeAOT Android tests
src/coreclr/nativeaot/Runtime/interoplibinterface_java.cppAdded missing thread.inl include for Java interop
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targetsExtended cross-compilation support for android- RID prefix
src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targetsAdded Android bionic libc flavor detection
eng/testing/tests.singlefile.targetsConditional OutputType and compilation adjustments for Android NativeAOT
eng/testing/tests.android.targetsRemoved redundant AndroidBundleDir property assignment
eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.ymlAdded CI pipeline job for NativeAOT Android emulator testing
eng/pipelines/extra-platforms/runtime-extra-platforms-android.ymlAdded CI pipeline job for NativeAOT Android device testing

Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

filipnavara commented Aug 6, 2025

Copy link
Copy Markdown
Member

There's one thing that we should still fix:

--- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs+++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs@@ -130,7 +130,9 @@ public override bool Execute()
continue;
}
- if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true)+ if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true &&+ !assemblyFileName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) &&+ !assemblyFileName.EndsWith(".dex", StringComparison.OrdinalIgnoreCase))
{
// Skip the native components of the runtime pack, we don't need them for NativeAOT.
assembliesToSkipPublish.Add(taskItem);

The native assets of the Android runtime files now contain the .jar/.dex files for libSystem.Security.Cryptography.Android. We should not strip them in ComputeManagedAssembliesToCompileToNative build target to keep the HTTP stack working.

@filipnavarafilipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested that it makes the Android runtime pack into functional state that can be consumed on the workload side and used to build a whole app. Obviously there's still work that has to be done on the consumption side (dotnet/android) but having an end-to-end scenrio running is a good start:

image

One thing that still needs to be resolved is who is responsible for exporting the JNI symbol for Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate in case of the builds that link the crypto libraries statically. Presumably that can and will be done on the Android workload side with something like <IlcArg Include="--export-dynamic-symbol:Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate" />.

@vitek-karas

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

@filipnavara

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

Yes, that's part of the solution. There's an issue for CoreCLR integration filed at dotnet/android#10324 that has a bit more context.

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/ba-g failures are unrelated

@jtschuster
jtschuster merged commit 1e322fd into dotnet:mainAug 11, 2025
154 of 162 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Sep 11, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

13 participants

@jtschuster@risc-vv@MichalStrehovsky@filipnavara@vitek-karas@steveisok@agocke@am11@jkotas@kotlarmilos@davidnguyen-tech@NayYeMaram
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add NativeAOT on Android test - #118037

Merged
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot
Aug 11, 2025
Merged

Add NativeAOT on Android test#118037
jtschuster merged 37 commits into
dotnet:mainfrom
jtschuster:AndroidAppBuilderNaot

Conversation

@jtschuster

@jtschusterjtschuster commented Jul 24, 2025

Copy link
Copy Markdown
Member

Adds a project to run a NativeAOT shared library on Android.

The android test builds a single native library that exports the methods that are expected by the monodroid tests (InitRuntime, SetEnv, ExecEntryPoint, FreeUnmanagedResources). JNI struct definitions are copied to get arg strings from the JNIEnv object.

ApkBuilder no longer needs to compile the monodroid native library, but it does need to add the java .jar from the cryptography library to the apk bundle in order to run crypto operations.

Build targets were updated to account for the new NativeAOT tests, and a new job was added for NativeAOT on android tests.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @akoeplinger, @matouskozak, @simonrozsival
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Comment threadsrc/coreclr/tools/Common/CommandLineHelpers.cs Outdated
@risc-vv

Copy link
Copy Markdown

@dotnet/samsung Could you please take a look? These changes may be related to riscv64.

Comment threadsrc/tasks/AndroidAppBuilder/ApkBuilder.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

- Don't use BundleDir for android bundle dir: This is PublishDir when TestSingleFile=true (which it is). Android deletes this dir before packaging, deleting the files that were just published.
- Don't add the singleFileTestRunner.cs when the test sets IsFunctionalTest=true
- Don't run regular nativeaot smoke tests on android yet.
- Enable android tests to publish as libs when TestSingleFile=true (default when TestNativeAOT=true)
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster
jtschuster marked this pull request as ready for review August 5, 2025 17:41
CopilotAI review requested due to automatic review settings August 5, 2025 17:41

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for running NativeAOT (Native Ahead-of-Time) compiled applications on Android. The implementation creates a shared library that exports the required JNI methods expected by the Android test infrastructure, eliminating the need for the monodroid runtime while maintaining compatibility with existing test frameworks.

Key changes include:

  • Added NativeAOT-specific Android test project and JNI interop layer
  • Updated build infrastructure to support NativeAOT runtime flavor
  • Modified Android app builder to handle NativeAOT library generation and packaging

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Program.csSimple test program that validates console output and cryptography functionality
src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csprojProject file configuring NativeAOT compilation with required JNI template inclusion
src/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.csJNI interop layer implementing required Android runtime interface methods
src/tasks/AndroidAppBuilder/Templates/MonoRunner.javaUpdated Java template to support dynamic library loading statements
src/tasks/AndroidAppBuilder/ApkBuilder.csEnhanced APK builder with NativeAOT runtime support and library packaging
src/mono/msbuild/android/build/AndroidBuild.targetsUpdated build targets to handle NativeAOT runtime flavor and dependencies
src/mono/msbuild/android/build/AndroidBuild.propsAdded Android NDK toolchain configuration and NativeAOT build dependencies
src/libraries/tests.projModified test project inclusion logic for NativeAOT Android tests
src/coreclr/nativeaot/Runtime/interoplibinterface_java.cppAdded missing thread.inl include for Java interop
src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targetsExtended cross-compilation support for android- RID prefix
src/coreclr/nativeaot/BuildIntegration/Microsoft.DotNet.ILCompiler.SingleEntry.targetsAdded Android bionic libc flavor detection
eng/testing/tests.singlefile.targetsConditional OutputType and compilation adjustments for Android NativeAOT
eng/testing/tests.android.targetsRemoved redundant AndroidBundleDir property assignment
eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.ymlAdded CI pipeline job for NativeAOT Android emulator testing
eng/pipelines/extra-platforms/runtime-extra-platforms-android.ymlAdded CI pipeline job for NativeAOT Android device testing

Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs
Comment threadsrc/tasks/AndroidAppBuilder/Templates/monodroid-nativeaot.cs Outdated
@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

filipnavara commented Aug 6, 2025

Copy link
Copy Markdown
Member

There's one thing that we should still fix:

--- a/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs+++ b/src/coreclr/tools/aot/ILCompiler.Build.Tasks/ComputeManagedAssembliesToCompileToNative.cs@@ -130,7 +130,9 @@ public override bool Execute()
continue;
}
- if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true)+ if (isFromRuntimePack && taskItem.GetMetadata("AssetType")?.Equals("native", StringComparison.OrdinalIgnoreCase) == true &&+ !assemblyFileName.EndsWith(".jar", StringComparison.OrdinalIgnoreCase) &&+ !assemblyFileName.EndsWith(".dex", StringComparison.OrdinalIgnoreCase))
{
// Skip the native components of the runtime pack, we don't need them for NativeAOT.
assembliesToSkipPublish.Add(taskItem);

The native assets of the Android runtime files now contain the .jar/.dex files for libSystem.Security.Cryptography.Android. We should not strip them in ComputeManagedAssembliesToCompileToNative build target to keep the HTTP stack working.

@filipnavarafilipnavara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tested that it makes the Android runtime pack into functional state that can be consumed on the workload side and used to build a whole app. Obviously there's still work that has to be done on the consumption side (dotnet/android) but having an end-to-end scenrio running is a good start:

image

One thing that still needs to be resolved is who is responsible for exporting the JNI symbol for Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate in case of the builds that link the crypto libraries statically. Presumably that can and will be done on the Android workload side with something like <IlcArg Include="--export-dynamic-symbol:Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate" />.

@vitek-karas

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

@filipnavara

Copy link
Copy Markdown
Member

@filipnavara maybe this will solve the JNI export problem for crypto: #108513

Yes, that's part of the solution. There's an issue for CoreCLR integration filed at dotnet/android#10324 that has a bit more context.

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-androidemulator

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jtschuster

Copy link
Copy Markdown
MemberAuthor

/ba-g failures are unrelated

@jtschuster
jtschuster merged commit 1e322fd into dotnet:mainAug 11, 2025
154 of 162 checks passed
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Sep 11, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

13 participants

@jtschuster@risc-vv@MichalStrehovsky@filipnavara@vitek-karas@steveisok@agocke@am11@jkotas@kotlarmilos@davidnguyen-tech@NayYeMaram