This commit is contained in:
Jackson Schuster 2025-07-30 15:56:24 +02:00 committed by GitHub
commit fd886269ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 634 additions and 87 deletions

View File

@ -993,6 +993,48 @@ extends:
eq(variables['coreclrContainsChange'], true),
eq(variables['isRollingBuild'], true))
#
# Android arm64 devices and x64 emulators
# Build the whole product using CoreCLR and run functional tests
#
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/common/global-build-job.yml
helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
buildConfig: Release
runtimeFlavor: nativeaot
platforms:
- android_x64
- android_arm64
variables:
# map dependencies variables to local variables
- name: librariesContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
- name: coreclrContainsChange
value: $[ stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'] ]
jobParameters:
testGroup: innerloop
nameSuffix: NativeAOT
buildArgs: -s clr.aot+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=true /p:UseNativeAOTRuntime=true /p:RuntimeFlavor=nativeaot /p:TestNativeAOT=true
timeoutInMinutes: 120
condition: >-
or(
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true),
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true),
eq(variables['isRollingBuild'], true))
# extra steps, run tests
postBuildSteps:
- template: /eng/pipelines/libraries/helix.yml
parameters:
creator: dotnet-bot
testRunNamePrefixSuffix: NativeAOT_$(_BuildConfig)
condition: >-
or(
eq(variables['librariesContainsChange'], true),
eq(variables['coreclrContainsChange'], true),
eq(variables['isRollingBuild'], true))
#
# iOS/tvOS devices - Full AOT + AggressiveTrimming to reduce size
# Build the whole product using Mono and run libraries tests

View File

@ -66,14 +66,14 @@
RuntimeFrameworkName="$(LocalFrameworkOverrideName)"
LatestRuntimeFrameworkVersion="$(ProductVersion)"
RuntimePackNamePatterns="$(LocalFrameworkOverrideName).Runtime.NativeAOT.**RID**"
RuntimePackRuntimeIdentifiers="ios-arm64;iossimulator-arm64;iossimulator-x64;tvos-arm64;tvossimulator-arm64;tvossimulator-x64;maccatalyst-arm64;maccatalyst-x64;linux-bionic-arm64;linux-bionic-x64;osx-arm64;osx-x64"
RuntimePackRuntimeIdentifiers="ios-arm64;iossimulator-arm64;iossimulator-x64;tvos-arm64;tvossimulator-arm64;tvossimulator-x64;maccatalyst-arm64;maccatalyst-x64;linux-bionic-arm64;linux-bionic-x64;android-x64;android-arm64;osx-arm64;osx-x64"
RuntimePackLabels="NativeAOT"
Condition="'$(UseLocalTargetingRuntimePack)' == 'true' and ('@(KnownRuntimePack)' == '' or @(KnownRuntimePack->WithMetadataValue('Identity', 'Microsoft.NETCore.App')->WithMetadataValue('RuntimePackLabels', 'NativeAOT')->WithMetadataValue('TargetFramework', '$(NetCoreAppCurrent)')) == '')" />
<KnownILCompilerPack Include="Microsoft.DotNet.ILCompiler"
ILCompilerPackNamePattern="runtime.**RID**.Microsoft.DotNet.ILCompiler"
TargetFramework="$(NetCoreAppCurrent)"
ILCompilerPackVersion="$(ProductVersion)"
ILCompilerRuntimeIdentifiers="linux-musl-x64;linux-x64;win-x64;linux-arm;linux-arm64;linux-musl-arm;linux-musl-arm64;osx-arm64;osx-x64;win-arm64;win-x86;linux-riscv64;linux-musl-riscv64;linux-loongarch64;linux-musl-loongarch64"
ILCompilerRuntimeIdentifiers="linux-musl-x64;linux-x64;win-x64;linux-arm;linux-arm64;linux-musl-arm;linux-musl-arm64;osx-arm64;osx-x64;win-arm64;win-x86;linux-riscv64;linux-musl-riscv64;linux-loongarch64;linux-musl-loongarch64;android-x64;linux-bionic-x64;android-arm64;linux-bionic-arm64"
Condition="'$(UseLocalILCompilerPack)' == 'true' and '@(KnownILCompilerPack->AnyHaveMetadataValue('TargetFramework', '$(NetCoreAppCurrent)'))' != 'true'" />
<KnownCrossgen2Pack Include="$(LocalFrameworkOverrideName).Crossgen2"
TargetFramework="$(NetCoreAppCurrent)"

View File

@ -28,7 +28,6 @@
<MainLibraryFileName Condition="'$(MainLibraryFileName)' == ''">AndroidTestRunner.dll</MainLibraryFileName>
<AndroidBuildDir>$(PublishDir)</AndroidBuildDir>
<AndroidBundleDir>$(BundleDir)</AndroidBundleDir>
</PropertyGroup>
<ItemGroup>

View File

@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>
<OutputType Condition="'$(TargetOS)' != 'android'">Exe</OutputType>
<BundleDir>$([MSBuild]::NormalizeDirectory('$(OutDir)', 'publish'))</BundleDir>
<RunScriptOutputPath>$([MSBuild]::NormalizePath('$(BundleDir)', '$(RunScriptOutputName)'))</RunScriptOutputPath>
@ -49,7 +49,8 @@
<ItemGroup>
<Compile Include="$(CommonTestPath)SingleFileTestRunner\SingleFileTestRunner.cs"
Link="Common\SingleFileTestRunner\SingleFileTestRunner.cs" />
Link="Common\SingleFileTestRunner\SingleFileTestRunner.cs"
Condition="'$(IsFunctionalTest)' != 'true'" />
</ItemGroup>
<ItemGroup>

View File

@ -31,6 +31,7 @@
<_targetOS>$(_originalTargetOS)</_targetOS>
<_linuxToken>linux-</_linuxToken>
<_linuxLibcFlavor Condition="$(_targetOS.StartsWith($(_linuxToken)))">$(_targetOS.SubString($(_linuxToken.Length)))</_linuxLibcFlavor>
<_linuxLibcFlavor Condition="'$(_targetOS)' == 'android'">bionic</_linuxLibcFlavor>
<_targetOS Condition="$(_targetOS.StartsWith($(_linuxToken)))">linux</_targetOS>
<!-- linux-bionic on ARM uses armel (softfp) ABI -->

View File

@ -47,7 +47,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<CrossCompileArch Condition="$(CrossCompileRid.EndsWith('-arm'))">armv7</CrossCompileArch>
<CrossCompileAbi>gnu</CrossCompileAbi>
<CrossCompileAbi Condition="$(CrossCompileRid.StartsWith('linux-bionic-'))">android21</CrossCompileAbi>
<CrossCompileAbi Condition="$(CrossCompileRid.StartsWith('linux-bionic-')) or $(CrossCompileRid.StartsWith('android'))">android21</CrossCompileAbi>
<CrossCompileAbi Condition="$(CrossCompileRid.StartsWith('linux-musl-')) or $(CrossCompileRid.StartsWith('alpine-'))">musl</CrossCompileAbi>
<CrossCompileAbi Condition="'$(CrossCompileRid)' == 'linux-arm'">gnueabihf</CrossCompileAbi>
<CrossCompileAbi Condition="'$(CrossCompileRid)' == 'linux-bionic-arm'">androideabi21</CrossCompileAbi>

View File

@ -574,7 +574,7 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)System.Runtime\tests\System.Globalization.Tests\System.Globalization.Tests.csproj" Condition="'$(OS)' != 'Windows_NT'" />
</ItemGroup>
<ItemGroup Condition="'$(TestNativeAot)' == 'true'">
<ItemGroup Condition="'$(TestNativeAot)' == 'true' and '$(TargetOS)' != 'android'">
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Collections\tests\System.Collections.Tests.csproj" />
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.IO.Compression\tests\System.IO.Compression.Tests.csproj" />
<SmokeTestProject Include="$(MSBuildThisFileDirectory)System.Linq.Expressions\tests\System.Linq.Expressions.Tests.csproj" />
@ -607,6 +607,10 @@
<SmokeTestProject Include="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\JIT\*.Test.csproj"/>
</ItemGroup>
<ItemGroup Condition="'$(TargetOS)' == 'android' and '$(RuntimeFlavor)' == 'NativeAOT'">
<SmokeTestProject Include="$(RepoRoot)src\tests\FunctionalTests\Android\Device_Emulator\NativeAOT\*.Test.csproj"/>
</ItemGroup>
<ItemGroup Condition="('$(TargetOS)' == 'iossimulator' or '$(TargetOS)' == 'tvossimulator') and '$(RuntimeFlavor)' == 'CoreCLR'">
<SmokeTestProject Remove="@(SmokeTestProject)" />
<SmokeTestProject Include="$(RepoRoot)\src\tests\FunctionalTests\iOS\Simulator\CoreCLR.Interpreter\*.Test.csproj"/>

View File

@ -3,7 +3,7 @@
<RuntimeIdentifier>$(TargetOS)-$(TargetArchitecture.ToLowerInvariant())</RuntimeIdentifier>
<!-- TODO: Revisit this.
We need to check for RuntimeFlavor setting as for runtime tests we always import CoreCLR props which force UseMonoRuntime=false (see: https://github.com/dotnet/runtime/issues/111919) -->
<UseMonoRuntime Condition="'$(RuntimeFlavor)' == 'coreclr'">false</UseMonoRuntime>
<UseMonoRuntime Condition="'$(RuntimeFlavor)' == 'coreclr' or '$(RuntimeFlavor)' == 'nativeaot'">false</UseMonoRuntime>
<UseMonoRuntime Condition="'$(UseMonoRuntime)' == '' or '$(RuntimeFlavor)' == 'mono'">true</UseMonoRuntime>
<UseMonoJustInterp Condition="'$(UseMonoRuntime)' == 'true' and '$(RunAOTCompilation)' == 'true' and '$(MonoForceInterpreter)' == 'true'">true</UseMonoJustInterp>
@ -14,8 +14,15 @@
<_IsLibraryMode Condition="'$(UseMonoRuntime)' == 'true' and '$(UseNativeAOTRuntime)' != 'true' and '$(NativeLib)' != ''">true</_IsLibraryMode>
<_ReadRuntimeComponentsManifestTargetName Condition="'$(UseMonoRuntime)' == 'true' and '$(UseNativeAOTRuntime)' != 'true'">_MonoReadAvailableComponentsManifest</_ReadRuntimeComponentsManifestTargetName>
<StaticLinkedRuntime Condition="'$(RuntimeFlavor)' == 'nativeaot'">false</StaticLinkedRuntime>
<StaticLinkedRuntime Condition="'$(RuntimeFlavor)' == 'coreclr' and '$(StaticLinkedRuntime)' == ''">false</StaticLinkedRuntime>
<!-- Android NDK uses x86_64 as the architecture for naming, even on MacOS arm64 -->
<NdkToolchainPrebuiltOS Condition="$([MSBuild]::IsOSPlatform('Linux'))">linux-x86_64</NdkToolchainPrebuiltOS>
<NdkToolchainPrebuiltOS Condition="$([MSBuild]::IsOSPlatform('OSX'))">darwin-x86_64</NdkToolchainPrebuiltOS>
<NdkToolchainPrebuiltOS Condition="'$(HostOS)' == 'windows'">windows-x86_64</NdkToolchainPrebuiltOS>
<CppCompilerAndLinker>$(ANDROID_NDK_ROOT)\toolchains\llvm\prebuilt\$(NdkToolchainPrebuiltOS)\bin\clang</CppCompilerAndLinker>
<AndroidBuildAfterThisTarget Condition="'$(AndroidBuildAfterThisTarget)' == ''">Publish</AndroidBuildAfterThisTarget>
<AndroidBuildDependsOn Condition="'$(UseMonoRuntime)' == 'true'">
$(_ReadRuntimeComponentsManifestTargetName);
@ -35,6 +42,11 @@
_AndroidGenerateAppBundle;
_AfterAndroidBuild
</AndroidBuildDependsOn>
<AndroidBuildDependsOn Condition="'$(UseNativeAOTRuntime)' == 'true'">
$(AndroidBuildDependsOn);
CopyNativeBinary;
_CopyAotSymbols
</AndroidBuildDependsOn>
<!-- When building on Helix $(_CommonTargetsDir) will be properly set, otherwise we have to set it to a in-tree location -->
<_CommonTargetsDir Condition="'$(_CommonTargetsDir)' == ''">$([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory), '..', '..', 'common'))</_CommonTargetsDir>

View File

@ -239,6 +239,7 @@
We are using a private property to determine the target runtime, we should instead unify the resolution with Apple targets instead, (see: https://github.com/dotnet/runtime/issues/111923) -->
<_RuntimeFlavor>Mono</_RuntimeFlavor>
<_RuntimeFlavor Condition="'$(UseMonoRuntime)' == 'false' and '$(UseNativeAOTRuntime)' != 'true'">CoreCLR</_RuntimeFlavor>
<_RuntimeFlavor Condition="'$(UseNativeAOTRuntime)' == 'true'">nativeaot</_RuntimeFlavor>
</PropertyGroup>
<AndroidAppBuilderTask
@ -290,4 +291,5 @@
RuntimeConfigReservedProperties="@(_RuntimeConfigReservedProperties)">
</RuntimeConfigParserTask>
</Target>
</Project>

View File

@ -16,7 +16,8 @@ using Microsoft.Build.Utilities;
public enum RuntimeFlavorEnum
{
Mono,
CoreCLR
CoreCLR,
NativeAOT
}
public partial class ApkBuilder
@ -53,6 +54,7 @@ public partial class ApkBuilder
private RuntimeFlavorEnum parsedRuntimeFlavor;
private bool IsMono => parsedRuntimeFlavor == RuntimeFlavorEnum.Mono;
private bool IsCoreCLR => parsedRuntimeFlavor == RuntimeFlavorEnum.CoreCLR;
private bool IsNativeAOT => parsedRuntimeFlavor == RuntimeFlavorEnum.NativeAOT;
private TaskLoggingHelper logger;
@ -91,7 +93,8 @@ public partial class ApkBuilder
throw new ArgumentException($"ProjectName='{ProjectName}' should not not contain spaces.");
}
if (string.IsNullOrEmpty(AndroidSdk)){
if (string.IsNullOrEmpty(AndroidSdk))
{
AndroidSdk = Environment.GetEnvironmentVariable("ANDROID_SDK_ROOT");
}
@ -154,7 +157,7 @@ public partial class ApkBuilder
var assemblerFilesToLink = new StringBuilder();
var aotLibraryFiles = new List<string>();
if (!IsLibraryMode)
if (!(IsLibraryMode || IsNativeAOT))
{
foreach (ITaskItem file in Assemblies)
{
@ -244,7 +247,7 @@ public partial class ApkBuilder
{
nativeLibraries = string.Join("\n ", NativeDependencies.Select(dep => dep));
}
else
else if (!IsNativeAOT)
{
string runtimeLib = "";
if (StaticLinkedRuntime && IsMono)
@ -325,79 +328,85 @@ public partial class ApkBuilder
nativeLibraries += $" libc++_static.a{Environment.NewLine}";
}
}
StringBuilder extraLinkerArgs = new StringBuilder();
foreach (ITaskItem item in ExtraLinkerArguments)
string abi;
if (IsNativeAOT)
{
extraLinkerArgs.AppendLine($" \"{item.ItemSpec}\"");
abi = AndroidProject.DetermineAbi(runtimeIdentifier);
}
if (StaticLinkedRuntime && IsCoreCLR)
else
{
// Ensure global symbol references in the shared library are resolved to definitions in
// the same shared library. For the static linked runtime specifically, we need this for
// global functions in assembly for the linker to treat relative offsets to them as constant
extraLinkerArgs.AppendLine($" \"-Wl,-Bsymbolic\"");
}
nativeLibraries += assemblerFilesToLink.ToString();
string aotSources = assemblerFiles.ToString();
string monodroidSource = IsCoreCLR ?
"monodroid-coreclr.c" : (IsLibraryMode) ? "monodroid-librarymode.c" : "monodroid.c";
string runtimeInclude = string.Join(" ", runtimeHeaders.Select(h => $"\"{NormalizePathToUnix(h)}\""));
string cmakeLists = Utils.GetEmbeddedResource("CMakeLists-android.txt")
.Replace("%RuntimeInclude%", runtimeInclude)
.Replace("%NativeLibrariesToLink%", NormalizePathToUnix(nativeLibraries))
.Replace("%MONODROID_SOURCE%", monodroidSource)
.Replace("%AotSources%", NormalizePathToUnix(aotSources))
.Replace("%AotModulesSource%", string.IsNullOrEmpty(aotSources) ? "" : "modules.c")
.Replace("%APP_LINKER_ARGS%", extraLinkerArgs.ToString());
var defines = new StringBuilder();
if (ForceInterpreter)
{
defines.AppendLine("add_definitions(-DFORCE_INTERPRETER=1)");
}
else if (ForceAOT)
{
defines.AppendLine("add_definitions(-DFORCE_AOT=1)");
if (aotLibraryFiles.Count == 0)
StringBuilder extraLinkerArgs = new StringBuilder();
foreach (ITaskItem item in ExtraLinkerArguments)
{
defines.AppendLine("add_definitions(-DSTATIC_AOT=1)");
extraLinkerArgs.AppendLine($" \"{item.ItemSpec}\"");
}
if (StaticLinkedRuntime && IsCoreCLR)
{
// Ensure global symbol references in the shared library are resolved to definitions in
// the same shared library. For the static linked runtime specifically, we need this for
// global functions in assembly for the linker to treat relative offsets to them as constant
extraLinkerArgs.AppendLine($" \"-Wl,-Bsymbolic\"");
}
nativeLibraries += assemblerFilesToLink.ToString();
string aotSources = assemblerFiles.ToString();
string monodroidSource = IsCoreCLR ?
"monodroid-coreclr.c" : (IsLibraryMode) ? "monodroid-librarymode.c" : "monodroid.c";
string runtimeInclude = string.Join(" ", runtimeHeaders.Select(h => $"\"{NormalizePathToUnix(h)}\""));
string cmakeLists = Utils.GetEmbeddedResource("CMakeLists-android.txt")
.Replace("%RuntimeInclude%", runtimeInclude)
.Replace("%NativeLibrariesToLink%", NormalizePathToUnix(nativeLibraries))
.Replace("%MONODROID_SOURCE%", monodroidSource)
.Replace("%AotSources%", NormalizePathToUnix(aotSources))
.Replace("%AotModulesSource%", string.IsNullOrEmpty(aotSources) ? "" : "modules.c")
.Replace("%APP_LINKER_ARGS%", extraLinkerArgs.ToString());
var defines = new StringBuilder();
if (ForceInterpreter)
{
defines.AppendLine("add_definitions(-DFORCE_INTERPRETER=1)");
}
else if (ForceAOT)
{
defines.AppendLine("add_definitions(-DFORCE_AOT=1)");
if (aotLibraryFiles.Count == 0)
{
defines.AppendLine("add_definitions(-DSTATIC_AOT=1)");
}
}
if (ForceFullAOT)
{
defines.AppendLine("add_definitions(-DFULL_AOT=1)");
}
if (!string.IsNullOrEmpty(DiagnosticPorts))
{
defines.AppendLine("add_definitions(-DDIAGNOSTIC_PORTS=\"" + DiagnosticPorts + "\")");
}
cmakeLists = cmakeLists.Replace("%Defines%", defines.ToString());
File.WriteAllText(Path.Combine(OutputDir, "CMakeLists.txt"), cmakeLists);
string monodroidContent = Utils.GetEmbeddedResource(monodroidSource);
if (IsCoreCLR)
{
monodroidContent = RenderMonodroidCoreClrTemplate(monodroidContent);
}
File.WriteAllText(Path.Combine(OutputDir, monodroidSource), monodroidContent);
AndroidProject project = new AndroidProject("monodroid", runtimeIdentifier, AndroidNdk, logger);
project.GenerateCMake(OutputDir, MinApiLevel, StripDebugSymbols);
project.BuildCMake(OutputDir, StripDebugSymbols);
abi = project.Abi;
// TODO: https://github.com/dotnet/runtime/issues/115717
}
if (ForceFullAOT)
{
defines.AppendLine("add_definitions(-DFULL_AOT=1)");
}
if (!string.IsNullOrEmpty(DiagnosticPorts))
{
defines.AppendLine("add_definitions(-DDIAGNOSTIC_PORTS=\"" + DiagnosticPorts + "\")");
}
cmakeLists = cmakeLists.Replace("%Defines%", defines.ToString());
File.WriteAllText(Path.Combine(OutputDir, "CMakeLists.txt"), cmakeLists);
string monodroidContent = Utils.GetEmbeddedResource(monodroidSource);
if (IsCoreCLR)
{
monodroidContent = RenderMonodroidCoreClrTemplate(monodroidContent);
}
File.WriteAllText(Path.Combine(OutputDir, monodroidSource), monodroidContent);
AndroidProject project = new AndroidProject("monodroid", runtimeIdentifier, AndroidNdk, logger);
project.GenerateCMake(OutputDir, MinApiLevel, StripDebugSymbols);
project.BuildCMake(OutputDir, StripDebugSymbols);
// TODO: https://github.com/dotnet/runtime/issues/115717
string abi = project.Abi;
// 2. Compile Java files
string javaSrcFolder = Path.Combine(OutputDir, "src", "net", "dot");
@ -430,11 +439,22 @@ public partial class ApkBuilder
envVariables += $"\t\tsetEnv(\"{name}\", \"{value}\");\n";
}
string jniLibraryName = (IsLibraryMode) ? ProjectName! :
(StaticLinkedRuntime && IsCoreCLR) ? "monodroid" : "System.Security.Cryptography.Native.Android";
string jniLibraryName;
if (IsLibraryMode || IsNativeAOT)
jniLibraryName = ProjectName!;
else if (StaticLinkedRuntime && IsCoreCLR)
jniLibraryName = "monodroid";
else
jniLibraryName = "System.Security.Cryptography.Native.Android";
List<string> librariesToLoad = [jniLibraryName];
if (!IsNativeAOT)
librariesToLoad.Add("monodroid");
string monoRunner = Utils.GetEmbeddedResource("MonoRunner.java")
.Replace("%EntryPointLibName%", Path.GetFileName(mainLibraryFileName))
.Replace("%JNI_LIBRARY_NAME%", jniLibraryName)
.Replace("%LoadLibraryStatements%",
string.Join('\n', librariesToLoad.Select(l => $"System.loadLibrary(\"{l}\");")))
.Replace("%EnvVariables%", envVariables);
File.WriteAllText(monoRunnerPath, monoRunner);
@ -455,8 +475,13 @@ public partial class ApkBuilder
if (classFiles.Length == 0)
throw new InvalidOperationException("Didn't find any .class files");
List<string> inputFiles = [.. classFiles];
if (IsNativeAOT)
{
inputFiles.Add(Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(AppDir)!)!, "libSystem.Security.Cryptography.Native.Android.jar"));
}
Utils.RunProcess(logger, androidSdkHelper.D8Path, $"--no-desugaring {string.Join(" ", classFiles)}", workingDir: OutputDir);
Utils.RunProcess(logger, androidSdkHelper.D8Path, $"--no-desugaring {string.Join(" ", inputFiles)}", workingDir: OutputDir);
}
else
{
@ -470,7 +495,8 @@ public partial class ApkBuilder
Utils.RunProcess(logger, androidSdkHelper.AaptPath, $"package -f -m -F {apkFile} -A assets -M AndroidManifest.xml -I {androidJar} {debugModeArg}", workingDir: OutputDir);
var dynamicLibs = new List<string>();
dynamicLibs.Add(Path.Combine(OutputDir, "monodroid", "libmonodroid.so"));
if (!IsNativeAOT)
dynamicLibs.Add(Path.Combine(OutputDir, "monodroid", "libmonodroid.so"));
if (IsLibraryMode)
{
@ -533,7 +559,6 @@ public partial class ApkBuilder
}
// NOTE: we can run android-strip tool from NDK to shrink native binaries here even more.
File.Copy(dynamicLib, Path.Combine(OutputDir, destRelative), true);
Utils.RunProcess(logger, androidSdkHelper.AaptPath, $"add {apkFile} {NormalizePathToUnix(destRelative)}", workingDir: OutputDir);
}

View File

@ -34,8 +34,7 @@ public class MonoRunner extends Instrumentation
{
static {
// loadLibrary triggers JNI_OnLoad in these libs
System.loadLibrary("%JNI_LIBRARY_NAME%");
System.loadLibrary("monodroid");
%LoadLibraryStatements%
}
static String testResultsDir;

View File

@ -0,0 +1,422 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.InteropServices;
using System.Runtime;
using System;
using System.Runtime.CompilerServices;
using JObject = nint;
using JString = nint;
using JObjectArray = nint;
namespace MonoDroid.NativeAOT;
#pragma warning disable IDE0060 // Remove unused parameter
internal static unsafe partial class MonoDroidExports
{
// void Java_net_dot_MonoRunner_setEnv (JNIEnv* env, jobject thiz, jstring j_key, jstring j_value);
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }, EntryPoint = "Java_net_dot_MonoRunner_setEnv")]
public static void SetEnv(JNIEnv* env, JObject thiz, JString j_key, JString j_value)
{
string key = env->GetStringUTFChars(j_key);
string value = env->GetStringUTFChars(j_value);
Environment.SetEnvironmentVariable(key, value);
}
// int Java_net_dot_MonoRunner_initRuntime (JNIEnv* env, jobject thiz, jstring j_files_dir, jstring j_entryPointLibName, long current_local_time);
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }, EntryPoint = "Java_net_dot_MonoRunner_initRuntime")]
public static int InitRuntime(JNIEnv* env, JObject thiz, JString j_files_dir, JString j_entryPointLibName, long current_local_time)
{
// The NativeAOT runtime does not need to be initialized, but the crypto library does.
JavaVM* javaVM = env->GetJavaVM();
AndroidCryptoNative_InitLibraryOnLoad(javaVM, null);
return 0;
}
[LibraryImport("System.Security.Cryptography.Native.Android")]
internal static partial int AndroidCryptoNative_InitLibraryOnLoad(JavaVM* vm, void* reserved);
// int Java_net_dot_MonoRunner_execEntryPoint (JNIEnv* env, jobject thiz, jstring j_entryPointLibName, jobjectArray j_args);
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }, EntryPoint = "Java_net_dot_MonoRunner_execEntryPoint")]
public static int ExecEntryPoint(JNIEnv* env, JObject thiz, JString j_entryPointLibName, JObjectArray j_args)
{
return Program.Main();
}
// void Java_net_dot_MonoRunner_freeNativeResources (JNIEnv* env, jobject thiz);
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) }, EntryPoint = "Java_net_dot_MonoRunner_freeNativeResources")]
public static void FreeNativeResources(JNIEnv* env, JObject thiz)
{
// Placeholder for actual implementation
Console.WriteLine("FreeNativeResources start");
}
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct JNIEnv
{
JNINativeInterface* NativeInterface;
public string GetStringUTFChars(JString str)
{
fixed (JNIEnv* thisptr = &this)
{
byte* chars = NativeInterface->GetStringUTFChars(thisptr, str, out byte isCopy);
string result = Marshal.PtrToStringUTF8((nint)chars);
if (isCopy != 0)
NativeInterface->ReleaseStringUTFChars(thisptr, str, chars);
return result;
}
}
public JavaVM* GetJavaVM()
{
fixed (JNIEnv* thisptr = &this)
{
JavaVM* vm;
NativeInterface->GetJavaVM(thisptr, &vm);
return vm;
}
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct JNINativeInterface
{
void* reserved0;
void* reserved1;
void* reserved2;
void* reserved3;
void* GetVersion;
void* DefineClass;
void* FindClass;
void* FromReflectedMethod;
void* FromReflectedField;
void* ToReflectedMethod;
void* GetSuperclass;
void* IsAssignableFrom;
void* ToReflectedField;
void* Throw;
void* ThrowNew;
void* ExceptionOccurred;
void* ExceptionDescribe;
void* ExceptionClear;
void* FatalError;
void* PushLocalFrame;
void* PopLocalFrame;
void* NewGlobalRef;
void* DeleteGlobalRef;
void* DeleteLocalRef;
void* IsSameObject;
void* NewLocalRef;
void* EnsureLocalCapacity;
void* AllocObject;
void* NewObject;
void* NewObjectV;
void* NewObjectA;
void* GetObjectClass;
void* IsInstanceOf;
void* GetMethodID;
void* CallObjectMethod;
void* CallObjectMethodV;
void* CallObjectMethodA;
void* CallBooleanMethod;
void* CallBooleanMethodV;
void* CallBooleanMethodA;
void* CallByteMethod;
void* CallByteMethodV;
void* CallByteMethodA;
void* CallCharMethod;
void* CallCharMethodV;
void* CallCharMethodA;
void* CallShortMethod;
void* CallShortMethodV;
void* CallShortMethodA;
void* CallIntMethod;
void* CallIntMethodV;
void* CallIntMethodA;
void* CallLongMethod;
void* CallLongMethodV;
void* CallLongMethodA;
void* CallFloatMethod;
void* CallFloatMethodV;
void* CallFloatMethodA;
void* CallDoubleMethod;
void* CallDoubleMethodV;
void* CallDoubleMethodA;
void* CallVoidMethod;
void* CallVoidMethodV;
void* CallVoidMethodA;
void* CallNonvirtualObjectMethod;
void* CallNonvirtualObjectMethodV;
void* CallNonvirtualObjectMethodA;
void* CallNonvirtualBooleanMethod;
void* CallNonvirtualBooleanMethodV;
void* CallNonvirtualBooleanMethodA;
void* CallNonvirtualByteMethod;
void* CallNonvirtualByteMethodV;
void* CallNonvirtualByteMethodA;
void* CallNonvirtualCharMethod;
void* CallNonvirtualCharMethodV;
void* CallNonvirtualCharMethodA;
void* CallNonvirtualShortMethod;
void* CallNonvirtualShortMethodV;
void* CallNonvirtualShortMethodA;
void* CallNonvirtualIntMethod;
void* CallNonvirtualIntMethodV;
void* CallNonvirtualIntMethodA;
void* CallNonvirtualLongMethod;
void* CallNonvirtualLongMethodV;
void* CallNonvirtualLongMethodA;
void* CallNonvirtualFloatMethod;
void* CallNonvirtualFloatMethodV;
void* CallNonvirtualFloatMethodA;
void* CallNonvirtualDoubleMethod;
void* CallNonvirtualDoubleMethodV;
void* CallNonvirtualDoubleMethodA;
void* CallNonvirtualVoidMethod;
void* CallNonvirtualVoidMethodV;
void* CallNonvirtualVoidMethodA;
void* GetFieldID;
void* GetObjectField;
void* GetBooleanField;
void* GetByteField;
void* GetCharField;
void* GetShortField;
void* GetIntField;
void* GetLongField;
void* GetFloatField;
void* GetDoubleField;
void* SetObjectField;
void* SetBooleanField;
void* SetByteField;
void* SetCharField;
void* SetShortField;
void* SetIntField;
void* SetLongField;
void* SetFloatField;
void* SetDoubleField;
void* GetStaticMethodID;
void* CallStaticObjectMethod;
void* CallStaticObjectMethodV;
void* CallStaticObjectMethodA;
void* CallStaticBooleanMethod;
void* CallStaticBooleanMethodV;
void* CallStaticBooleanMethodA;
void* CallStaticByteMethod;
void* CallStaticByteMethodV;
void* CallStaticByteMethodA;
void* CallStaticCharMethod;
void* CallStaticCharMethodV;
void* CallStaticCharMethodA;
void* CallStaticShortMethod;
void* CallStaticShortMethodV;
void* CallStaticShortMethodA;
void* CallStaticIntMethod;
void* CallStaticIntMethodV;
void* CallStaticIntMethodA;
void* CallStaticLongMethod;
void* CallStaticLongMethodV;
void* CallStaticLongMethodA;
void* CallStaticFloatMethod;
void* CallStaticFloatMethodV;
void* CallStaticFloatMethodA;
void* CallStaticDoubleMethod;
void* CallStaticDoubleMethodV;
void* CallStaticDoubleMethodA;
void* CallStaticVoidMethod;
void* CallStaticVoidMethodV;
void* CallStaticVoidMethodA;
void* GetStaticFieldID;
void* GetStaticObjectField;
void* GetStaticBooleanField;
void* GetStaticByteField;
void* GetStaticCharField;
void* GetStaticShortField;
void* GetStaticIntField;
void* GetStaticLongField;
void* GetStaticFloatField;
void* GetStaticDoubleField;
void* SetStaticObjectField;
void* SetStaticBooleanField;
void* SetStaticByteField;
void* SetStaticCharField;
void* SetStaticShortField;
void* SetStaticIntField;
void* SetStaticLongField;
void* SetStaticFloatField;
void* SetStaticDoubleField;
void* NewString;
void* GetStringLength;
void* GetStringChars;
void* ReleaseStringChars;
void* NewStringUTF;
delegate* unmanaged[Cdecl]<JNIEnv*, JString, int> GetStringUTFLength;
public delegate* unmanaged[Cdecl]<JNIEnv*, JString, out byte, byte*> GetStringUTFChars;
public delegate* unmanaged[Cdecl]<JNIEnv*, JString, byte*, void> ReleaseStringUTFChars;
void* GetArrayLength;
void* NewObjectArray;
void* GetObjectArrayElement;
void* SetObjectArrayElement;
void* NewBooleanArray;
void* NewByteArray;
void* NewCharArray;
void* NewShortArray;
void* NewIntArray;
void* NewLongArray;
void* NewFloatArray;
void* NewDoubleArray;
void* GetBooleanArrayElements;
void* GetByteArrayElements;
void* GetCharArrayElements;
void* GetShortArrayElements;
void* GetIntArrayElements;
void* GetLongArrayElements;
void* GetFloatArrayElements;
void* GetDoubleArrayElements;
void* ReleaseBooleanArrayElements;
void* ReleaseByteArrayElements;
void* ReleaseCharArrayElements;
void* ReleaseShortArrayElements;
void* ReleaseIntArrayElements;
void* ReleaseLongArrayElements;
void* ReleaseFloatArrayElements;
void* ReleaseDoubleArrayElements;
void* GetBooleanArrayRegion;
void* GetByteArrayRegion;
void* GetCharArrayRegion;
void* GetShortArrayRegion;
void* GetIntArrayRegion;
void* GetLongArrayRegion;
void* GetFloatArrayRegion;
void* GetDoubleArrayRegion;
void* SetBooleanArrayRegion;
void* SetByteArrayRegion;
void* SetCharArrayRegion;
void* SetShortArrayRegion;
void* SetIntArrayRegion;
void* SetLongArrayRegion;
void* SetFloatArrayRegion;
void* SetDoubleArrayRegion;
void* RegisterNatives;
void* UnregisterNatives;
void* MonitorEnter;
void* MonitorExit;
public delegate* unmanaged[Cdecl]<JNIEnv*, JavaVM**, int> GetJavaVM;
void* GetStringRegion;
void* GetStringUTFRegion;
void* GetPrimitiveArrayCritical;
void* ReleasePrimitiveArrayCritical;
void* GetStringCritical;
void* ReleaseStringCritical;
void* NewWeakGlobalRef;
void* DeleteWeakGlobalRef;
void* ExceptionCheck;
void* NewDirectByteBuffer;
void* GetDirectBufferAddress;
void* GetDirectBufferCapacity;
/* New JNI 1.6 Features */
void* GetObjectRefType;
/* Module Features */
void* GetModule;
/* Virtual threads */
void* IsVirtualThread;
/* Large UTF8 Support */
void* GetStringUTFLengthAsLong;
};
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct JavaVM
{
JNIInvokeInterface* InvokeInterface;
[StructLayout(LayoutKind.Sequential)]
struct JNIInvokeInterface
{
void* reserved0;
void* reserved1;
void* reserved2;
void* DestroyJavaVM;
void* AttachCurrentThread;
void* DetachCurrentThread;
void* GetEnv;
void* AttachCurrentThreadAsDaemon;
}
}
#pragma warning restore IDE0060 // Remove unused parameter

View File

@ -151,7 +151,7 @@ namespace Microsoft.Android.Build
return "linux";
}
private static string DetermineAbi(string runtimeIdentifier) =>
public static string DetermineAbi(string runtimeIdentifier) =>
runtimeIdentifier switch
{
"android-x86" => "x86",

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- ./dotnet.sh build -c <Debug|Release> src/tests/FunctionalTests/Android/Device_Emulator/NativeAOT/Android.Device_Emulator.NativeAOT.Test.csproj /t:Test -bl /p:targetos=android /p:targetarchitecture=x64 -->
<PropertyGroup>
<OutputType>Library</OutputType>
<TestRuntime>true</TestRuntime>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<TargetName>lib$(MSBuildProjectName)</TargetName>
<MainLibraryFileName>$(TargetName).so</MainLibraryFileName>
<ExpectedExitCode>42</ExpectedExitCode>
<UseNativeAOTRuntime>true</UseNativeAOTRuntime>
<PublishAOT>true</PublishAOT>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\..\..\tasks\AndroidAppBuilder\Templates\monodroid-nativeaot.cs" />
<DirectPInvoke Include="System.Security.Cryptography.Native.Android" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
public class Program
{
public static int Main()
{
string message = "Hello, Android!";
Console.WriteLine(message); // logcat
// Test the linux-bionic cryptography library
Console.WriteLine(System.Security.Cryptography.SHA256.HashData(new byte[] {0x1, 0x2, 0x3}));
return 42;
}
}